diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index 43fa842c96..3b9c573fab 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -208,13 +208,12 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { closeLibrary(); } -void ColladaSerializer::ColladaExporter::startDocument() { +void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) { stream.startDocument(); COLLADASW::Asset asset(&stream); asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION; - // TODO: Get the appropriate unit from the IFC file. - asset.setUnit("meter", 1.0); + asset.setUnit(unit_name, unit_magnitude); asset.setUpAxisType(COLLADASW::Asset::Z_UP); asset.add(); } @@ -271,7 +270,7 @@ bool ColladaSerializer::ready() { } void ColladaSerializer::writeHeader() { - exporter.startDocument(); + exporter.startDocument(unit_name, unit_magnitude); } void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) { diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index 60646202d5..7bb7f80e6d 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -135,11 +135,13 @@ private: {} std::vector deferreds; virtual ~ColladaExporter() {} - void startDocument(); + void startDocument(const std::string& unit_name, float unit_magnitude); void writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices, const std::vector& material_ids, const std::vector& materials); void endDocument(); }; ColladaExporter exporter; + std::string unit_name; + float unit_magnitude; public: ColladaSerializer(const std::string& dae_filename) : GeometrySerializer() @@ -151,6 +153,10 @@ public: void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {} void finalize(); bool isTesselated() const { return true; } + void setUnitNameAndMagnitude(const std::string& name, float magnitude) { + unit_name = name; + unit_magnitude = magnitude; + } }; #endif diff --git a/src/ifcconvert/GeometrySerializer.h b/src/ifcconvert/GeometrySerializer.h index 4524f8b681..c4895069a0 100644 --- a/src/ifcconvert/GeometrySerializer.h +++ b/src/ifcconvert/GeometrySerializer.h @@ -31,6 +31,7 @@ public: virtual ~GeometrySerializer() {} virtual void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) = 0; virtual void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) = 0; + virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; }; #endif \ No newline at end of file diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 3917af1b7e..5ee64d0a07 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -69,6 +69,9 @@ std::string change_extension(const std::string& fn, const std::string& ext) { } } +static std::stringstream log_stream; +void write_log(); + int main(int argc, char** argv) { boost::program_options::options_description generic_options; generic_options.add_options() @@ -180,11 +183,13 @@ int main(int argc, char** argv) { *c = tolower(*c); } + Logger::SetOutput(&std::cout, &log_stream); + GeometrySerializer* serializer; if (output_extension == ".obj") { const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl"; if (!use_world_coords) { - Logger::Message(Logger::LOG_WARNING, "Use world coords settings ignored for WaveFront OBJ files"); + Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files"); IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true); } serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename); @@ -201,6 +206,7 @@ int main(int argc, char** argv) { serializer = new IgesSerializer(output_filename); } else { Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension"); + write_log(); printUsage(generic_options, geom_options); return 1; } @@ -209,24 +215,32 @@ int main(int argc, char** argv) { if (!serializer->ready()) { Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing"); + write_log(); return 1; } - serializer->writeHeader(); - if (!serializer->isTesselated()) { IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_TRIANGULATION, true); + if (weld_vertices) { + Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files"); + } } - // Stream for log messages, we don't want to interupt our new progress bar... - std::stringstream ss; - // Parse the file supplied in argv[1]. Returns true on succes. - if ( ! IfcGeomObjects::Init(input_filename,&std::cout,&ss) ) { + if ( ! IfcGeomObjects::Init(input_filename, &std::cout, &log_stream) ) { Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found"); + write_log(); return 1; } + if (convert_back_units) { + serializer->setUnitNameAndMagnitude(IfcGeomObjects::GetUnitName(), IfcGeomObjects::GetUnitMagnitude()); + } else { + serializer->setUnitNameAndMagnitude("METER", 1.0f); + } + + serializer->writeHeader(); + std::set materials; time_t start,end; @@ -269,14 +283,17 @@ int main(int argc, char** argv) { Logger::Status("\rDone creating geometry "); - // Writes the material settings, defined in Materials.h - std::string log = ss.str(); - if (!log.empty()) { - std::cerr << std::endl << "Log:" << std::endl; - std::cerr << ss.str(); - } + write_log(); time(&end); int dif = (int) difftime (end,start); printf ("\nConversion took %d seconds\n", dif ); +} + +void write_log() { + std::string log = log_stream.str(); + if (!log.empty()) { + std::cerr << std::endl << "Log:" << std::endl; + std::cerr << log << std::endl; + } } \ No newline at end of file diff --git a/src/ifcconvert/IgesSerializer.h b/src/ifcconvert/IgesSerializer.h index 157fc67759..d18082c642 100644 --- a/src/ifcconvert/IgesSerializer.h +++ b/src/ifcconvert/IgesSerializer.h @@ -22,6 +22,7 @@ #include #include +#include #include "../ifcgeom/IfcGeomObjects.h" @@ -42,6 +43,12 @@ public: void finalize() { writer.Write(out_filename.c_str()); } + void setUnitNameAndMagnitude(const std::string& name, float magnitude) { + const char* symbol = getSymbolForUnitMagnitude(magnitude); + if (symbol) { + Interface_Static::SetCVal("write.iges.unit", symbol); + } + } }; #endif \ No newline at end of file diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.cpp b/src/ifcconvert/OpenCascadeBasedSerializer.cpp index fe8ca86176..0bf3f0c24b 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.cpp +++ b/src/ifcconvert/OpenCascadeBasedSerializer.cpp @@ -62,3 +62,22 @@ void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomSh writeShape(moved_shape); } } + +#define RATHER_SMALL (1e-3) +#define ALMOST_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL) + +const char* OpenCascadeBasedSerializer::getSymbolForUnitMagnitude(float mag) { + if (ALMOST_THE_SAME(mag, 0.001f)) { + return "MM"; + } else if (ALMOST_THE_SAME(mag, 0.01f)) { + return "CM"; + } else if (ALMOST_THE_SAME(mag, 1.0f)) { + return "M"; + } else if (ALMOST_THE_SAME(mag, 0.3048f)) { + return "FT"; + } else if (ALMOST_THE_SAME(mag, 0.0254f)) { + return "INCH"; + } else { + return 0; + } +} diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.h b/src/ifcconvert/OpenCascadeBasedSerializer.h index 5087bc1023..15472363bd 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.h +++ b/src/ifcconvert/OpenCascadeBasedSerializer.h @@ -27,6 +27,7 @@ class OpenCascadeBasedSerializer : public GeometrySerializer { protected: const std::string& out_filename; + const char* getSymbolForUnitMagnitude(float mag); public: explicit OpenCascadeBasedSerializer(const std::string& out_filename) : GeometrySerializer() diff --git a/src/ifcconvert/StepSerializer.h b/src/ifcconvert/StepSerializer.h index db5267af49..d0db600704 100644 --- a/src/ifcconvert/StepSerializer.h +++ b/src/ifcconvert/StepSerializer.h @@ -22,6 +22,7 @@ #include #include +#include #include "../ifcgeom/IfcGeomObjects.h" @@ -37,10 +38,22 @@ public: {} virtual ~StepSerializer() {} void writeShape(const TopoDS_Shape& shape) { + std::stringstream ss; + std::streambuf *sb = std::cout.rdbuf(ss.rdbuf()); writer.Transfer(shape, STEPControl_AsIs); + std::cout.rdbuf(sb); } void finalize() { + std::stringstream ss; + std::streambuf *sb = std::cout.rdbuf(ss.rdbuf()); writer.Write(out_filename.c_str()); + std::cout.rdbuf(sb); + } + void setUnitNameAndMagnitude(const std::string& name, float magnitude) { + const char* symbol = getSymbolForUnitMagnitude(magnitude); + if (symbol) { + Interface_Static::SetCVal("write.step.unit", symbol); + } } }; diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h index 6124c8d5c3..b31dcc1c94 100644 --- a/src/ifcconvert/WavefrontObjSerializer.h +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -49,6 +49,7 @@ public: void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {} void finalize() {} bool isTesselated() const { return true; } + void setUnitNameAndMagnitude(const std::string& name, float magnitude) {} }; #endif \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index 232bd29f0c..1e92d17d02 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -605,6 +605,9 @@ void IfcGeomObjects::InitPrecision() { } } +static std::string unit_name = "METER"; +static float unit_magnitude = 1.0f; + void IfcGeomObjects::InitUnits() { // Set default units, set length to meters, angles to undefined IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,1.0); @@ -631,11 +634,13 @@ void IfcGeomObjects::InitUnits() { } try { for ( IfcUtil::IfcAbstractSelect::it it = units->begin(); it != units->end(); ++ it ) { + std::string current_unit_name = ""; const IfcUtil::IfcAbstractSelect::ptr base = *it; Ifc2x3::IfcSIUnit::ptr unit = Ifc2x3::IfcSIUnit::ptr(); double value = 1.0f; if ( base->is(Ifc2x3::Type::IfcConversionBasedUnit) ) { const Ifc2x3::IfcConversionBasedUnit::ptr u = reinterpret_pointer_cast(base); + current_unit_name = u->Name(); const Ifc2x3::IfcMeasureWithUnit::ptr u2 = u->ConversionFactor(); Ifc2x3::IfcUnit u3 = u2->UnitComponent(); if ( u3->is(Ifc2x3::Type::IfcSIUnit) ) { @@ -655,6 +660,14 @@ void IfcGeomObjects::InitUnits() { Ifc2x3::IfcUnitEnum::IfcUnitEnum type = unit->UnitType(); if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_LENGTHUNIT ) { IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,value); + if (current_unit_name.empty()) { + if (unit->hasPrefix()) { + current_unit_name = Ifc2x3::IfcSIPrefix::ToString(unit->Prefix()); + } + current_unit_name += Ifc2x3::IfcSIUnitName::ToString(unit->Name()); + } + unit_magnitude = value; + unit_name = current_unit_name; } else if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) { IfcGeom::SetValue(IfcGeom::GV_PLANEANGLE_UNIT,value); } @@ -740,6 +753,14 @@ int IfcGeomObjects::Progress() { return 100 * done / total; } +const std::string& IfcGeomObjects::GetUnitName() { + return unit_name; +} + +const float IfcGeomObjects::GetUnitMagnitude() { + return unit_magnitude; +} + const std::string IfcGeomObjects::GetLog() { return Logger::GetLog(); } diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index 050ae2993d..a402b5e770 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -274,6 +274,9 @@ namespace IfcGeomObjects { bool Next(); int Progress(); + + const std::string& GetUnitName(); + const float GetUnitMagnitude(); const std::string GetLog(); IfcParse::IfcFile* GetFile();