@@ -690,10 +690,11 @@ bool IfcGeom::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) {
690690 return true ;
691691}
692692
693- std::string IfcGeom::create_brep_data (Ifc2x3 ::IfcProduct* ifc_product, unsigned int settings) {
693+ std::string IfcGeom::create_brep_data (IfcSchema ::IfcProduct* ifc_product, unsigned int settings) {
694694 const bool no_openings = !!(settings & DISABLE_OPENING_SUBTRACTIONS);
695695 const bool no_placement = !!(settings & DISABLE_OBJECT_PLACEMENT);
696696 const bool sew_shells = !!(settings & SEW_SHELLS);
697+ const bool convert_to_meters = !!(settings & CONVERT_TO_METERS);
697698
698699 const double old_max_faces_to_sew = GetValue (GV_MAX_FACES_TO_SEW);
699700 const double inf = std::numeric_limits<double >::infinity ();
@@ -703,13 +704,13 @@ std::string IfcGeom::create_brep_data(Ifc2x3::IfcProduct* ifc_product, unsigned
703704
704705 if (ifc_product->hasRepresentation ()) {
705706
706- Ifc2x3 ::IfcProductRepresentation* prod_rep = ifc_product->Representation ();
707- Ifc2x3 ::IfcRepresentation::list li = prod_rep->Representations ();
708- Ifc2x3 ::IfcShapeRepresentation* shape_rep = 0 ;
709- for (Ifc2x3 ::IfcRepresentation::it i = li->begin (); i != li->end (); ++i) {
707+ IfcSchema ::IfcProductRepresentation* prod_rep = ifc_product->Representation ();
708+ IfcSchema ::IfcRepresentation::list li = prod_rep->Representations ();
709+ IfcSchema ::IfcShapeRepresentation* shape_rep = 0 ;
710+ for (IfcSchema ::IfcRepresentation::it i = li->begin (); i != li->end (); ++i) {
710711 const std::string representation_identifier = (*i)->RepresentationIdentifier ();
711- if ((*i)->is (Ifc2x3 ::Type::IfcShapeRepresentation) && (representation_identifier == " Body" || representation_identifier == " Facetation" )) {
712- shape_rep = (Ifc2x3 ::IfcShapeRepresentation*) *i;
712+ if ((*i)->is (IfcSchema ::Type::IfcShapeRepresentation) && (representation_identifier == " Body" || representation_identifier == " Facetation" )) {
713+ shape_rep = (IfcSchema ::IfcShapeRepresentation*) *i;
713714 break ;
714715 }
715716 }
@@ -781,6 +782,11 @@ std::string IfcGeom::create_brep_data(Ifc2x3::IfcProduct* ifc_product, unsigned
781782 BRepBuilderAPI_GTransform (s,trsf,true ).Shape ();
782783 builder.Add (compound,moved_shape);
783784 }
785+ if (GetValue (GV_LENGTH_UNIT) != 1 . && !convert_to_meters) {
786+ gp_Trsf length_unit_scale;
787+ length_unit_scale.SetScaleFactor (1 . / GetValue (GV_LENGTH_UNIT));
788+ compound.Move (length_unit_scale);
789+ }
784790 std::stringstream sstream;
785791 BRepTools::Write (compound,sstream);
786792 brep_data = sstream.str ();
@@ -791,4 +797,124 @@ std::string IfcGeom::create_brep_data(Ifc2x3::IfcProduct* ifc_product, unsigned
791797 SetValue (GV_MAX_FACES_TO_SEW, old_max_faces_to_sew);
792798
793799 return brep_data;
800+ }
801+
802+ double UnitPrefixToValue ( IfcSchema::IfcSIPrefix::IfcSIPrefix v ) {
803+ if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_EXA ) return (double ) 1e18 ;
804+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_PETA ) return (double ) 1e15 ;
805+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_TERA ) return (double ) 1e12 ;
806+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_GIGA ) return (double ) 1e9 ;
807+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_MEGA ) return (double ) 1e6 ;
808+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_KILO ) return (double ) 1e3 ;
809+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_HECTO ) return (double ) 1e2 ;
810+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_DECA ) return (double ) 1 ;
811+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_DECI ) return (double ) 1e-1 ;
812+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_CENTI ) return (double ) 1e-2 ;
813+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_MILLI ) return (double ) 1e-3 ;
814+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_MICRO ) return (double ) 1e-6 ;
815+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_NANO ) return (double ) 1e-9 ;
816+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_PICO ) return (double ) 1e-12 ;
817+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_FEMTO ) return (double ) 1e-15 ;
818+ else if ( v == IfcSchema::IfcSIPrefix::IfcSIPrefix_ATTO ) return (double ) 1e-18 ;
819+ else return 1 .0f ;
820+ }
821+
822+ void IfcGeom::initialize_units_and_precision (IfcSchema::IfcProject* proj, double & unit_magnitude, std::string& unit_name) {
823+
824+ // IfcOpenShell measures internally in meters, therefore a conversion factor
825+ // is obtained based on the length unit in the file.
826+
827+ // Set default units, set length to meters, angles to undefined
828+ IfcGeom::SetValue (IfcGeom::GV_LENGTH_UNIT,1.0 );
829+ IfcGeom::SetValue (IfcGeom::GV_PLANEANGLE_UNIT,-1.0 );
830+
831+ IfcUtil::IfcAbstractSelect::list units = IfcUtil::IfcAbstractSelect::list ();
832+ try {
833+ IfcSchema::IfcUnitAssignment* unit_assignment = proj->UnitsInContext ();
834+ units = unit_assignment->Units ();
835+ } catch (const IfcParse::IfcException&) {}
836+
837+ try {
838+ for ( IfcUtil::IfcAbstractSelect::it it = units->begin (); it != units->end (); ++ it ) {
839+ std::string current_unit_name = " " ;
840+ const IfcUtil::IfcAbstractSelect::ptr base = *it;
841+ IfcSchema::IfcSIUnit::ptr unit = IfcSchema::IfcSIUnit::ptr ();
842+ double value = 1 .0f ;
843+ if ( base->is (IfcSchema::Type::IfcConversionBasedUnit) ) {
844+ const IfcSchema::IfcConversionBasedUnit::ptr u = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcConversionBasedUnit>(base);
845+ current_unit_name = u->Name ();
846+ const IfcSchema::IfcMeasureWithUnit::ptr u2 = u->ConversionFactor ();
847+ IfcSchema::IfcUnit u3 = u2->UnitComponent ();
848+ if ( u3->is (IfcSchema::Type::IfcSIUnit) ) {
849+ unit = (IfcSchema::IfcSIUnit*) u3;
850+ }
851+ IfcSchema::IfcValue v = u2->ValueComponent ();
852+ const double f = *((IfcUtil::IfcBaseEntity*)v)->entity ->getArgument (0 );
853+ value *= f;
854+ } else if ( base->is (IfcSchema::Type::IfcSIUnit) ) {
855+ unit = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcSIUnit>(base);
856+ }
857+ if ( unit ) {
858+ if ( unit->hasPrefix () ) {
859+ value *= UnitPrefixToValue (unit->Prefix ());
860+ }
861+ IfcSchema::IfcUnitEnum::IfcUnitEnum type = unit->UnitType ();
862+ if ( type == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT ) {
863+ IfcGeom::SetValue (IfcGeom::GV_LENGTH_UNIT,value);
864+ if (current_unit_name.empty ()) {
865+ if (unit->hasPrefix ()) {
866+ current_unit_name = IfcSchema::IfcSIPrefix::ToString (unit->Prefix ());
867+ }
868+ current_unit_name += IfcSchema::IfcSIUnitName::ToString (unit->Name ());
869+ }
870+ unit_magnitude = value;
871+ unit_name = current_unit_name;
872+ } else if ( type == IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) {
873+ IfcGeom::SetValue (IfcGeom::GV_PLANEANGLE_UNIT,value);
874+ }
875+ }
876+ }
877+ } catch (const IfcParse::IfcException& ex) {
878+ std::stringstream ss;
879+ ss << " Failed to determine unit information '" << ex.what () << " '" ;
880+ Logger::Message (Logger::LOG_ERROR, ss.str ());
881+ }
882+
883+ // Boolean operations rely on a precision value for vertex and face coincedence. This
884+ // value is obtained from the IfcGeometricRepresentationContexts in the file.
885+
886+ // Set an initial guess in case reading from file fails.
887+ IfcGeom::SetValue (IfcGeom::GV_PRECISION, 0.00001 );
888+
889+ try {
890+ IfcSchema::IfcRepresentationContext::list rep_contexts = proj->RepresentationContexts ();
891+ // Currently, IfcGeometricRepresentationContext aren't used as much as they should be
892+ // in the evaluation of shape representations, hence, we try to find the one with the
893+ // lowest precision. Typically, a value of 1e-5 is encountered. This value is applied
894+ // to all TopoDS_Shapes generated by one of the IfcGeom::convert() functions.
895+ // TODO: Many of the empirically found tolerances should probably be substituted by
896+ // one that is defined in the model file.
897+ double lowest_precision_encountered = std::numeric_limits<double >::infinity ();
898+ bool any_precision_encountered = false ;
899+ for (IfcSchema::IfcRepresentationContext::it it = rep_contexts->begin (); it != rep_contexts->end (); ++it) {
900+ if ((*it)->is (IfcSchema::Type::IfcGeometricRepresentationContext)) {
901+ IfcSchema::IfcGeometricRepresentationContext* rep_context = (IfcSchema::IfcGeometricRepresentationContext*)*it;
902+ if (rep_context->is (IfcSchema::Type::IfcGeometricRepresentationSubContext)) continue ;
903+ if (rep_context->hasPrecision ()) {
904+ const double precision = rep_context->Precision ();
905+ if (precision < lowest_precision_encountered) {
906+ any_precision_encountered = true ;
907+ lowest_precision_encountered = precision;
908+ }
909+ }
910+ }
911+ }
912+ if (any_precision_encountered) {
913+ IfcGeom::SetValue (IfcGeom::GV_PRECISION, lowest_precision_encountered);
914+ }
915+ } catch (const IfcParse::IfcException& ex) {
916+ std::stringstream ss;
917+ ss << " Failed to determine precision value '" << ex.what () << " '" ;
918+ Logger::Message (Logger::LOG_ERROR, ss.str ());
919+ }
794920}
0 commit comments