/******************************************************************************** * * * This file is part of IfcOpenShell. * * * * IfcOpenShell is free software: you can redistribute it and/or modify * * it under the terms of the Lesser GNU General Public License as published by * * the Free Software Foundation, either version 3.0 of the License, or * * (at your option) any later version. * * * * IfcOpenShell is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * Lesser GNU General Public License for more details. * * * * You should have received a copy of the Lesser GNU General Public License * * along with this program. If not, see . * * * ********************************************************************************/ /******************************************************************************** * * * Implementations of the various conversion functions defined in IfcRegister.h * * * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../ifcgeom/IfcGeom.h" namespace IfcGeom { namespace Cache { #include "IfcRegisterCreateCache.h" } } #define IN_CACHE(T,E,t,e) std::map::const_iterator it = Cache::T.find(E->entity->id());\ if ( it != Cache::T.end() ) { e = it->second; return true; } #define CACHE(T,E,e) Cache::T[E->entity->id()] = e; bool IfcGeom::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) { IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point) std::vector xyz = l->Coordinates(); point = gp_Pnt( xyz.size() ? (xyz[0]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 1 ? (xyz[1]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 2 ? (xyz[2]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f ); CACHE(IfcCartesianPoint,l,point) return true; } bool IfcGeom::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) { IN_CACHE(IfcDirection,l,gp_Dir,dir) std::vector xyz = l->DirectionRatios(); dir = gp_Dir( xyz.size() ? xyz[0] : 0.0f, xyz.size() > 1 ? xyz[1] : 0.0f, xyz.size() > 2 ? xyz[2] : 0.0f ); CACHE(IfcDirection,l,dir) return true; } bool IfcGeom::convert(const IfcSchema::IfcVector* l, gp_Vec& v) { IN_CACHE(IfcVector,l,gp_Vec,v) gp_Dir d; IfcGeom::convert(l->Orientation(),d); v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d; CACHE(IfcVector,l,v) return true; } bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) { IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; IfcGeom::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis); if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection); gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0))); CACHE(IfcAxis2Placement3D,l,trsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) { IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax) gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1); IfcGeom::convert(l->Location(),o); if ( l->hasAxis() ) IfcGeom::convert(l->Axis(), axis); ax = gp_Ax1(o, axis); CACHE(IfcAxis1Placement,l,ax) return true; } bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) { IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf) gp_Pnt origin; IfcGeom::convert(l->LocalOrigin(),origin); gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); gp_Dir axis3 (0.,0.,1.); if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1); if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2); if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3); gp_Ax3 ax3 (origin,axis3,axis1); if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse(); trsf.SetTransformation(ax3); trsf.Invert(); if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale()); CACHE(IfcCartesianTransformationOperator3D,l,trsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) { IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf) gp_Pnt origin; gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); IfcGeom::convert(l->LocalOrigin(),origin); if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1); if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2); const gp_Pnt2d origin2d(origin.X(), origin.Y()); const gp_Dir2d axis12d(axis1.X(), axis1.Y()); const gp_Dir2d axis22d(axis2.X(), axis2.Y()); // A better match to represent the IfcCartesianTransformationOperator2D would // be the gp_Ax22d, but to my knowledge no easy way exists to convert it into // a gp_Trsf2d. Easiest would probably be to simply update the underlying // gp_Mat2d directly. const gp_Ax2d ax2d (origin2d, axis12d); trsf.SetTransformation(ax2d); if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) { gp_Trsf2d mirror; mirror.SetMirror(ax2d); trsf.Multiply(mirror); } trsf.Invert(); if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale()); CACHE(IfcCartesianTransformationOperator2D,l,trsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) { IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf) gp_Trsf trsf; gp_Pnt origin; IfcGeom::convert(l->LocalOrigin(),origin); gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); gp_Dir axis3 (0.,0.,1.); if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1); if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2); if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3); gp_Ax3 ax3 (origin,axis3,axis1); if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse(); trsf.SetTransformation(ax3); trsf.Invert(); const double scale1 = l->hasScale() ? l->Scale() : 1.0f; const double scale2 = l->hasScale2() ? l->Scale2() : scale1; const double scale3 = l->hasScale3() ? l->Scale3() : scale1; gtrsf = gp_GTrsf(); gtrsf.SetValue(1,1,scale1); gtrsf.SetValue(2,2,scale2); gtrsf.SetValue(3,3,scale3); gtrsf.PreMultiply(trsf); CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) { IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf) gp_Trsf2d trsf; gp_Pnt origin; gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); IfcGeom::convert(l->LocalOrigin(),origin); if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1); if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2); const gp_Pnt2d origin2d(origin.X(), origin.Y()); const gp_Dir2d axis12d(axis1.X(), axis1.Y()); const gp_Dir2d axis22d(axis2.X(), axis2.Y()); const gp_Ax2d ax2d (origin2d, axis12d); trsf.SetTransformation(ax2d); if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) { gp_Trsf2d mirror; mirror.SetMirror(ax2d); trsf.Multiply(mirror); } trsf.Invert(); const double scale1 = l->hasScale() ? l->Scale() : 1.0f; const double scale2 = l->hasScale2() ? l->Scale2() : scale1; gtrsf = gp_GTrsf2d(); gtrsf.SetValue(1,1,scale1); gtrsf.SetValue(2,2,scale2); gtrsf.Multiply(trsf); CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) { IN_CACHE(IfcPlane,pln,gp_Pln,plane) IfcSchema::IfcAxis2Placement3D* l = pln->Position(); gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; IfcGeom::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis); if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection); gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); plane = gp_Pln(ax3); CACHE(IfcPlane,pln,plane) return true; } bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) { IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf) gp_Pnt P; gp_Dir V (1,0,0); IfcGeom::convert(l->Location(),P); if ( l->hasRefDirection() ) IfcGeom::convert(l->RefDirection(),V); gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y())); trsf.SetTransformation(axis,gp_Ax2d()); CACHE(IfcAxis2Placement2D,l,trsf) return true; } bool IfcGeom::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) { IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf) if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); return false; } IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; while (1) { gp_Trsf trsf2; IfcSchema::IfcAxis2Placement relplacement = current->RelativePlacement(); if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); trsf.PreMultiply(trsf2); } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); else break; } else break; } CACHE(IfcObjectPlacement,l,trsf) return true; } void IfcGeom::Cache::Purge() { #include "IfcRegisterPurgeCache.h" IfcGeom::Cache::PurgeShapeCache(); }