From c97cf661a23ef5905cc985dc9b2dfed873139a0e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 22 Apr 2015 09:15:48 +0000 Subject: [PATCH] 1. Also emit Plan and Axis shape representations and IfcTopologyRepresentations if requested. 2. Add serialization for curves. 3. In Python add option to specify representation for which to generate shape. --- cmake/CMakeLists.txt | 4 +- .../io_import_scene_ifc/__init__.py | 2 +- src/ifcconvert/ColladaSerializer.cpp | 57 ++++++++++++---- src/ifcconvert/ColladaSerializer.h | 17 +++-- src/ifcconvert/IfcConvert.cpp | 13 +++- src/ifcconvert/WavefrontObjSerializer.cpp | 39 ++++++++++- src/ifcgeom/IfcGeom.h | 7 +- src/ifcgeom/IfcGeomElement.h | 10 +-- src/ifcgeom/IfcGeomFaces.cpp | 7 +- src/ifcgeom/IfcGeomFunctions.cpp | 19 +++++- src/ifcgeom/IfcGeomIterator.h | 36 +++++----- src/ifcgeom/IfcGeomIteratorSettings.h | 18 ++++- src/ifcgeom/IfcGeomRepresentation.h | 54 ++++++++++++--- src/ifcgeom/IfcGeomShapeType.h | 38 +++++++++++ src/ifcgeom/IfcGeomShapes.cpp | 35 ++++++---- src/ifcgeom/IfcGeomWires.cpp | 63 ++++++++++++++++++ src/ifcgeom/IfcRegister.cpp | 48 ++++++++++++-- src/ifcgeom/IfcRegister.h | 5 +- src/ifcgeom/IfcRegisterIsShapeCollection.h | 6 -- src/ifcgeom/IfcRegisterShapeType.h | 14 ++++ src/ifcgeomserver/IfcGeomServer.cpp | 2 +- src/ifcmax/IfcMax.cpp | 37 +++++++++-- .../ifcopenshell/geom/__init__.py | 2 +- src/ifcwrap/IfcGeomWrapper.i | 66 +++++++++++++------ win/IfcGeom.vcproj | 8 ++- 25 files changed, 495 insertions(+), 112 deletions(-) create mode 100644 src/ifcgeom/IfcGeomShapeType.h delete mode 100644 src/ifcgeom/IfcRegisterIsShapeCollection.h create mode 100644 src/ifcgeom/IfcRegisterShapeType.h diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ceef6c5d13..a9cc5562cf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -193,6 +193,7 @@ SET(include_files_geom ../src/ifcgeom/IfcGeomMaterial.h ../src/ifcgeom/IfcGeomRenderStyles.h ../src/ifcgeom/IfcGeomRepresentation.h + ../src/ifcgeom/IfcGeomShapeType.h ../src/ifcgeom/IfcRegister.h ../src/ifcgeom/IfcRegisterConvertCurve.h ../src/ifcgeom/IfcRegisterConvertFace.h @@ -202,11 +203,12 @@ SET(include_files_geom ../src/ifcgeom/IfcRegisterCreateCache.h ../src/ifcgeom/IfcRegisterDef.h ../src/ifcgeom/IfcRegisterGeomHeader.h - ../src/ifcgeom/IfcRegisterIsShapeCollection.h ../src/ifcgeom/IfcRegisterPurgeCache.h + ../src/ifcgeom/IfcRegisterShapeType.h ../src/ifcgeom/IfcRegisterUndef.h ../src/ifcgeom/IfcRepresentationShapeItem.h ) + SET(include_files_parse ../src/ifcparse/Ifc2x3-latebound.h ../src/ifcparse/Ifc2x3.h diff --git a/src/ifcblender/io_import_scene_ifc/__init__.py b/src/ifcblender/io_import_scene_ifc/__init__.py index 43efe9f4e3..70868b4595 100644 --- a/src/ifcblender/io_import_scene_ifc/__init__.py +++ b/src/ifcblender/io_import_scene_ifc/__init__.py @@ -66,7 +66,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans): settings = ifcopenshell_geom.settings() settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans) iterator = ifcopenshell_geom.iterator(settings, filename) - valid_file = iterator.findContext() + valid_file = iterator.initialize() if not valid_file: return False print("Done reading file") diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index 7f69d2d7bf..98ca38b530 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -51,12 +51,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const source.finish(); } -void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& indices, const std::vector material_ids, const std::vector& materials) { - // The goal of the IfcGeom::Iterator is to filter out empty geometries, but - // since this function would crash trying to deference the material_ids in - // that case, a hard return statement is added just in case. - if (indices.empty()) return; - +void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector material_ids, const std::vector& materials) { openMesh(mesh_id); // The normals vector can be empty for example when the WELD_VERTICES setting is used. @@ -73,13 +68,13 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX)); vertices.add(); - std::vector::const_iterator index_range_start = indices.begin(); + std::vector::const_iterator index_range_start = faces.begin(); std::vector::const_iterator material_it = material_ids.begin(); int previous_material_id = -1; - for (std::vector::const_iterator it = indices.begin(); ; it += 3) { + for (std::vector::const_iterator it = faces.begin(); !faces.empty(); it += 3) { const int current_material_id = *(material_it++); const int num_triangles = std::distance(index_range_start, it) / 3; - if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) { + if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) { COLLADASW::Triangles triangles(mSW); triangles.setMaterial(materials[previous_material_id].name()); triangles.setCount(num_triangles); @@ -101,11 +96,44 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str index_range_start = it; } previous_material_id = current_material_id; - if (it == indices.end()) { + if (it == faces.end()) { break; } } + std::set faces_set (faces.begin(), faces.end()); + typedef std::vector< std::pair > > linelist_t; + linelist_t linelist; + + int num_lines = 0; + for ( std::vector::const_iterator it = edges.begin(); it != edges.end(); ++num_lines) { + const int i1 = *(it++); + const int i2 = *(it++); + + if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) { + continue; + } + + const int current_material_id = *(material_it++); + if ((previous_material_id != current_material_id) || (num_lines == 0)) { + linelist.resize(linelist.size() + 1); + } + + linelist.rbegin()->second.push_back(i1); + linelist.rbegin()->second.push_back(i2); + } + + for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) { + COLLADASW::Lines lines(mSW); + lines.setMaterial(materials[it->first].name()); + lines.setCount(it->second.size()); + int offset = 0; + lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, 0)); + lines.prepareToAppendValues(); + lines.appendValues(it->second); + lines.finish(); + } + closeMesh(); closeGeometry(); } @@ -219,7 +247,7 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n asset.add(); } -void ColladaSerializer::ColladaExporter::write(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 ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, const std::string& context, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& _materials) { std::vector material_references; for (std::vector::const_iterator it = _materials.begin(); it != _materials.end(); ++it) { const IfcGeom::Material& material = *it; @@ -228,7 +256,7 @@ void ColladaSerializer::ColladaExporter::write(const std::string& guid, const st } material_references.push_back(collada_id(material.name())); } - deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references)); + deferreds.push_back(DeferredObject(guid, name, type, context, obj_id, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references)); } const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const { @@ -238,6 +266,7 @@ const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() con } else { ss << this->guid; } + ss << "_" << this->context; return collada_id(ss.str()); } @@ -247,7 +276,7 @@ void ColladaSerializer::ColladaExporter::endDocument() { materials.write(); for (std::vector::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) { const std::string object_name = it->Name(); - geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials); + geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials); } geometries.close(); for (std::vector::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) { @@ -268,7 +297,7 @@ void ColladaSerializer::writeHeader() { void ColladaSerializer::write(const IfcGeom::TriangulationElement* o) { const IfcGeom::Representation::Triangulation& mesh = o->geometry(); - exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials()); + exporter.write(o->guid(), o->name(), o->type(), o->context(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials()); } void ColladaSerializer::finalize() { diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index 6c3618fce6..6ba9cc6dc7 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -52,7 +52,7 @@ private: : COLLADASW::LibraryGeometries(&stream) {} void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords = "XYZ"); - void write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& indices, const std::vector material_ids, const std::vector& materials); + void write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector material_ids, const std::vector& materials); void close(); }; class ColladaScene : public COLLADASW::LibraryVisualScenes @@ -94,26 +94,29 @@ private: }; class DeferredObject { public: - std::string guid, name, type; + std::string guid, name, type, context; int obj_id; std::vector matrix; std::vector vertices; std::vector normals; - std::vector indices; + std::vector faces; + std::vector edges; std::vector material_ids; std::vector materials; std::vector material_references; - DeferredObject(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, + DeferredObject(const std::string& guid, const std::string& name, const std::string& type, const std::string& context, int obj_id, const std::vector& matrix, const std::vector& vertices, + const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& materials, const std::vector& material_references) : guid(guid) , name(name) , type(type) + , context(context) , obj_id(obj_id) , matrix(matrix) , vertices(vertices) , normals(normals) - , indices(indices) + , faces(faces) + , edges(edges) , material_ids(material_ids) , materials(materials) , material_references(material_references) @@ -136,7 +139,7 @@ private: std::vector deferreds; virtual ~ColladaExporter() {} void startDocument(const std::string& unit_name, float unit_magnitude); - void write(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 write(const std::string& guid, const std::string& name, const std::string& type, const std::string& context, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& materials); void endDocument(); }; ColladaExporter exporter; diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 12dd6861e4..410345451a 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -89,6 +89,13 @@ int main(int argc, char** argv) { std::vector entity_vector; boost::program_options::options_description geom_options; geom_options.add_options() + ("plan", + "Specifies whether to include curves in the output result. Typically " + "these are representations of type Plan or Axis. Excluded by default.") + ("model", + "Specifies whether to include surfaces and solides in the output result. " + "Typically these are representations of type Body or Facetation. " + "Included by default.") ("weld-vertices", "Specifies whether vertices are welded, meaning that the coordinates " "vector will only contain unique xyz-triplets. This results in a " @@ -169,6 +176,8 @@ int main(int argc, char** argv) { const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0; const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0; const bool include_entities = vmap.count("include") != 0; + const bool include_plan = vmap.count("plan") != 0; + const bool include_model = vmap.count("model") != 0 || (!include_plan); // Gets the set ifc types to be ignored from the command line. std::set entities; @@ -233,6 +242,8 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands); settings.set(IfcGeom::IteratorSettings::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation); settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); + settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); + settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); GeometrySerializer* serializer; if (output_extension == ".obj") { @@ -289,7 +300,7 @@ int main(int argc, char** argv) { time_t start,end; time(&start); - if (!context_iterator.findContext()) { + if (!context_iterator.initialize()) { Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found"); write_log(); return 1; diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index a931a3028b..6d63d0d4cf 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -70,7 +70,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* std::string tmp = o->name().empty() ? o->guid() : o->name(); std::replace( tmp.begin(), tmp.end(), ' ', '_'); - const std::string name = tmp; + std::string name = tmp; + name += std::string("_") + o->context(); + obj_stream << "g " << name << "\n"; obj_stream << "s 1" << "\n"; @@ -83,6 +85,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* const double z = *(it++); obj_stream << "v " << x << " " << y << " " << z << "\n"; } + for ( std::vector::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) { const double x = *(it++); const double y = *(it++); @@ -111,6 +114,38 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* const int v2 = *(it++)+vcount_total; const int v3 = *(it++)+vcount_total; obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n"; + } - vcount_total += vcount; + + std::set faces_set (mesh.faces().begin(), mesh.faces().end()); + const std::vector& edges = mesh.edges(); + + for ( std::vector::const_iterator it = edges.begin(); it != edges.end(); ) { + const int i1 = *(it++); + const int i2 = *(it++); + + if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) { + continue; + } + + const int material_id = *(material_it++); + + if (material_id != previous_material_id) { + const IfcGeom::Material& material = mesh.materials()[material_id]; + const std::string material_name = material.name(); + obj_stream << "usemtl " << material_name << "\n"; + if (materials.find(material_name) == materials.end()) { + writeMaterial(material); + materials.insert(material_name); + } + previous_material_id = material_id; + } + + const int v1 = i1 + vcount_total; + const int v2 = i2 + vcount_total; + + obj_stream << "l " << v1 << " " << v2 << "\n"; + } + + vcount_total += vcount; } diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 3d4fcf769f..49a8bf8ef4 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -44,6 +44,7 @@ #include "../ifcgeom/IfcGeomElement.h" #include "../ifcgeom/IfcGeomRepresentation.h" #include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom/IfcGeomShapeType.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; } @@ -94,13 +95,15 @@ public: // The precision used in boolean operations, setting this value too low results // in artefacts and potentially modelling failures // Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available) - GV_PRECISION + GV_PRECISION, + // Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0) + GV_DIMENSIONALITY }; bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result); - bool is_shape_collection(const IfcUtil::IfcBaseClass* L); + IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L); bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse); bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result); diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index c44fd8d6e9..5a8a2415d6 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -72,6 +72,7 @@ namespace IfcGeom { std::string _name; std::string _type; std::string _guid; + std::string _context; Transformation

_transformation; public: int id() const { return _id; } @@ -79,9 +80,10 @@ namespace IfcGeom { const std::string& name() const { return _name; } const std::string& type() const { return _type; } const std::string& guid() const { return _guid; } + const std::string& context() const { return _context; } const Transformation

& transformation() const { return _transformation; } - Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf) - : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf) + Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf) + : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) {} virtual ~Element() {} }; @@ -92,8 +94,8 @@ namespace IfcGeom { Representation::BRep* _geometry; public: const Representation::BRep& geometry() const { return *_geometry; } - BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, Representation::BRep* geometry) - : Element

(geometry->settings(),id,parent_id,name,type,guid,trsf) + BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, Representation::BRep* geometry) + : Element

(geometry->settings(),id,parent_id,name,type,guid,context,trsf) , _geometry(geometry) {} virtual ~BRepElement() { diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/IfcGeomFaces.cpp index de87c68e47..1730e8ffd5 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/IfcGeomFaces.cpp @@ -101,6 +101,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); IfcSchema::IfcFaceBound::list::it it = bounds->begin(); IfcSchema::IfcLoop* loop = (*it)->Bound(); + // FIXME: The assumption that the first bound is + // the outer bound is not necessarily correct. TopoDS_Wire outer_wire; if ( ! convert_wire(loop,outer_wire) ) return false; BRepBuilderAPI_MakeFace mf (outer_wire); @@ -127,10 +129,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { sfs.Perform(); TopoDS_Shape sfs_shape = sfs.Shape(); bool is_face = sfs_shape.ShapeType() == TopAbs_FACE; + // This assertion is not strictly necessary. The schema + // does suggest there to be only one outer bound, but + // not all models comply with this. if ( is_face ) { face = TopoDS::Face(sfs_shape); } else { - return false; + face = sfs_shape; } } else { return false; diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 2909871134..317f2dd601 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -370,7 +370,9 @@ bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& } bool IfcGeom::Kernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) { - wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve)); + try { + wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve)); + } catch(...) { return false; } return true; } @@ -503,6 +505,7 @@ static double ifc_length_unit = 1.0; static double ifc_planeangle_unit = -1.0; static double force_ccw_face_orientation = -1.0; static double modelling_precision = 0.00001; +static double dimensionality = 1; void IfcGeom::Kernel::setValue(GeomValue var, double value) { switch (var) { @@ -533,6 +536,9 @@ void IfcGeom::Kernel::setValue(GeomValue var, double value) { case GV_PRECISION: modelling_precision = value; break; + case GV_DIMENSIONALITY: + dimensionality = value; + break; default: assert(!"never reach here"); } @@ -562,6 +568,9 @@ double IfcGeom::Kernel::getValue(GeomValue var) { case GV_PRECISION: return modelling_precision; break; + case GV_DIMENSIONALITY: + return dimensionality; + break; } assert(!"never reach here"); return 0; @@ -911,12 +920,20 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes); } + std::string context_string = ""; + if (representation->hasRepresentationIdentifier()) { + context_string = representation->RepresentationIdentifier(); + } else if (representation->ContextOfItems()->hasContextType()) { + context_string = representation->ContextOfItems()->ContextType(); + } + return new BRepElement

( product->entity->id(), parent_id, name, product_type, guid, + context_string, trsf, shape ); diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 81c4519283..e0d51c22a8 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -39,7 +39,7 @@ * IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the * * orientation and translation of the mesh in relation to the world origin * * * - * IfcGeom::Iterator::findContext() * + * IfcGeom::Iterator::initialize() * * finds the most suitable representation contexts. Returns true iff * * at least a single representation will process successfully * * * @@ -143,19 +143,24 @@ namespace IfcGeom { } public: - bool findContext() { + bool initialize() { try { initUnits(); } catch (...) {} - // Really this should only be 'Model', as per - // the standard 'Design' is deprecated. So, - // just for backwards compatibility: std::set context_types; - context_types.insert("model"); - context_types.insert("design"); - // DDS likes to output 'model view' - context_types.insert("model view"); + if (!settings.exclude_solids_and_surfaces()) { + // Really this should only be 'Model', as per + // the standard 'Design' is deprecated. So, + // just for backwards compatibility: + context_types.insert("model"); + context_types.insert("design"); + // DDS likes to output 'model view' + context_types.insert("model view"); + } + if (settings.include_curves()) { + context_types.insert("plan"); + } double lowest_precision_encountered = std::numeric_limits::infinity(); bool any_precision_encountered = false; @@ -407,7 +412,7 @@ namespace IfcGeom { } catch(...) {} ElementSettings element_settings(settings, unit_magnitude, instance_type); - Element

* ifc_object = new Element

(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf); + Element

* ifc_object = new Element

(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf); return ifc_object; } @@ -432,7 +437,7 @@ namespace IfcGeom { } } private: - void initialize() { + void _initialize() { current_triangulation = 0; current_shape_model = 0; current_serialization = 0; @@ -446,34 +451,35 @@ namespace IfcGeom { kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1); + kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); } public: Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file) : settings(settings) , ifc_file(file) { - initialize(); + _initialize(); } Iterator(const IteratorSettings& settings, const std::string& filename) : settings(settings) , ifc_file(new IfcParse::IfcFile) { ifc_file->Init(filename); - initialize(); + _initialize(); } Iterator(const IteratorSettings& settings, void* data, int length) : settings(settings) , ifc_file(new IfcParse::IfcFile) { ifc_file->Init(data, length); - initialize(); + _initialize(); } Iterator(const IteratorSettings& settings, std::istream& filestream, int length) : settings(settings) , ifc_file(new IfcParse::IfcFile) { ifc_file->Init(filestream, length); - initialize(); + _initialize(); } ~Iterator() { diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index f34e7294c0..7b59ea8bbb 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -66,11 +66,15 @@ namespace IfcGeom { static const int DISABLE_TRIANGULATION = 9; // Applies default materials to entity instances without a surface style. static const int APPLY_DEFAULT_MATERIALS = 10; + // Specifies whether to include subtypes of IfcCurve. + static const int INCLUDE_CURVES = 11; + // Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface. + static const int EXCLUDE_SOLIDS_AND_SURFACES = 12; // End of settings enumeration. private: - bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials; + bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces; double _deflection_tolerance; public: IteratorSettings() @@ -84,6 +88,8 @@ namespace IfcGeom { , _disable_opening_subtractions(false) , _disable_triangulation(false) , _apply_default_materials(false) + , _include_curves(false) + , _exclude_solids_and_surfaces(false) // TODO: Make deflection tolerance into a command line argument // For now, stick to one millimeter. Note that this is independent of the IFC length unit. , _deflection_tolerance(1.e-3) @@ -109,6 +115,10 @@ namespace IfcGeom { bool& disable_triangulation() { return _disable_triangulation; } const bool& apply_default_materials() const { return _apply_default_materials; } bool& apply_default_materials() { return _apply_default_materials; } + const bool& include_curves() const { return _include_curves; } + bool& include_curves() { return _include_curves; } + const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; } + bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; } const double& deflection_tolerance() const { return _deflection_tolerance; } double& deflection_tolerance() { return _deflection_tolerance; } @@ -145,6 +155,12 @@ namespace IfcGeom { case APPLY_DEFAULT_MATERIALS: _apply_default_materials = value; break; + case INCLUDE_CURVES: + _include_curves = value; + break; + case EXCLUDE_SOLIDS_AND_SURFACES: + _exclude_solids_and_surfaces = value; + break; default: throw IfcParse::IfcException("Invalid IteratorSetting"); } } diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index b151b29cbb..f2b1fc3ca7 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -29,6 +29,9 @@ #include +#include +#include + #include "../ifcgeom/IfcGeomIteratorSettings.h" #include "../ifcgeom/IfcGeomMaterial.h" #include "../ifcgeom/IfcRepresentationShapeItem.h" @@ -150,10 +153,11 @@ namespace IfcGeom { Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape"); continue; } - TopExp_Explorer exp; // Iterates over the faces of the shape - for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) { + int num_faces = 0; + TopExp_Explorer exp; + for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) { TopoDS_Face face = TopoDS::Face(exp.Current()); TopLoc_Location loc; Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc); @@ -191,9 +195,9 @@ namespace IfcGeom { if (normal_direction.Magnitude() > ALMOST_ZERO) { normal = gp_Dir(normal_direction.XYZ() * rotation_matrix); } - _normals.push_back((float)normal.X()); - _normals.push_back((float)normal.Y()); - _normals.push_back((float)normal.Z()); + _normals.push_back(static_cast

(normal.X())); + _normals.push_back(static_cast

(normal.Y())); + _normals.push_back(static_cast

(normal.Z())); } } @@ -224,15 +228,47 @@ namespace IfcGeom { _material_ids.push_back(surface_style_id); - addEdge(n1,n2,edgecount,edges_temp); - addEdge(n2,n3,edgecount,edges_temp); - addEdge(n3,n1,edgecount,edges_temp); + addEdge(n1, n2, edgecount, edges_temp); + addEdge(n2, n3, edgecount, edges_temp); + addEdge(n3, n1, edgecount, edges_temp); } for ( std::vector >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) { - _edges.push_back(edgecount[*it]==1); + if (edgecount[*it] == 1) { + // non manifold edge, face boundary + _edges.push_back(it->first); + _edges.push_back(it->second); + } } } } + + if (num_faces == 0) { + // Edges are only emitted if there are no faces. A mixed representation of faces + // and loose edges is discouraged by the standard. An alternative would be to use + // TopExp::MapShapesAndAncestors() to find edges that do not belong to any face. + for (TopExp_Explorer exp(s, TopAbs_EDGE); exp.More(); exp.Next()) { + BRepAdaptor_Curve crv(TopoDS::Edge(exp.Current())); + GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance()); + int n = tessellater.NbPoints(); + int start = _verts.size() / 3; + for (int i = 1; i <= n; ++i) { + gp_XYZ p = tessellater.Value(i).XYZ(); + trsf.Transforms(p); + + _material_ids.push_back(surface_style_id); + + _verts.push_back(static_cast

(p.X())); + _verts.push_back(static_cast

(p.Y())); + _verts.push_back(static_cast

(p.Z())); + + if (i > 1) { + _edges.push_back(start + i - 2); + _edges.push_back(start + i - 1); + } + } + } + } + } } virtual ~Triangulation() {} diff --git a/src/ifcgeom/IfcGeomShapeType.h b/src/ifcgeom/IfcGeomShapeType.h new file mode 100644 index 0000000000..3d2c11233a --- /dev/null +++ b/src/ifcgeom/IfcGeomShapeType.h @@ -0,0 +1,38 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#ifndef IFCGEOMSHAPETYPE_H +#define IFCGEOMSHAPETYPE_H + +namespace IfcGeom { + + enum ShapeType { + ST_SHAPELIST, + ST_SHAPE, + ST_FACE, + ST_WIRE, + ST_CURVE, + ST_EDGE, + ST_VERTEX, + ST_OTHER + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index f9f905d6c5..16c90666e8 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -278,16 +278,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); - if ( is_shape_collection(operand1) ) { + if ( shape_type(operand1) == ST_SHAPELIST ) { if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { return false; } - } else { + } else if ( shape_type(operand1) == ST_SHAPE ) { if ( ! convert_shape(operand1, s1) ) { return false; } { TopoDS_Solid temp_solid; s1 = ensure_fit_for_subtraction(s1, temp_solid); } + } else { + Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1->entity); + return false; } const double first_operand_volume = shape_volume(s1); @@ -295,14 +298,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); bool shape2_processed = false; - if ( is_shape_collection(operand2) ) { + if ( shape_type(operand2) == ST_SHAPELIST ) { shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); - } else { + } else if ( shape_type(operand2) == ST_SHAPE ) { shape2_processed = convert_shape(operand2,s2); if (shape2_processed && !is_halfspace) { TopoDS_Solid temp_solid; s2 = ensure_fit_for_subtraction(s2, temp_solid); } + } else { + Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2->entity); } if (!shape2_processed) { @@ -494,13 +499,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati return b; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcShapeRepresentation* l, IfcRepresentationShapeItems& shapes) { +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) { IfcSchema::IfcRepresentationItem::list::ptr items = l->Items(); bool part_succes = false; if ( items->size() ) { for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) { IfcSchema::IfcRepresentationItem* representation_item = *it; - if ( is_shape_collection(representation_item) ) { + if ( shape_type(representation_item) == ST_SHAPELIST ) { part_succes |= convert_shapes(*it, shapes); } else { TopoDS_Shape s; @@ -521,14 +526,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta const IfcGeom::SurfaceStyle* parent_style = get_style(l); for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) { IfcSchema::IfcGeometricSetSelect* element = *it; - if (element->is(IfcSchema::Type::IfcSurface)) { - IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element; - TopoDS_Shape s; - if (convert_shape(surface, s)) { - part_succes = true; - const IfcGeom::SurfaceStyle* style = get_style(surface); - shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style)); + TopoDS_Shape s; + if (convert_shape(element, s)) { + part_succes = true; + const IfcGeom::SurfaceStyle* style = 0; + if (element->is(IfcSchema::Type::IfcPoint)) { + style = get_style((IfcSchema::IfcPoint*) element); + } else if (element->is(IfcSchema::Type::IfcCurve)) { + style = get_style((IfcSchema::IfcCurve*) element); + } else if (element->is(IfcSchema::Type::IfcSurface)) { + style = get_style((IfcSchema::IfcSurface*) element); } + shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style)); } } return part_succes; diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/IfcGeomWires.cpp index f7600b4d60..48e5166723 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -65,6 +65,8 @@ #include #include #include + +#include #include #include #include @@ -435,3 +437,64 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu result = mw; return true; } + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) { + if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity); + return false; + } + + IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry(); + IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry(); + if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); + return false; + } + + gp_Pnt p1, p2; + if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || + !convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) + { + return false; + } + + BRepBuilderAPI_MakeWire mw; + mw.Add(BRepBuilderAPI_MakeEdge(p1, p2)); + + result = mw.Wire(); + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) { + if (convert(l->EdgeElement(), result)) { + if (!l->Orientation()) { + result.Reverse(); + } + return true; + } else { + return false; + } +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) { + TopoDS_Wire temp; + if (convert(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) { + TopExp_Explorer exp(result, TopAbs_EDGE); + TopoDS_Edge edge = TopoDS::Edge(exp.Current()); + Standard_Real u1, u2; + Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2); + TopoDS_Vertex v1, v2; + TopExp::Vertices(temp, v1, v2); + BRepBuilderAPI_MakeWire mw; + mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2)); + result = mw.Wire(); + return true; + } else { + return false; + } +} + + + + + diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/IfcRegister.cpp index 9b58176120..e00654da5d 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/IfcRegister.cpp @@ -18,6 +18,7 @@ ********************************************************************************/ #include "IfcGeom.h" +#include "IfcGeomShapeType.h" using namespace IfcSchema; using namespace IfcUtil; @@ -28,24 +29,59 @@ bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationSha return false; } -bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) { -#include "IfcRegisterIsShapeCollection.h" - return false; +IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) { +#include "IfcRegisterShapeType.h" + return ST_OTHER; } bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { const unsigned int id = l->entity->id(); bool success = false; bool processed = false; + bool ignored = false; + std::map::const_iterator it = cache.Shape.find(id); if ( it != cache.Shape.end() ) { r = it->second; return true; } + const bool include_curves = getValue(GV_DIMENSIONALITY) != +1; + const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1; + + IfcGeom::ShapeType st = shape_type(l); + ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE)); + if (st == ST_SHAPELIST) { + processed = true; + IfcRepresentationShapeItems items; + success = convert_shapes(l, items) && flatten_shape_list(items, r, false); + } else if (st == ST_SHAPE && include_solids_and_surfaces) { #include "IfcRegisterConvertShape.h" - if ( processed ) { + } else if (st == ST_FACE && include_solids_and_surfaces) { + processed = true; + success = convert_face(l, r); + } else if (st == ST_WIRE && include_curves) { + processed = true; + TopoDS_Wire w; + success = convert_wire(l, w); + if (success) { + r = w; + } + } else if (st == ST_CURVE && include_curves) { + processed = true; + Handle(Geom_Curve) crv; + TopoDS_Wire w; + success = convert_curve(l, crv) && convert_curve_to_wire(crv, w); + if (success) { + r = w; + } + } + + if ( processed && success ) { const double precision = getValue(GV_PRECISION); apply_tolerance(r, precision); cache.Shape[id] = r; - } else { - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); + } else if (!ignored) { + const char* const msg = processed + ? "Failed to convert:" + : "No operation defined for:"; + Logger::Message(Logger::LOG_ERROR, msg, l->entity); } return success; } diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/IfcRegister.h index 15f8fe0d23..3ce2edf403 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/IfcRegister.h @@ -43,7 +43,7 @@ SHAPES(IfcShellBasedSurfaceModel); SHAPES(IfcFaceBasedSurfaceModel); -SHAPES(IfcShapeRepresentation); +SHAPES(IfcRepresentation); SHAPES(IfcMappedItem); SHAPES(IfcFacetedBrep); SHAPES(IfcGeometricSet); @@ -96,6 +96,9 @@ FACE(IfcDerivedProfileDef); FACE(IfcFace); WIRE(IfcEdgeCurve); +WIRE(IfcSubedge); +WIRE(IfcOrientedEdge); +WIRE(IfcEdge); WIRE(IfcEdgeLoop); WIRE(IfcPolyline); WIRE(IfcPolyLoop); diff --git a/src/ifcgeom/IfcRegisterIsShapeCollection.h b/src/ifcgeom/IfcRegisterIsShapeCollection.h deleted file mode 100644 index 8545a71614..0000000000 --- a/src/ifcgeom/IfcRegisterIsShapeCollection.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define SHAPES(T) \ - if ( l->is(T::Class()) ) return true; -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterShapeType.h b/src/ifcgeom/IfcRegisterShapeType.h new file mode 100644 index 0000000000..d11d64c9b0 --- /dev/null +++ b/src/ifcgeom/IfcRegisterShapeType.h @@ -0,0 +1,14 @@ +#include "IfcRegisterUndef.h" +#define SHAPES(T) \ + if ( l->is(T::Class()) ) return ST_SHAPELIST; +#define SHAPE(T) \ + if ( l->is(T::Class()) ) return ST_SHAPE; +#define WIRE(T) \ + if ( l->is(T::Class()) ) return ST_WIRE; +#define FACE(T) \ + if ( l->is(T::Class()) ) return ST_FACE; +#define CURVE(T) \ + if ( l->is(T::Class()) ) return ST_CURVE; +#include "IfcRegisterDef.h" + +#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index fcd0e279cd..b04b5042ce 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -299,7 +299,7 @@ int main (int argc, char** argv) { settings.force_ccw_face_orientation() = true; iterator = new IfcGeom::Iterator(settings, data, len); - has_more = iterator->findContext(); + has_more = iterator->initialize(); More(has_more).write(std::cout); continue; diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index 5a2eeb62fe..dde5cc8547 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -17,6 +17,9 @@ * * ********************************************************************************/ +#include +#include + #include #include #include @@ -215,7 +218,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, IfcGeom::Iterator iterator(settings, fn_mb); - if (!iterator.findContext()) return false; + if (!iterator.initialize()) return false; itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL); @@ -244,11 +247,37 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end(); + typedef std::pair edge_t; + + std::set face_boundaries; + for(std::vector::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) { + const int v1 = *it++; + const int v2 = *it++; + + const edge_t e((std::min)(v1, v2), (std::max)(v1, v2)); + face_boundaries.insert(e); + } + for( int i = 0; i < numFaces; i ++ ) { - tri->mesh.faces[i].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]); - tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]); + const int v1 = o->geometry().faces()[3*i+0]; + const int v2 = o->geometry().faces()[3*i+1]; + const int v3 = o->geometry().faces()[3*i+2]; + + const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2)); + const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3)); + const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1)); + + const bool b1 = face_boundaries.find(e1) != face_boundaries.end(); + const bool b2 = face_boundaries.find(e2) != face_boundaries.end(); + const bool b3 = face_boundaries.find(e3) != face_boundaries.end(); + + tri->mesh.faces[i].setVerts(v1, v2, v3); + tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3); + MtlID mtlid = o->geometry().material_ids()[i]; - if (needs_default) mtlid ++; + if (needs_default) { + mtlid ++; + } tri->mesh.faces[i].setMatID(mtlid); } diff --git a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py index d160bf8350..ba7c2ddcc4 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py @@ -74,7 +74,7 @@ def create_shape(settings, inst): def iterate(settings, filename): it = iterator(settings, filename) - if it.findContext(): + if it.initialize(): while True: yield it.get() if not it.next(): break diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 2b705a1cd9..94c59f80ac 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -145,6 +145,7 @@ name = property(name) type = property(type) guid = property(guid) + context = property(context) transformation = property(transformation) %} }; @@ -198,8 +199,14 @@ }; %inline %{ - boost::variant*, IfcGeom::Representation::Representation*> create_shape(IfcGeom::IteratorSettings& settings, IfcParse::IfcLateBoundEntity* instance) { + boost::variant*, IfcGeom::Representation::Representation*> create_shape(IfcGeom::IteratorSettings& settings, IfcParse::IfcLateBoundEntity* instance, IfcParse::IfcLateBoundEntity* representation = 0) { if (instance->is(IfcSchema::Type::IfcProduct)) { + if (representation) { + if (!representation->is(IfcSchema::Type::IfcRepresentation)) { + throw IfcParse::IfcException("Supplied representation not of type IfcRepresentation"); + } + } + IfcParse::IfcFile* file = instance->entity->file; IfcSchema::IfcProject::list::ptr projects = file->entitiesByType(); @@ -211,28 +218,39 @@ IfcGeom::Kernel kernel; kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1); + kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); IfcSchema::IfcProduct* product = (IfcSchema::IfcProduct*) instance; - if (!product->hasRepresentation()) { + if (!representation && !product->hasRepresentation()) { throw IfcParse::IfcException("Representation is NULL"); } IfcSchema::IfcProductRepresentation* prodrep = product->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - IfcSchema::IfcRepresentation* representation = 0; + IfcSchema::IfcRepresentation* ifc_representation = (IfcSchema::IfcRepresentation*) representation; - // First, try to find a representation with a 'Body' identifier - for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { - IfcSchema::IfcRepresentation* rep = *it; - if (rep->RepresentationIdentifier() == "Body") { - representation = rep; - break; + if (!ifc_representation) { + // First, try to find a representation based on the settings + for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { + IfcSchema::IfcRepresentation* rep = *it; + if (!settings.exclude_solids_and_surfaces()) { + if (rep->RepresentationIdentifier() == "Body") { + ifc_representation = rep; + break; + } + } + if (settings.include_curves()) { + if (rep->RepresentationIdentifier() == "Plan" || rep->RepresentationIdentifier() == "Axis") { + ifc_representation = rep; + break; + } + } } } - // Otherwise, find a representation within the 'Model' context - if (!representation) { + // Otherwise, find a representation within the 'Model' or 'Plan' context + if (!ifc_representation) { for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { IfcSchema::IfcRepresentation* rep = *it; IfcSchema::IfcRepresentationContext* context = rep->ContextOfItems(); @@ -240,26 +258,36 @@ // TODO: Remove redundancy with IfcGeomIterator.h if (context->hasContextType()) { std::set context_types; - context_types.insert("model"); - context_types.insert("design"); - context_types.insert("model view"); + if (!settings.exclude_solids_and_surfaces()) { + context_types.insert("model"); + context_types.insert("design"); + context_types.insert("model view"); + } + if (settings.include_curves()) { + context_types.insert("plan"); + } std::string context_type_lc = context->ContextType(); for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) { *c = tolower(*c); } if (context_types.find(context_type_lc) != context_types.end()) { - representation = rep; + ifc_representation = rep; } } } } - if (!representation) { - throw IfcParse::IfcException("No IfcRepresentations with a 'Body' RepresentationIdentifier found"); + if (!ifc_representation) { + if (reps->size()) { + // Return a random representation + ifc_representation = *reps->begin(); + } else { + throw IfcParse::IfcException("No suitable IfcRepresentation found"); + } } - IfcSchema::IfcRepresentationContext* ctx = representation->ContextOfItems(); + IfcSchema::IfcRepresentationContext* ctx = ifc_representation->ContextOfItems(); if (!ctx->is(IfcSchema::Type::IfcGeometricRepresentationContext)) { throw IfcParse::IfcException("Context not of type IfcGeometricRepresentationContext"); } @@ -281,7 +309,7 @@ kernel.setValue(IfcGeom::Kernel::GV_PRECISION, precision); - IfcGeom::BRepElement* brep = kernel.create_brep_for_representation_and_product(settings, representation, product); + IfcGeom::BRepElement* brep = kernel.create_brep_for_representation_and_product(settings, ifc_representation, product); if (!brep) { throw IfcParse::IfcException("Failed to process shape"); } diff --git a/win/IfcGeom.vcproj b/win/IfcGeom.vcproj index 22e36838c8..561649b717 100644 --- a/win/IfcGeom.vcproj +++ b/win/IfcGeom.vcproj @@ -224,6 +224,10 @@ RelativePath="..\src\ifcgeom\IfcGeomRepresentation.h" > + + @@ -261,11 +265,11 @@ >