1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2019, assimp team
6
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the
12 following conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40 ----------------------------------------------------------------------
41 */
42
43 /** @file IFCUtil.cpp
44 * @brief Implementation of conversion routines for some common Ifc helper entities.
45 */
46
47 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
48
49 #include "Importer/IFC/IFCUtil.h"
50 #include "Common/PolyTools.h"
51 #include "PostProcessing/ProcessHelper.h"
52 #include <assimp/Defines.h>
53
54 namespace Assimp {
55 namespace IFC {
56
57 // ------------------------------------------------------------------------------------------------
Transform(const IfcMatrix4 & mat)58 void TempOpening::Transform(const IfcMatrix4& mat) {
59 if(profileMesh) {
60 profileMesh->Transform(mat);
61 }
62 if(profileMesh2D) {
63 profileMesh2D->Transform(mat);
64 }
65 extrusionDir *= IfcMatrix3(mat);
66 }
67
68 // ------------------------------------------------------------------------------------------------
ToMesh()69 aiMesh* TempMesh::ToMesh()
70 {
71 ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0)));
72
73 if (mVerts.empty()) {
74 return NULL;
75 }
76
77 std::unique_ptr<aiMesh> mesh(new aiMesh());
78
79 // copy vertices
80 mesh->mNumVertices = static_cast<unsigned int>(mVerts.size());
81 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
82 std::copy(mVerts.begin(),mVerts.end(),mesh->mVertices);
83
84 // and build up faces
85 mesh->mNumFaces = static_cast<unsigned int>(mVertcnt.size());
86 mesh->mFaces = new aiFace[mesh->mNumFaces];
87
88 for(unsigned int i = 0,n=0, acc = 0; i < mesh->mNumFaces; ++n) {
89 aiFace& f = mesh->mFaces[i];
90 if (!mVertcnt[n]) {
91 --mesh->mNumFaces;
92 continue;
93 }
94
95 f.mNumIndices = mVertcnt[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 }
100
101 ++i;
102 }
103
104 return mesh.release();
105 }
106
107 // ------------------------------------------------------------------------------------------------
Clear()108 void TempMesh::Clear()
109 {
110 mVerts.clear();
111 mVertcnt.clear();
112 }
113
114 // ------------------------------------------------------------------------------------------------
Transform(const IfcMatrix4 & mat)115 void TempMesh::Transform(const IfcMatrix4& mat)
116 {
117 for(IfcVector3& v : mVerts) {
118 v *= mat;
119 }
120 }
121
122 // ------------------------------------------------------------------------------
Center() const123 IfcVector3 TempMesh::Center() const
124 {
125 return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(),mVerts.end(),IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
126 }
127
128 // ------------------------------------------------------------------------------------------------
Append(const TempMesh & other)129 void TempMesh::Append(const TempMesh& other)
130 {
131 mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end());
132 mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end());
133 }
134
135 // ------------------------------------------------------------------------------------------------
RemoveDegenerates()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.
141
142 std::vector<IfcVector3> normals;
143 ComputePolygonNormals(normals, false);
144
145 bool drop = false;
146 size_t inor = 0;
147
148 std::vector<IfcVector3>::iterator vit = mVerts.begin();
149 for (std::vector<unsigned int>::iterator it = mVertcnt.begin(); it != mVertcnt.end(); ++inor) {
150 const unsigned int pcount = *it;
151
152 if (normals[inor].SquareLength() < 1e-10f) {
153 it = mVertcnt.erase(it);
154 vit = mVerts.erase(vit, vit + pcount);
155
156 drop = true;
157 continue;
158 }
159
160 vit += pcount;
161 ++it;
162 }
163
164 if(drop) {
165 IFCImporter::LogDebug("removing degenerate faces");
166 }
167 }
168
169 // ------------------------------------------------------------------------------------------------
ComputePolygonNormal(const IfcVector3 * vtcs,size_t cnt,bool normalize)170 IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
171 {
172 std::vector<IfcFloat> temp((cnt+2)*3);
173 for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
174 {
175 const IfcVector3& v = vtcs[vofs];
176 temp[i++] = v.x;
177 temp[i++] = v.y;
178 temp[i++] = v.z;
179 }
180
181 IfcVector3 nor;
182 NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2]);
183 return normalize ? nor.Normalize() : nor;
184 }
185
186 // ------------------------------------------------------------------------------------------------
ComputePolygonNormals(std::vector<IfcVector3> & normals,bool normalize,size_t ofs) const187 void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
188 bool normalize,
189 size_t ofs) const
190 {
191 size_t max_vcount = 0;
192 std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit;
193 for(iit = begin; iit != end; ++iit) {
194 max_vcount = std::max(max_vcount,static_cast<size_t>(*iit));
195 }
196
197 std::vector<IfcFloat> temp((max_vcount+2)*4);
198 normals.reserve( normals.size() + mVertcnt.size()-ofs );
199
200 // `NewellNormal()` currently has a relatively strange interface and need to
201 // re-structure things a bit to meet them.
202 size_t vidx = std::accumulate(mVertcnt.begin(),begin,0);
203 for(iit = begin; iit != end; vidx += *iit++) {
204 if (!*iit) {
205 normals.push_back(IfcVector3());
206 continue;
207 }
208 for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
209 const IfcVector3& v = mVerts[vidx+vofs];
210 temp[cnt++] = v.x;
211 temp[cnt++] = v.y;
212 temp[cnt++] = v.z;
213 #ifdef ASSIMP_BUILD_DEBUG
214 temp[cnt] = std::numeric_limits<IfcFloat>::quiet_NaN();
215 #endif
216 ++cnt;
217 }
218
219 normals.push_back(IfcVector3());
220 NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
221 }
222
223 if(normalize) {
224 for(IfcVector3& n : normals) {
225 n.Normalize();
226 }
227 }
228 }
229
230 // ------------------------------------------------------------------------------------------------
231 // Compute the normal of the last polygon in the given mesh
ComputeLastPolygonNormal(bool normalize) const232 IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
233 {
234 return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
235 }
236
237 struct CompareVector
238 {
operator ()Assimp::IFC::CompareVector239 bool operator () (const IfcVector3& a, const IfcVector3& b) const
240 {
241 IfcVector3 d = a - b;
242 IfcFloat eps = 1e-6;
243 return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
244 }
245 };
246 struct FindVector
247 {
248 IfcVector3 v;
FindVectorAssimp::IFC::FindVector249 FindVector(const IfcVector3& p) : v(p) { }
operator ()Assimp::IFC::FindVector250 bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
251 };
252
253 // ------------------------------------------------------------------------------------------------
FixupFaceOrientation()254 void TempMesh::FixupFaceOrientation()
255 {
256 const IfcVector3 vavg = Center();
257
258 // create a list of start indices for all faces to allow random access to faces
259 std::vector<size_t> faceStartIndices(mVertcnt.size());
260 for( size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a )
261 faceStartIndices[a] = i;
262
263 // list all faces on a vertex
264 std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
265 for( size_t a = 0; a < mVertcnt.size(); ++a )
266 {
267 for( size_t b = 0; b < mVertcnt[a]; ++b )
268 facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
269 }
270 // determine neighbourhood for all polys
271 std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
272 std::vector<size_t> tempIntersect(10);
273 for( size_t a = 0; a < mVertcnt.size(); ++a )
274 {
275 for( size_t b = 0; b < mVertcnt[a]; ++b )
276 {
277 size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
278 const std::vector<size_t>& facesOnB = facesByVertex[mVerts[ib]];
279 const std::vector<size_t>& facesOnNB = facesByVertex[mVerts[nib]];
280 // there should be exactly one or two faces which appear in both lists. Our face and the other side
281 std::vector<size_t>::iterator sectstart = tempIntersect.begin();
282 std::vector<size_t>::iterator sectend = std::set_intersection(
283 facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart);
284
285 if( std::distance(sectstart, sectend) != 2 )
286 continue;
287 if( *sectstart == a )
288 ++sectstart;
289 neighbour[ib] = *sectstart;
290 }
291 }
292
293 // now we're getting started. We take the face which is the farthest away from the center. This face is most probably
294 // facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
295 // faces to have the same winding until all faces have been tested.
296 std::vector<bool> faceDone(mVertcnt.size(), false);
297 while( std::count(faceDone.begin(), faceDone.end(), false) != 0 )
298 {
299 // find the farthest of the remaining faces
300 size_t farthestIndex = SIZE_MAX;
301 IfcFloat farthestDistance = -1.0;
302 for( size_t a = 0; a < mVertcnt.size(); ++a )
303 {
304 if( faceDone[a] )
305 continue;
306 IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
307 mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]);
308 IfcFloat dst = (faceCenter - vavg).SquareLength();
309 if( dst > farthestDistance ) { farthestDistance = dst; farthestIndex = a; }
310 }
311
312 // calculate its normal and reverse the poly if its facing towards the mesh center
313 IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
314 IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
315 mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0))
316 / IfcFloat(mVertcnt[farthestIndex]);
317 // We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
318 // the file.
319 if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 )
320 {
321 size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
322 std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
323 std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
324 // because of the neighbour index belonging to the edge starting with the point at the same index, we need to
325 // cycle the neighbours through to match the edges again.
326 // Before: points A - B - C - D with edge neighbour p - q - r - s
327 // After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be
328 // r q p s
329 for( size_t a = 0; a < fvc - 1; ++a )
330 std::swap(neighbour[fsi + a], neighbour[fsi + a + 1]);
331 }
332 faceDone[farthestIndex] = true;
333 std::vector<size_t> todo;
334 todo.push_back(farthestIndex);
335
336 // go over its neighbour faces recursively and adapt their winding order to match the farthest face
337 while( !todo.empty() )
338 {
339 size_t tdf = todo.back();
340 size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
341 todo.pop_back();
342
343 // check its neighbours
344 for( size_t a = 0; a < vc; ++a )
345 {
346 // ignore neighbours if we already checked them
347 size_t nbi = neighbour[vsi + a];
348 if( nbi == SIZE_MAX || faceDone[nbi] )
349 continue;
350
351 const IfcVector3& vp = mVerts[vsi + a];
352 size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi];
353 std::vector<IfcVector3>::iterator it = std::find_if(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc, FindVector(vp));
354 ai_assert(it != mVerts.begin() + nbvsi + nbvc);
355 size_t nb_vidx = std::distance(mVerts.begin() + nbvsi, it);
356 // two faces winded in the same direction should have a crossed edge, where one face has p0->p1 and the other
357 // has p1'->p0'. If the next point on the neighbouring face is also the next on the current face, we need
358 // to reverse the neighbour
359 nb_vidx = (nb_vidx + 1) % nbvc;
360 size_t oursideidx = (a + 1) % vc;
361 if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) )
362 {
363 std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
364 std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
365 for( size_t a = 0; a < nbvc - 1; ++a )
366 std::swap(neighbour[nbvsi + a], neighbour[nbvsi + a + 1]);
367 }
368
369 // either way we're done with the neighbour. Mark it as done and continue checking from there recursively
370 faceDone[nbi] = true;
371 todo.push_back(nbi);
372 }
373 }
374
375 // no more faces reachable from this part of the surface, start over with a disjunct part and its farthest face
376 }
377 }
378
379 // ------------------------------------------------------------------------------------------------
RemoveAdjacentDuplicates()380 void TempMesh::RemoveAdjacentDuplicates() {
381 bool drop = false;
382 std::vector<IfcVector3>::iterator base = mVerts.begin();
383 for(unsigned int& cnt : mVertcnt) {
384 if (cnt < 2){
385 base += cnt;
386 continue;
387 }
388
389 IfcVector3 vmin,vmax;
390 ArrayBounds(&*base, cnt ,vmin,vmax);
391
392
393 const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9);
394 //const IfcFloat dotepsilon = 1e-9;
395
396 //// look for vertices that lie directly on the line between their predecessor and their
397 //// successor and replace them with either of them.
398
399 //for(size_t i = 0; i < cnt; ++i) {
400 // IfcVector3& v1 = *(base+i), &v0 = *(base+(i?i-1:cnt-1)), &v2 = *(base+(i+1)%cnt);
401 // const IfcVector3& d0 = (v1-v0), &d1 = (v2-v1);
402 // const IfcFloat l0 = d0.SquareLength(), l1 = d1.SquareLength();
403 // if (!l0 || !l1) {
404 // continue;
405 // }
406
407 // const IfcFloat d = (d0/std::sqrt(l0))*(d1/std::sqrt(l1));
408
409 // if ( d >= 1.f-dotepsilon ) {
410 // v1 = v0;
411 // }
412 // else if ( d < -1.f+dotepsilon ) {
413 // v2 = v1;
414 // continue;
415 // }
416 //}
417
418 // drop any identical, adjacent vertices. this pass will collect the dropouts
419 // of the previous pass as a side-effect.
420 FuzzyVectorCompare fz(epsilon);
421 std::vector<IfcVector3>::iterator end = base+cnt, e = std::unique( base, end, fz );
422 if (e != end) {
423 cnt -= static_cast<unsigned int>(std::distance(e, end));
424 mVerts.erase(e,end);
425 drop = true;
426 }
427
428 // check front and back vertices for this polygon
429 if (cnt > 1 && fz(*base,*(base+cnt-1))) {
430 mVerts.erase(base+ --cnt);
431 drop = true;
432 }
433
434 // removing adjacent duplicates shouldn't erase everything :-)
435 ai_assert(cnt>0);
436 base += cnt;
437 }
438 if(drop) {
439 IFCImporter::LogDebug("removing duplicate vertices");
440 }
441 }
442
443 // ------------------------------------------------------------------------------------------------
Swap(TempMesh & other)444 void TempMesh::Swap(TempMesh& other)
445 {
446 mVertcnt.swap(other.mVertcnt);
447 mVerts.swap(other.mVerts);
448 }
449
450 // ------------------------------------------------------------------------------------------------
IsTrue(const::Assimp::STEP::EXPRESS::BOOLEAN & in)451 bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in)
452 {
453 return (std::string)in == "TRUE" || (std::string)in == "T";
454 }
455
456 // ------------------------------------------------------------------------------------------------
ConvertSIPrefix(const std::string & prefix)457 IfcFloat ConvertSIPrefix(const std::string& prefix)
458 {
459 if (prefix == "EXA") {
460 return 1e18f;
461 }
462 else if (prefix == "PETA") {
463 return 1e15f;
464 }
465 else if (prefix == "TERA") {
466 return 1e12f;
467 }
468 else if (prefix == "GIGA") {
469 return 1e9f;
470 }
471 else if (prefix == "MEGA") {
472 return 1e6f;
473 }
474 else if (prefix == "KILO") {
475 return 1e3f;
476 }
477 else if (prefix == "HECTO") {
478 return 1e2f;
479 }
480 else if (prefix == "DECA") {
481 return 1e-0f;
482 }
483 else if (prefix == "DECI") {
484 return 1e-1f;
485 }
486 else if (prefix == "CENTI") {
487 return 1e-2f;
488 }
489 else if (prefix == "MILLI") {
490 return 1e-3f;
491 }
492 else if (prefix == "MICRO") {
493 return 1e-6f;
494 }
495 else if (prefix == "NANO") {
496 return 1e-9f;
497 }
498 else if (prefix == "PICO") {
499 return 1e-12f;
500 }
501 else if (prefix == "FEMTO") {
502 return 1e-15f;
503 }
504 else if (prefix == "ATTO") {
505 return 1e-18f;
506 }
507 else {
508 IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
509 return 1;
510 }
511 }
512
513 // ------------------------------------------------------------------------------------------------
ConvertColor(aiColor4D & out,const Schema_2x3::IfcColourRgb & in)514 void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
515 {
516 out.r = static_cast<float>( in.Red );
517 out.g = static_cast<float>( in.Green );
518 out.b = static_cast<float>( in.Blue );
519 out.a = static_cast<float>( 1.f );
520 }
521
522 // ------------------------------------------------------------------------------------------------
ConvertColor(aiColor4D & out,const Schema_2x3::IfcColourOrFactor & in,ConversionData & conv,const aiColor4D * base)523 void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base)
524 {
525 if (const ::Assimp::STEP::EXPRESS::REAL* const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
526 out.r = out.g = out.b = static_cast<float>(*r);
527 if(base) {
528 out.r *= static_cast<float>( base->r );
529 out.g *= static_cast<float>( base->g );
530 out.b *= static_cast<float>( base->b );
531 out.a = static_cast<float>( base->a );
532 }
533 else out.a = 1.0;
534 }
535 else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
536 ConvertColor(out,*rgb);
537 }
538 else {
539 IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
540 }
541 }
542
543 // ------------------------------------------------------------------------------------------------
ConvertCartesianPoint(IfcVector3 & out,const Schema_2x3::IfcCartesianPoint & in)544 void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in)
545 {
546 out = IfcVector3();
547 for(size_t i = 0; i < in.Coordinates.size(); ++i) {
548 out[static_cast<unsigned int>(i)] = in.Coordinates[i];
549 }
550 }
551
552 // ------------------------------------------------------------------------------------------------
ConvertVector(IfcVector3 & out,const Schema_2x3::IfcVector & in)553 void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in)
554 {
555 ConvertDirection(out,in.Orientation);
556 out *= in.Magnitude;
557 }
558
559 // ------------------------------------------------------------------------------------------------
ConvertDirection(IfcVector3 & out,const Schema_2x3::IfcDirection & in)560 void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
561 {
562 out = IfcVector3();
563 for(size_t i = 0; i < in.DirectionRatios.size(); ++i) {
564 out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
565 }
566 const IfcFloat len = out.Length();
567 if (len<1e-6) {
568 IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
569 return;
570 }
571 out /= len;
572 }
573
574 // ------------------------------------------------------------------------------------------------
AssignMatrixAxes(IfcMatrix4 & out,const IfcVector3 & x,const IfcVector3 & y,const IfcVector3 & z)575 void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z)
576 {
577 out.a1 = x.x;
578 out.b1 = x.y;
579 out.c1 = x.z;
580
581 out.a2 = y.x;
582 out.b2 = y.y;
583 out.c2 = y.z;
584
585 out.a3 = z.x;
586 out.b3 = z.y;
587 out.c3 = z.z;
588 }
589
590 // ------------------------------------------------------------------------------------------------
ConvertAxisPlacement(IfcMatrix4 & out,const Schema_2x3::IfcAxis2Placement3D & in)591 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in)
592 {
593 IfcVector3 loc;
594 ConvertCartesianPoint(loc,in.Location);
595
596 IfcVector3 z(0.f,0.f,1.f),r(1.f,0.f,0.f),x;
597
598 if (in.Axis) {
599 ConvertDirection(z,*in.Axis.Get());
600 }
601 if (in.RefDirection) {
602 ConvertDirection(r,*in.RefDirection.Get());
603 }
604
605 IfcVector3 v = r.Normalize();
606 IfcVector3 tmpx = z * (v*z);
607
608 x = (v-tmpx).Normalize();
609 IfcVector3 y = (z^x);
610
611 IfcMatrix4::Translation(loc,out);
612 AssignMatrixAxes(out,x,y,z);
613 }
614
615 // ------------------------------------------------------------------------------------------------
ConvertAxisPlacement(IfcMatrix4 & out,const Schema_2x3::IfcAxis2Placement2D & in)616 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in)
617 {
618 IfcVector3 loc;
619 ConvertCartesianPoint(loc,in.Location);
620
621 IfcVector3 x(1.f,0.f,0.f);
622 if (in.RefDirection) {
623 ConvertDirection(x,*in.RefDirection.Get());
624 }
625
626 const IfcVector3 y = IfcVector3(x.y,-x.x,0.f);
627
628 IfcMatrix4::Translation(loc,out);
629 AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f));
630 }
631
632 // ------------------------------------------------------------------------------------------------
ConvertAxisPlacement(IfcVector3 & axis,IfcVector3 & pos,const Schema_2x3::IfcAxis1Placement & in)633 void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in)
634 {
635 ConvertCartesianPoint(pos,in.Location);
636 if (in.Axis) {
637 ConvertDirection(axis,in.Axis.Get());
638 }
639 else {
640 axis = IfcVector3(0.f,0.f,1.f);
641 }
642 }
643
644 // ------------------------------------------------------------------------------------------------
ConvertAxisPlacement(IfcMatrix4 & out,const Schema_2x3::IfcAxis2Placement & in,ConversionData & conv)645 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv)
646 {
647 if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
648 ConvertAxisPlacement(out,*pl3);
649 }
650 else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
651 ConvertAxisPlacement(out,*pl2);
652 }
653 else {
654 IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
655 }
656 }
657
658 // ------------------------------------------------------------------------------------------------
ConvertTransformOperator(IfcMatrix4 & out,const Schema_2x3::IfcCartesianTransformationOperator & op)659 void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op)
660 {
661 IfcVector3 loc;
662 ConvertCartesianPoint(loc,op.LocalOrigin);
663
664 IfcVector3 x(1.f,0.f,0.f),y(0.f,1.f,0.f),z(0.f,0.f,1.f);
665 if (op.Axis1) {
666 ConvertDirection(x,*op.Axis1.Get());
667 }
668 if (op.Axis2) {
669 ConvertDirection(y,*op.Axis2.Get());
670 }
671 if (const Schema_2x3::IfcCartesianTransformationOperator3D* op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) {
672 if(op2->Axis3) {
673 ConvertDirection(z,*op2->Axis3.Get());
674 }
675 }
676
677 IfcMatrix4 locm;
678 IfcMatrix4::Translation(loc,locm);
679 AssignMatrixAxes(out,x,y,z);
680
681
682 IfcVector3 vscale;
683 if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
684 vscale.x = nuni->Scale?op.Scale.Get():1.f;
685 vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f;
686 vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f;
687 }
688 else {
689 const IfcFloat sc = op.Scale?op.Scale.Get():1.f;
690 vscale = IfcVector3(sc,sc,sc);
691 }
692
693 IfcMatrix4 s;
694 IfcMatrix4::Scaling(vscale,s);
695
696 out = locm * out * s;
697 }
698
699
700 } // ! IFC
701 } // ! Assimp
702
703 #endif
704