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