From 3cba2422951e64c6b2cffc4fbbcad12dd714b1b8 Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 14 Aug 2015 22:11:32 +0200 Subject: [PATCH 01/10] When built without ICU filter characters outside of unencoded range --- src/ifcparse/IfcCharacterDecoder.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ifcparse/IfcCharacterDecoder.cpp b/src/ifcparse/IfcCharacterDecoder.cpp index c33a6f9b0c..c3eeb186d7 100644 --- a/src/ifcparse/IfcCharacterDecoder.cpp +++ b/src/ifcparse/IfcCharacterDecoder.cpp @@ -352,8 +352,15 @@ IfcCharacterEncoder::operator std::string() { #else for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { char ch = *i; - if ( ch == '\\' || ch == '\'' ) oss.put(ch); - oss.put(ch); + const bool within_spf_range = ch >= 0x20 && ch <= 0x7e; + if (within_spf_range) { + if ( ch == '\\' || ch == '\'' ) { + oss.put(ch); + } + oss.put(ch); + } else { + oss.put('_'); + } } #endif oss.put('\''); From 4385f3b14dce676248f24a3de3b0afc8a6fe5660 Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 4 Sep 2015 11:46:52 +0200 Subject: [PATCH 02/10] Revert some of the typemap work in b96cf38e1729761e1065c8a83748584e89128613 and rely on a general mapping from const vector to tuple --- src/ifcwrap/IfcGeomWrapper.i | 57 ++++------------------------- src/ifcwrap/utils/type_conversion.i | 4 +- src/ifcwrap/utils/typemaps_out.i | 1 + 3 files changed, 12 insertions(+), 50 deletions(-) diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 3b669d069b..1069f6ba30 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -93,47 +93,6 @@ %ignore IfcGeom::Iterator::Iterator(const IfcGeom::IteratorSettings&, void*, int); %ignore IfcGeom::Iterator::Iterator(const IfcGeom::IteratorSettings&, std::istream&, int); -// Ignore the std::vector accessors and replace them to pairs that will -// be expanded to Python tuples by means of typemaps. This in order to -// minimize passing STL objects across dynamic library boundaries. -%ignore IfcGeom::Representation::Triangulation::verts; -%ignore IfcGeom::Representation::Triangulation::faces; -%ignore IfcGeom::Representation::Triangulation::edges; -%ignore IfcGeom::Representation::Triangulation::normals; -%ignore IfcGeom::Representation::Triangulation::material_ids; -%ignore IfcGeom::Representation::Triangulation::materials; -%extend IfcGeom::Representation::Triangulation { - std::pair get_faces() { - return std::make_pair(&$self->faces()[0], $self->faces().size()); - } - std::pair get_edges() { - return std::make_pair(&$self->edges()[0], $self->edges().size()); - } - std::pair get_material_ids() { - return std::make_pair(&$self->material_ids()[0], $self->material_ids().size()); - } - std::pair get_materials() { - return std::make_pair(&$self->materials()[0], $self->materials().size()); - } -} -%extend IfcGeom::Representation::Triangulation { - std::pair get_verts() { - return std::make_pair(&$self->verts()[0], $self->verts().size()); - } - std::pair get_normals() { - return std::make_pair(&$self->normals()[0], $self->normals().size()); - } -} -%extend IfcGeom::Representation::Triangulation { - std::pair get_verts() { - return std::make_pair(&$self->verts()[0], $self->verts().size()); - } - std::pair get_normals() { - return std::make_pair(&$self->normals()[0], $self->normals().size()); - } -} - - %extend IfcGeom::IteratorSettings { %pythoncode %{ attrs = ("convert_back_units", "deflection_tolerance", "disable_opening_subtractions", "disable_triangulation", "faster_booleans", "sew_shells", "use_brep_data", "use_world_coords", "weld_vertices") @@ -159,10 +118,10 @@ if _newclass: # Hide the getters with read-only property implementations id = property(id) - faces = property(get_faces) - edges = property(get_edges) - material_ids = property(get_material_ids) - materials = property(get_materials) + faces = property(faces) + edges = property(edges) + material_ids = property(material_ids) + materials = property(materials) %} }; @@ -172,16 +131,16 @@ %pythoncode %{ if _newclass: # Hide the getters with read-only property implementations - verts = property(get_verts) - normals = property(get_normals) + verts = property(verts) + normals = property(normals) %} }; %extend IfcGeom::Representation::Triangulation { %pythoncode %{ if _newclass: # Hide the getters with read-only property implementations - verts = property(get_verts) - normals = property(get_normals) + verts = property(verts) + normals = property(normals) %} }; diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i index 604be11ced..1f83559a5f 100644 --- a/src/ifcwrap/utils/type_conversion.i +++ b/src/ifcwrap/utils/type_conversion.i @@ -112,7 +112,9 @@ PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); } PyObject* pythonize(const std::string& t) { return PyString_FromString(t.c_str()); } PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); } - + // NB: This cannot be temporary as a Python object is constructed from a pointer to the address of this object + PyObject* pythonize(const IfcGeom::Material& t) { return SWIG_NewPointerObj(SWIG_as_voidptr(&t), SWIGTYPE_p_IfcGeom__Material, 0); } + PyObject* pythonize(const boost::dynamic_bitset<>& t) { std::string bitstring; boost::to_string(t, bitstring); diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i index 5680a07ab5..69cccc8081 100644 --- a/src/ifcwrap/utils/typemaps_out.i +++ b/src/ifcwrap/utils/typemaps_out.i @@ -105,3 +105,4 @@ CREATE_VECTOR_TYPEMAP_OUT(int) CREATE_VECTOR_TYPEMAP_OUT(unsigned int) CREATE_VECTOR_TYPEMAP_OUT(double) CREATE_VECTOR_TYPEMAP_OUT(std::string) +CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::Material) From 22a8d9a17b59e260005a902ff3be0f823277a3c0 Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 4 Sep 2015 11:48:53 +0200 Subject: [PATCH 03/10] Don't leave MakeFace in an invalid state when one of the face boundaries cannot be processed or is not planar --- src/ifcgeom/IfcGeomFaces.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/IfcGeomFaces.cpp index 7adc9eb998..fe0b36681f 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/IfcGeomFaces.cpp @@ -164,7 +164,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { if (is_interior == !process_interior) continue; TopoDS_Wire wire; - if (!convert_wire(loop, wire)) break; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + delete mf; + return false; + } /* The approach below does not result in a significant speed-up @@ -252,13 +256,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { // Reinitialize the builder to the outer face // bound in order to add holes more robustly. delete mf; + // TODO: What about the face_surface? mf = new BRepBuilderAPI_MakeFace(outer_face_bound); } else { face = outer_face_bound; success = true; } } else { - break; + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity); + delete mf; + return false; } } else { From 82143f226e1affb5a7477870bead31cc8ca67cf6 Mon Sep 17 00:00:00 2001 From: aothms Date: Sun, 6 Sep 2015 14:50:07 +0200 Subject: [PATCH 04/10] Small changes to SVG serialization --- src/ifcconvert/SvgSerializer.cpp | 30 +++++++++++++++++++----------- src/ifcconvert/SvgSerializer.h | 3 +++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/ifcconvert/SvgSerializer.cpp b/src/ifcconvert/SvgSerializer.cpp index 80b61062b0..8319393ff8 100644 --- a/src/ifcconvert/SvgSerializer.cpp +++ b/src/ifcconvert/SvgSerializer.cpp @@ -90,16 +90,10 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) { path.add(","); addYCoordinate(path.add(p1.Y())); - if (p1.X() < xmin) xmin = p1.X(); - if (p1.X() > xmax) xmax = p1.X(); - if (p1.Y() < ymin) ymin = p1.Y(); - if (p1.Y() > ymax) ymax = p1.Y(); + growBoundingBox(p1.X(), p1.Y()); } - if (p2.X() < xmin) xmin = p2.X(); - if (p2.X() > xmax) xmax = p2.X(); - if (p2.Y() < ymin) ymin = p2.Y(); - if (p2.Y() > ymax) ymax = p2.Y(); + growBoundingBox(p2.X(), p2.Y()); Handle(Standard_Type) ty = curve->DynamicType(); @@ -218,7 +212,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement* o) { if (!storey) return; - path_object& p = start_path(storey, o->unique_id()); + path_object& p = start_path(storey, nameElement(o)); for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { gp_GTrsf gtrsf = it->Placement(); @@ -334,9 +328,9 @@ void SvgSerializer::finalize() { svg_file << " \n"; } std::ostringstream oss; - svg_file << " first->GlobalId()).formatted() << "\">\n"; + svg_file << " first) << ">\n"; } - svg_file << " second.first << "\">\n"; + svg_file << " second.first << ">\n"; std::vector::const_iterator jt; for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) { svg_file << jt->str(); @@ -353,3 +347,17 @@ void SvgSerializer::finalize() { void SvgSerializer::writeHeader() { svg_file << "\n"; } + +std::string SvgSerializer::nameElement(const IfcGeom::Element* elem) { + std::ostringstream oss; + const std::string type = "product"; + oss << "id=\"" << type << "-" << elem->unique_id() << "\""; + return oss.str(); +} + +std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) { + std::ostringstream oss; + const std::string type = elem->is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product"; + oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\""; + return oss.str(); +} \ No newline at end of file diff --git a/src/ifcconvert/SvgSerializer.h b/src/ifcconvert/SvgSerializer.h index 04dbb34188..2efb632b6d 100644 --- a/src/ifcconvert/SvgSerializer.h +++ b/src/ifcconvert/SvgSerializer.h @@ -59,6 +59,7 @@ public: virtual void addXCoordinate(const SHARED_PTR& fi) { xcoords.push_back(fi); } virtual void addYCoordinate(const SHARED_PTR& fi) { ycoords.push_back(fi); } virtual void addSizeComponent(const SHARED_PTR& fi) { radii.push_back(fi); } + virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } virtual ~SvgSerializer() {} virtual void writeHeader(); virtual void writeMaterial(const IfcGeom::SurfaceStyle& style) {} @@ -73,6 +74,8 @@ public: virtual void setFile(IfcParse::IfcFile* f) { file = f; } virtual void setBoundingRectangle(double width, double height); virtual void setSectionHeight(double h) { section_height = h; } + virtual std::string nameElement(const IfcGeom::Element* elem); + virtual std::string nameElement(const IfcSchema::IfcProduct* elem); }; #endif From 9096895bdbb9ea9f66230c031bae3769a666b3f3 Mon Sep 17 00:00:00 2001 From: aothms Date: Tue, 8 Sep 2015 15:27:05 +0200 Subject: [PATCH 05/10] Support for schemas using TYPE definitions to redeclare BINARY types --- src/ifcexpressparser/mapping.py | 22 +++++++++++----------- src/ifcexpressparser/schema.py | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/ifcexpressparser/mapping.py b/src/ifcexpressparser/mapping.py index 76633f3746..ee536697fd 100644 --- a/src/ifcexpressparser/mapping.py +++ b/src/ifcexpressparser/mapping.py @@ -52,11 +52,11 @@ class Mapping: def simple_type_parent(self, type): parent = self.schema.types[type].type.type if isinstance(parent, nodes.AggregationType): parent = None - return None if parent in self.express_to_cpp_typemapping else parent + return None if str(parent) in self.express_to_cpp_typemapping else parent def make_type_string(self, type): - if isinstance(type, str): - return self.express_to_cpp_typemapping.get(type, type) + if isinstance(type, (str, nodes.BinaryType)): + return self.express_to_cpp_typemapping.get(str(type), type) else: is_list = self.schema.is_entity(type.type) is_nested_list = isinstance(type.type, nodes.AggregationType) @@ -83,12 +83,8 @@ class Mapping: def make_argument_type(self, attr): def _make_argument_type(type): - if type in self.express_to_cpp_typemapping: - return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper() - elif self.schema.is_entity(type) or isinstance(type, nodes.SelectType): + if self.schema.is_entity(type) or isinstance(type, nodes.SelectType): return "ENTITY_INSTANCE" - elif self.schema.is_type(type): - return _make_argument_type(self.schema.types[type].type.type) elif isinstance(type, nodes.BinaryType): return "BINARY" elif isinstance(type, nodes.EnumerationType): @@ -97,17 +93,21 @@ class Mapping: ty = _make_argument_type(type.type) if ty == "UNKNOWN": return "UNKNOWN" return "AGGREGATE_OF_" + ty + elif str(type) in self.express_to_cpp_typemapping: + return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper() + elif self.schema.is_type(type): + return _make_argument_type(self.schema.types[type].type.type) else: raise ValueError("Unable to map type %r for attribute %r" % (type, attr)) ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr) if ty not in self.supported_argument_types: - print("Attribute %r mapped as 'unknown'" % (type, attr), file=sys.stderr) + print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr) ty = 'UNKNOWN' return "IfcUtil::Argument_%s" % ty def get_type_dep(self, type): if isinstance(type, str): - return self.express_to_cpp_typemapping.get(type, type) + return self.express_to_cpp_typemapping.get(str(type), type) else: return self.get_type_dep(type.type) @@ -124,7 +124,7 @@ class Mapping: ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False) if self.schema.is_select(attr_type.type): type_str = templates.untyped_list - elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values(): + elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values(): tmpl = templates.nested_array_type if is_nested_list else templates.array_type type_str = tmpl % { 'instance_type' : ty, diff --git a/src/ifcexpressparser/schema.py b/src/ifcexpressparser/schema.py index 73ff5596fe..74d62bfacb 100644 --- a/src/ifcexpressparser/schema.py +++ b/src/ifcexpressparser/schema.py @@ -22,15 +22,15 @@ import collections class Schema: def is_enumeration(self, v): - return v in self.enumerations + return str(v) in self.enumerations def is_select(self, v): - return v in self.selects + return str(v) in self.selects def is_simpletype(self, v): - return v in self.simpletypes + return str(v) in self.simpletypes def is_type(self, v): - return v in self.types + return str(v) in self.types def is_entity(self, v): - return v in self.entities + return str(v) in self.entities def __init__(self, parsetree): self.name = parsetree[1] @@ -43,4 +43,4 @@ class Schema: self.enumerations = of_type(nodes.EnumerationType) self.selects = of_type(nodes.SelectType) - self.simpletypes = of_type(str, nodes.AggregationType) + self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType) From 2532ba30e40cd76fcf1d5ecc3b0bffcf7bf47e80 Mon Sep 17 00:00:00 2001 From: aothms Date: Thu, 10 Sep 2015 13:58:27 +0200 Subject: [PATCH 06/10] Fix addRelatedObject, fix by Cadline St2 --- src/ifcparse/IfcHierarchyHelper.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index b8ad5d7a21..f5d52b62ce 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -78,8 +78,8 @@ public: double xx=1.0, double xy=0.0, double xz=0.0); template - void addRelatedObject(IfcSchema::IfcObjectDefinition* related_object, - IfcSchema::IfcObjectDefinition* relating_object, IfcSchema::IfcOwnerHistory* owner_hist = 0) + void addRelatedObject(IfcSchema::IfcObjectDefinition* relating_object, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist = 0) { typename T::list::ptr li = entitiesByType(); bool found = false; @@ -100,9 +100,9 @@ public: if (! owner_hist) { owner_hist = addOwnerHistory(); } - IfcSchema::IfcObjectDefinition::list::ptr relating_objects (new IfcTemplatedEntityList()); - relating_objects->push(relating_object); - T* t = new T(IfcParse::IfcGlobalId(), owner_hist, boost::none, boost::none, related_object, relating_objects); + IfcSchema::IfcObjectDefinition::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push(related_object); + T* t = new T(IfcParse::IfcGlobalId(), owner_hist, boost::none, boost::none, relating_object, related_objects); addEntity(t); } } @@ -174,14 +174,14 @@ private: }; template <> -inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* related_object, - IfcSchema::IfcObjectDefinition* relating_object, IfcSchema::IfcOwnerHistory* owner_hist) +inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* relating_structure, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist) { IfcSchema::IfcRelContainedInSpatialStructure::list::ptr li = entitiesByType(); bool found = false; for (IfcSchema::IfcRelContainedInSpatialStructure::list::it i = li->begin(); i != li->end(); ++i) { IfcSchema::IfcRelContainedInSpatialStructure* rel = *i; - if (rel->RelatingStructure() == relating_object) { + if (rel->RelatingStructure() == relating_structure) { IfcSchema::IfcProduct::list::ptr products = rel->RelatedElements(); products->push((IfcSchema::IfcProduct*)related_object); rel->setRelatedElements(products); @@ -196,10 +196,10 @@ inline void IfcHierarchyHelper::addRelatedObject ()); - relating_objects->push((IfcSchema::IfcProduct*)relating_object); + IfcSchema::IfcProduct::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push((IfcSchema::IfcProduct*)related_object); IfcSchema::IfcRelContainedInSpatialStructure* t = new IfcSchema::IfcRelContainedInSpatialStructure(IfcParse::IfcGlobalId(), owner_hist, - boost::none, boost::none, relating_objects, (IfcSchema::IfcSpatialStructureElement*)related_object); + boost::none, boost::none, related_objects, (IfcSchema::IfcSpatialStructureElement*)relating_structure); addEntity(t); } From b590747db9e0a2884f07e78c99575cf86c765687 Mon Sep 17 00:00:00 2001 From: aothms Date: Thu, 10 Sep 2015 15:53:59 +0200 Subject: [PATCH 07/10] Add version information and schema identifier to Python wrapper --- src/ifcopenshell-python/ifcopenshell/__init__.py | 3 +++ src/ifcwrap/IfcParseWrapper.i | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 4d9f8b4d34..388581942b 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -141,3 +141,6 @@ def create_entity(type,*args,**kwargs): for idx, arg in attrs: e[idx] = arg return e + +version = ifcopenshell_wrapper.version() +schema_identifier = ifcopenshell_wrapper.schema_identifier() diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index a4ebb234bc..23955f190f 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -200,4 +200,12 @@ namespace IfcUtil { f->Init(s); return f; } + + const char* const schema_identifier() { + return IfcSchema::Identifier; + } + + const char* const version() { + return IFCOPENSHELL_VERSION; + } %} \ No newline at end of file From e5c20a009d10f2ea402639a4004c8f4ebdc2f4aa Mon Sep 17 00:00:00 2001 From: aothms Date: Sat, 12 Sep 2015 14:27:58 +0200 Subject: [PATCH 08/10] Add convenience method for relating objects to types. As suggested by Cadline St2. --- src/examples/IfcOpenHouse.cpp | 4 ++++ src/ifcparse/IfcHierarchyHelper.h | 32 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index 5cfb523f63..9f4887c5f9 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -381,6 +381,10 @@ int main(int argc, char** argv) { file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9); file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle(), null, null, door_opening, door)); + IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle(), S("Door type"), null, null, null, null, null, + IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false); + file.addRelatedObject(door_style, door); + // Surface styles are assigned to representation items, hence there is no real limitation to // assign different colours within the same representation. However, some viewers have // difficulties rendering products with representation items with different surface styles. diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index f5d52b62ce..7a1393632b 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -205,4 +205,36 @@ inline void IfcHierarchyHelper::addRelatedObject +inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* relating_type, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist) +{ + IfcSchema::IfcRelDefinesByType::list::ptr li = entitiesByType(); + bool found = false; + for (IfcSchema::IfcRelDefinesByType::list::it i = li->begin(); i != li->end(); ++i) { + IfcSchema::IfcRelDefinesByType* rel = *i; + if (rel->RelatingType() == relating_type) { + IfcSchema::IfcObject::list::ptr objects = rel->RelatedObjects(); + objects->push((IfcSchema::IfcObject*)related_object); + rel->setRelatedObjects(objects); + found = true; + break; + } + } + if (! found) { + if (! owner_hist) { + owner_hist = getSingle(); + } + if (! owner_hist) { + owner_hist = addOwnerHistory(); + } + IfcSchema::IfcObject::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push((IfcSchema::IfcObject*)related_object); + IfcSchema::IfcRelDefinesByType* t = new IfcSchema::IfcRelDefinesByType(IfcParse::IfcGlobalId(), owner_hist, + boost::none, boost::none, related_objects, (IfcSchema::IfcTypeObject*)relating_type); + + addEntity(t); + } +} + #endif \ No newline at end of file From a58b2ede63e927b6e28afb58d508bebcb5d98728 Mon Sep 17 00:00:00 2001 From: aothms Date: Sun, 13 Sep 2015 14:43:42 +0200 Subject: [PATCH 09/10] Fixes for unicode handling in Python --- cmake/CMakeLists.txt | 5 +++-- src/ifcopenshell-python/ifcopenshell/__init__.py | 3 +++ src/ifcparse/IfcCharacterDecoder.cpp | 2 +- src/ifcwrap/CMakeLists.txt | 2 +- src/ifcwrap/utils/type_conversion.i | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 429920293e..7431c8d566 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -56,6 +56,7 @@ FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${I IF(icu) MESSAGE(STATUS "ICU libraries found") ADD_DEFINITIONS(-DHAVE_ICU) + SET(ICU_LIBRARIES icuuc icudata) ELSE() MESSAGE(STATUS "Unable to find ICU library files, continuing") ENDIF() @@ -170,13 +171,13 @@ ADD_EXECUTABLE(IfcConvert ../src/ifcconvert/util.cpp ) -TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES}) +TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES}) ADD_EXECUTABLE(IfcGeomServer ../src/ifcgeomserver/IfcGeomServer.cpp ) -TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset) +TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${ICU_LIBRARIES}) # Build python wrapper using separate CMakeLists.txt ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 388581942b..eb14ece33a 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -82,6 +82,9 @@ class entity_instance(object): attr_type = self.attribute_type(idx).title().replace(' ', '') attr_type = attr_type.replace('Binary', 'String') attr_type = attr_type.replace('Enumeration', 'String') + try: + if isinstance(value, unicode): value = value.encode("utf-8") + except: pass getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value)) return value def __len__(self): return len(self.wrapped_data) diff --git a/src/ifcparse/IfcCharacterDecoder.cpp b/src/ifcparse/IfcCharacterDecoder.cpp index c3eeb186d7..a3aad64c1e 100644 --- a/src/ifcparse/IfcCharacterDecoder.cpp +++ b/src/ifcparse/IfcCharacterDecoder.cpp @@ -288,7 +288,7 @@ UErrorCode IfcCharacterDecoder::status = U_ZERO_ERROR; #endif #ifdef HAVE_ICU -IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::JSON; +IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::UTF8; // Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior bool IfcCharacterDecoder::compatibility_mode = false; diff --git a/src/ifcwrap/CMakeLists.txt b/src/ifcwrap/CMakeLists.txt index ba87b658c9..a5a2f36e22 100644 --- a/src/ifcwrap/CMakeLists.txt +++ b/src/ifcwrap/CMakeLists.txt @@ -16,7 +16,7 @@ SET(CMAKE_SWIG_FLAGS "") SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON) SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i) -SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${PYTHON_LIBRARIES} IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset) +SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${PYTHON_LIBRARIES} IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset ${ICU_LIBRARIES}) # To install IfcPython let's get the site-packages dir from python EXECUTE_PROCESS(COMMAND python -c "import sys; from distutils.sysconfig import get_python_lib; sys.stdout.write(get_python_lib())" diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i index 1f83559a5f..6c739033d7 100644 --- a/src/ifcwrap/utils/type_conversion.i +++ b/src/ifcwrap/utils/type_conversion.i @@ -110,7 +110,7 @@ PyObject* pythonize(const unsigned int& t) { return PyInt_FromLong(t); } PyObject* pythonize(const bool& t) { return PyBool_FromLong(t); } PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); } - PyObject* pythonize(const std::string& t) { return PyString_FromString(t.c_str()); } + PyObject* pythonize(const std::string& t) { return PyUnicode_FromString(t.c_str()); } PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); } // NB: This cannot be temporary as a Python object is constructed from a pointer to the address of this object PyObject* pythonize(const IfcGeom::Material& t) { return SWIG_NewPointerObj(SWIG_as_voidptr(&t), SWIGTYPE_p_IfcGeom__Material, 0); } From 94d214808e12fea57b22b06b5c40267dc4d16549 Mon Sep 17 00:00:00 2001 From: aothms Date: Sun, 13 Sep 2015 15:00:21 +0200 Subject: [PATCH 10/10] Use boost::to_upper() and -::to_upper_copy() for string manipulation throughout codebase --- src/ifcgeom/IfcGeomIterator.h | 7 +++---- src/ifcparse/IfcLateBoundEntity.cpp | 10 ++++------ src/ifcparse/IfcParse.cpp | 8 ++++---- src/ifcparse/IfcWrite.cpp | 4 +++- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 6c411a4fc5..fc62b3bbf4 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -64,6 +64,8 @@ #include #include +#include + #include #include #include @@ -125,10 +127,7 @@ namespace IfcGeom { void populate_set(const std::set& include_or_ignore) { entities_to_include_or_exclude.clear(); for (std::set::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) { - std::string uppercase_type = *it; - for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) { - *c = toupper(*c); - } + const std::string uppercase_type = boost::to_upper_copy(*it); IfcSchema::Type::Enum ty; try { ty = IfcSchema::Type::FromString(uppercase_type); diff --git a/src/ifcparse/IfcLateBoundEntity.cpp b/src/ifcparse/IfcLateBoundEntity.cpp index af13f6d9fd..dbe78d1d04 100644 --- a/src/ifcparse/IfcLateBoundEntity.cpp +++ b/src/ifcparse/IfcLateBoundEntity.cpp @@ -19,6 +19,8 @@ #include +#include + #include "../ifcparse/IfcWritableEntity.h" #include "../ifcparse/IfcUtil.h" @@ -44,9 +46,7 @@ IfcWrite::IfcWritableEntity* IfcParse::IfcLateBoundEntity::writable_entity() { return e; } IfcParse::IfcLateBoundEntity::IfcLateBoundEntity(const std::string& s) { - std::string S = s; - for (std::string::iterator i = S.begin(); i != S.end(); ++i ) *i = toupper(*i); - _type = IfcSchema::Type::FromString(S); + _type = IfcSchema::Type::FromString(boost::to_upper_copy(s)); entity = new IfcWrite::IfcWritableEntity(_type); for (unsigned i = 0; i < getArgumentCount(); ++i) { // Side effect of this is that a NULL attribute is created. @@ -78,9 +78,7 @@ std::string IfcParse::IfcLateBoundEntity::is_a() const { return IfcSchema::Type::ToString(_type); } bool IfcParse::IfcLateBoundEntity::is_a(const std::string& s) const { - std::string S = s; - for (std::string::iterator i = S.begin(); i != S.end(); ++i ) *i = toupper(*i); - return is(IfcSchema::Type::FromString(S)); + return is(IfcSchema::Type::FromString(boost::to_upper_copy(s))); } IfcSchema::Type::Enum IfcParse::IfcLateBoundEntity::type() const { return _type; diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 593a512a1b..ac3e0cc99c 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -28,6 +28,8 @@ #include #endif +#include + #include "../ifcparse/IfcCharacterDecoder.h" #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcException.h" @@ -855,7 +857,7 @@ std::string Entity::toString(bool upper) const { std::string dt = datatype(); if (upper) { - for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p); + boost::to_upper(dt); } if (!IfcSchema::Type::IsSimple(type()) || _id != 0) { @@ -1355,9 +1357,7 @@ IfcEntityList::ptr IfcFile::entitiesByType(IfcSchema::Type::Enum t) { } IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) { - std::string ty = t; - for (std::string::iterator p = ty.begin(); p != ty.end(); ++p ) *p = toupper(*p); - return entitiesByType(IfcSchema::Type::FromString(ty)); + return entitiesByType(IfcSchema::Type::FromString(boost::to_upper_copy(t))); } IfcEntityList::ptr IfcFile::entitiesByReference(int t) { diff --git a/src/ifcparse/IfcWrite.cpp b/src/ifcparse/IfcWrite.cpp index 934651d3e6..86486ed992 100644 --- a/src/ifcparse/IfcWrite.cpp +++ b/src/ifcparse/IfcWrite.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcWrite.h" #include "../ifcparse/IfcWritableEntity.h" @@ -91,7 +93,7 @@ std::string IfcWritableEntity::toString(bool upper) const { std::string dt = datatype(); if (upper) { - for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p); + boost::to_upper(dt); } if (_id && !IfcSchema::Type::IsSimple(type())) {