vrshoot
view libs/assimp/IFCUtil.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file IFCUtil.cpp
42 * @brief Implementation of conversion routines for some common Ifc helper entities.
43 */
45 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
49 #include "IFCUtil.h"
50 #include "PolyTools.h"
51 #include "ProcessHelper.h"
53 namespace Assimp {
54 namespace IFC {
56 // ------------------------------------------------------------------------------------------------
57 void TempOpening::Transform(const IfcMatrix4& mat)
58 {
59 if(profileMesh) {
60 profileMesh->Transform(mat);
61 }
62 if(profileMesh2D) {
63 profileMesh2D->Transform(mat);
64 }
65 extrusionDir *= IfcMatrix3(mat);
66 }
68 // ------------------------------------------------------------------------------------------------
69 aiMesh* TempMesh::ToMesh()
70 {
71 ai_assert(verts.size() == std::accumulate(vertcnt.begin(),vertcnt.end(),size_t(0)));
73 if (verts.empty()) {
74 return NULL;
75 }
77 std::auto_ptr<aiMesh> mesh(new aiMesh());
79 // copy vertices
80 mesh->mNumVertices = static_cast<unsigned int>(verts.size());
81 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
82 std::copy(verts.begin(),verts.end(),mesh->mVertices);
84 // and build up faces
85 mesh->mNumFaces = static_cast<unsigned int>(vertcnt.size());
86 mesh->mFaces = new aiFace[mesh->mNumFaces];
88 for(unsigned int i = 0,n=0, acc = 0; i < mesh->mNumFaces; ++n) {
89 aiFace& f = mesh->mFaces[i];
90 if (!vertcnt[n]) {
91 --mesh->mNumFaces;
92 continue;
93 }
95 f.mNumIndices = vertcnt[n];
96 f.mIndices = new unsigned int[f.mNumIndices];
97 for(unsigned int a = 0; a < f.mNumIndices; ++a) {
98 f.mIndices[a] = acc++;
99 }
101 ++i;
102 }
104 return mesh.release();
105 }
107 // ------------------------------------------------------------------------------------------------
108 void TempMesh::Clear()
109 {
110 verts.clear();
111 vertcnt.clear();
112 }
114 // ------------------------------------------------------------------------------------------------
115 void TempMesh::Transform(const IfcMatrix4& mat)
116 {
117 BOOST_FOREACH(IfcVector3& v, verts) {
118 v *= mat;
119 }
120 }
122 // ------------------------------------------------------------------------------
123 IfcVector3 TempMesh::Center() const
124 {
125 return std::accumulate(verts.begin(),verts.end(),IfcVector3()) / static_cast<IfcFloat>(verts.size());
126 }
128 // ------------------------------------------------------------------------------------------------
129 void TempMesh::Append(const TempMesh& other)
130 {
131 verts.insert(verts.end(),other.verts.begin(),other.verts.end());
132 vertcnt.insert(vertcnt.end(),other.vertcnt.begin(),other.vertcnt.end());
133 }
135 // ------------------------------------------------------------------------------------------------
136 void TempMesh::RemoveDegenerates()
137 {
138 // The strategy is simple: walk the mesh and compute normals using
139 // Newell's algorithm. The length of the normals gives the area
140 // of the polygons, which is close to zero for lines.
142 std::vector<IfcVector3> normals;
143 ComputePolygonNormals(normals, false);
145 bool drop = false;
146 size_t inor = 0;
148 std::vector<IfcVector3>::iterator vit = verts.begin();
149 for (std::vector<unsigned int>::iterator it = vertcnt.begin(); it != vertcnt.end(); ++inor) {
150 const unsigned int pcount = *it;
152 if (normals[inor].SquareLength() < 1e-5f) {
153 it = vertcnt.erase(it);
154 vit = verts.erase(vit, vit + pcount);
156 drop = true;
157 continue;
158 }
160 vit += pcount;
161 ++it;
162 }
164 if(drop) {
165 IFCImporter::LogDebug("removing degenerate faces");
166 }
167 }
169 // ------------------------------------------------------------------------------------------------
170 void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
171 bool normalize,
172 size_t ofs) const
173 {
174 size_t max_vcount = 0;
175 std::vector<unsigned int>::const_iterator begin = vertcnt.begin()+ofs, end = vertcnt.end(), iit;
176 for(iit = begin; iit != end; ++iit) {
177 max_vcount = std::max(max_vcount,static_cast<size_t>(*iit));
178 }
180 std::vector<IfcFloat> temp((max_vcount+2)*4);
181 normals.reserve( normals.size() + vertcnt.size()-ofs );
183 // `NewellNormal()` currently has a relatively strange interface and need to
184 // re-structure things a bit to meet them.
185 size_t vidx = std::accumulate(vertcnt.begin(),begin,0);
186 for(iit = begin; iit != end; vidx += *iit++) {
187 if (!*iit) {
188 normals.push_back(IfcVector3());
189 continue;
190 }
191 for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
192 const IfcVector3& v = verts[vidx+vofs];
193 temp[cnt++] = v.x;
194 temp[cnt++] = v.y;
195 temp[cnt++] = v.z;
196 #ifdef _DEBUG
197 temp[cnt] = std::numeric_limits<IfcFloat>::quiet_NaN();
198 #endif
199 ++cnt;
200 }
202 normals.push_back(IfcVector3());
203 NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
204 }
206 if(normalize) {
207 BOOST_FOREACH(IfcVector3& n, normals) {
208 n.Normalize();
209 }
210 }
211 }
213 // ------------------------------------------------------------------------------------------------
214 // Compute the normal of the last polygon in the given mesh
215 IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
216 {
217 size_t total = vertcnt.back(), vidx = verts.size() - total;
218 std::vector<IfcFloat> temp((total+2)*3);
219 for(size_t vofs = 0, cnt = 0; vofs < total; ++vofs) {
220 const IfcVector3& v = verts[vidx+vofs];
221 temp[cnt++] = v.x;
222 temp[cnt++] = v.y;
223 temp[cnt++] = v.z;
224 }
225 IfcVector3 nor;
226 NewellNormal<3,3,3>(nor,total,&temp[0],&temp[1],&temp[2]);
227 return normalize ? nor.Normalize() : nor;
228 }
230 // ------------------------------------------------------------------------------------------------
231 void TempMesh::FixupFaceOrientation()
232 {
233 const IfcVector3 vavg = Center();
235 std::vector<IfcVector3> normals;
236 ComputePolygonNormals(normals);
238 size_t c = 0, ofs = 0;
239 BOOST_FOREACH(unsigned int cnt, vertcnt) {
240 if (cnt>2){
241 const IfcVector3& thisvert = verts[c];
242 if (normals[ofs]*(thisvert-vavg) < 0) {
243 std::reverse(verts.begin()+c,verts.begin()+cnt+c);
244 }
245 }
246 c += cnt;
247 ++ofs;
248 }
249 }
251 // ------------------------------------------------------------------------------------------------
252 void TempMesh::RemoveAdjacentDuplicates()
253 {
255 bool drop = false;
256 std::vector<IfcVector3>::iterator base = verts.begin();
257 BOOST_FOREACH(unsigned int& cnt, vertcnt) {
258 if (cnt < 2){
259 base += cnt;
260 continue;
261 }
263 IfcVector3 vmin,vmax;
264 ArrayBounds(&*base, cnt ,vmin,vmax);
267 const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9);
268 //const IfcFloat dotepsilon = 1e-9;
270 //// look for vertices that lie directly on the line between their predecessor and their
271 //// successor and replace them with either of them.
273 //for(size_t i = 0; i < cnt; ++i) {
274 // IfcVector3& v1 = *(base+i), &v0 = *(base+(i?i-1:cnt-1)), &v2 = *(base+(i+1)%cnt);
275 // const IfcVector3& d0 = (v1-v0), &d1 = (v2-v1);
276 // const IfcFloat l0 = d0.SquareLength(), l1 = d1.SquareLength();
277 // if (!l0 || !l1) {
278 // continue;
279 // }
281 // const IfcFloat d = (d0/sqrt(l0))*(d1/sqrt(l1));
283 // if ( d >= 1.f-dotepsilon ) {
284 // v1 = v0;
285 // }
286 // else if ( d < -1.f+dotepsilon ) {
287 // v2 = v1;
288 // continue;
289 // }
290 //}
292 // drop any identical, adjacent vertices. this pass will collect the dropouts
293 // of the previous pass as a side-effect.
294 FuzzyVectorCompare fz(epsilon);
295 std::vector<IfcVector3>::iterator end = base+cnt, e = std::unique( base, end, fz );
296 if (e != end) {
297 cnt -= static_cast<unsigned int>(std::distance(e, end));
298 verts.erase(e,end);
299 drop = true;
300 }
302 // check front and back vertices for this polygon
303 if (cnt > 1 && fz(*base,*(base+cnt-1))) {
304 verts.erase(base+ --cnt);
305 drop = true;
306 }
308 // removing adjacent duplicates shouldn't erase everything :-)
309 ai_assert(cnt>0);
310 base += cnt;
311 }
312 if(drop) {
313 IFCImporter::LogDebug("removing duplicate vertices");
314 }
315 }
317 // ------------------------------------------------------------------------------------------------
318 void TempMesh::Swap(TempMesh& other)
319 {
320 vertcnt.swap(other.vertcnt);
321 verts.swap(other.verts);
322 }
324 // ------------------------------------------------------------------------------------------------
325 bool IsTrue(const EXPRESS::BOOLEAN& in)
326 {
327 return (std::string)in == "TRUE" || (std::string)in == "T";
328 }
330 // ------------------------------------------------------------------------------------------------
331 IfcFloat ConvertSIPrefix(const std::string& prefix)
332 {
333 if (prefix == "EXA") {
334 return 1e18f;
335 }
336 else if (prefix == "PETA") {
337 return 1e15f;
338 }
339 else if (prefix == "TERA") {
340 return 1e12f;
341 }
342 else if (prefix == "GIGA") {
343 return 1e9f;
344 }
345 else if (prefix == "MEGA") {
346 return 1e6f;
347 }
348 else if (prefix == "KILO") {
349 return 1e3f;
350 }
351 else if (prefix == "HECTO") {
352 return 1e2f;
353 }
354 else if (prefix == "DECA") {
355 return 1e-0f;
356 }
357 else if (prefix == "DECI") {
358 return 1e-1f;
359 }
360 else if (prefix == "CENTI") {
361 return 1e-2f;
362 }
363 else if (prefix == "MILLI") {
364 return 1e-3f;
365 }
366 else if (prefix == "MICRO") {
367 return 1e-6f;
368 }
369 else if (prefix == "NANO") {
370 return 1e-9f;
371 }
372 else if (prefix == "PICO") {
373 return 1e-12f;
374 }
375 else if (prefix == "FEMTO") {
376 return 1e-15f;
377 }
378 else if (prefix == "ATTO") {
379 return 1e-18f;
380 }
381 else {
382 IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
383 return 1;
384 }
385 }
387 // ------------------------------------------------------------------------------------------------
388 void ConvertColor(aiColor4D& out, const IfcColourRgb& in)
389 {
390 out.r = static_cast<float>( in.Red );
391 out.g = static_cast<float>( in.Green );
392 out.b = static_cast<float>( in.Blue );
393 out.a = static_cast<float>( 1.f );
394 }
396 // ------------------------------------------------------------------------------------------------
397 void ConvertColor(aiColor4D& out, const IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base)
398 {
399 if (const EXPRESS::REAL* const r = in.ToPtr<EXPRESS::REAL>()) {
400 out.r = out.g = out.b = static_cast<float>(*r);
401 if(base) {
402 out.r *= static_cast<float>( base->r );
403 out.g *= static_cast<float>( base->g );
404 out.b *= static_cast<float>( base->b );
405 out.a = static_cast<float>( base->a );
406 }
407 else out.a = 1.0;
408 }
409 else if (const IfcColourRgb* const rgb = in.ResolveSelectPtr<IfcColourRgb>(conv.db)) {
410 ConvertColor(out,*rgb);
411 }
412 else {
413 IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
414 }
415 }
417 // ------------------------------------------------------------------------------------------------
418 void ConvertCartesianPoint(IfcVector3& out, const IfcCartesianPoint& in)
419 {
420 out = IfcVector3();
421 for(size_t i = 0; i < in.Coordinates.size(); ++i) {
422 out[i] = in.Coordinates[i];
423 }
424 }
426 // ------------------------------------------------------------------------------------------------
427 void ConvertVector(IfcVector3& out, const IfcVector& in)
428 {
429 ConvertDirection(out,in.Orientation);
430 out *= in.Magnitude;
431 }
433 // ------------------------------------------------------------------------------------------------
434 void ConvertDirection(IfcVector3& out, const IfcDirection& in)
435 {
436 out = IfcVector3();
437 for(size_t i = 0; i < in.DirectionRatios.size(); ++i) {
438 out[i] = in.DirectionRatios[i];
439 }
440 const IfcFloat len = out.Length();
441 if (len<1e-6) {
442 IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
443 return;
444 }
445 out /= len;
446 }
448 // ------------------------------------------------------------------------------------------------
449 void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z)
450 {
451 out.a1 = x.x;
452 out.b1 = x.y;
453 out.c1 = x.z;
455 out.a2 = y.x;
456 out.b2 = y.y;
457 out.c2 = y.z;
459 out.a3 = z.x;
460 out.b3 = z.y;
461 out.c3 = z.z;
462 }
464 // ------------------------------------------------------------------------------------------------
465 void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement3D& in)
466 {
467 IfcVector3 loc;
468 ConvertCartesianPoint(loc,in.Location);
470 IfcVector3 z(0.f,0.f,1.f),r(1.f,0.f,0.f),x;
472 if (in.Axis) {
473 ConvertDirection(z,*in.Axis.Get());
474 }
475 if (in.RefDirection) {
476 ConvertDirection(r,*in.RefDirection.Get());
477 }
479 IfcVector3 v = r.Normalize();
480 IfcVector3 tmpx = z * (v*z);
482 x = (v-tmpx).Normalize();
483 IfcVector3 y = (z^x);
485 IfcMatrix4::Translation(loc,out);
486 AssignMatrixAxes(out,x,y,z);
487 }
489 // ------------------------------------------------------------------------------------------------
490 void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement2D& in)
491 {
492 IfcVector3 loc;
493 ConvertCartesianPoint(loc,in.Location);
495 IfcVector3 x(1.f,0.f,0.f);
496 if (in.RefDirection) {
497 ConvertDirection(x,*in.RefDirection.Get());
498 }
500 const IfcVector3 y = IfcVector3(x.y,-x.x,0.f);
502 IfcMatrix4::Translation(loc,out);
503 AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f));
504 }
506 // ------------------------------------------------------------------------------------------------
507 void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const IfcAxis1Placement& in)
508 {
509 ConvertCartesianPoint(pos,in.Location);
510 if (in.Axis) {
511 ConvertDirection(axis,in.Axis.Get());
512 }
513 else {
514 axis = IfcVector3(0.f,0.f,1.f);
515 }
516 }
518 // ------------------------------------------------------------------------------------------------
519 void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement& in, ConversionData& conv)
520 {
521 if(const IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<IfcAxis2Placement3D>(conv.db)) {
522 ConvertAxisPlacement(out,*pl3);
523 }
524 else if(const IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<IfcAxis2Placement2D>(conv.db)) {
525 ConvertAxisPlacement(out,*pl2);
526 }
527 else {
528 IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
529 }
530 }
532 // ------------------------------------------------------------------------------------------------
533 void ConvertTransformOperator(IfcMatrix4& out, const IfcCartesianTransformationOperator& op)
534 {
535 IfcVector3 loc;
536 ConvertCartesianPoint(loc,op.LocalOrigin);
538 IfcVector3 x(1.f,0.f,0.f),y(0.f,1.f,0.f),z(0.f,0.f,1.f);
539 if (op.Axis1) {
540 ConvertDirection(x,*op.Axis1.Get());
541 }
542 if (op.Axis2) {
543 ConvertDirection(y,*op.Axis2.Get());
544 }
545 if (const IfcCartesianTransformationOperator3D* op2 = op.ToPtr<IfcCartesianTransformationOperator3D>()) {
546 if(op2->Axis3) {
547 ConvertDirection(z,*op2->Axis3.Get());
548 }
549 }
551 IfcMatrix4 locm;
552 IfcMatrix4::Translation(loc,locm);
553 AssignMatrixAxes(out,x,y,z);
556 IfcVector3 vscale;
557 if (const IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<IfcCartesianTransformationOperator3DnonUniform>()) {
558 vscale.x = nuni->Scale?op.Scale.Get():1.f;
559 vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f;
560 vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f;
561 }
562 else {
563 const IfcFloat sc = op.Scale?op.Scale.Get():1.f;
564 vscale = IfcVector3(sc,sc,sc);
565 }
567 IfcMatrix4 s;
568 IfcMatrix4::Scaling(vscale,s);
570 out = locm * out * s;
571 }
574 } // ! IFC
575 } // ! Assimp
577 #endif