diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index b34ceda695..9077187dc3 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -102,6 +102,8 @@ ADD_LIBRARY(IfcParse STATIC
../src/ifcparse/IfcWrite.cpp
../src/ifcparse/IfcGuidHelper.cpp
+
+ ../src/ifcparse/IfcHierarchyHelper.cpp
)
ADD_LIBRARY(IfcGeom STATIC
@@ -159,6 +161,7 @@ SET(include_files_parse
../src/ifcparse/IfcCharacterDecoder.h
../src/ifcparse/IfcException.h
../src/ifcparse/IfcFile.h
+ ../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/SharedPointer.h
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
index 523563fdf5..2693ed2668 100644
--- a/src/examples/CMakeLists.txt
+++ b/src/examples/CMakeLists.txt
@@ -1,2 +1,5 @@
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
-TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
\ No newline at end of file
+TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
+
+ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
+TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet)
diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp
new file mode 100644
index 0000000000..115144deb2
--- /dev/null
+++ b/src/examples/IfcOpenHouse.cpp
@@ -0,0 +1,374 @@
+/********************************************************************************
+ * *
+ * 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 . *
+ * *
+ ********************************************************************************/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "../ifcparse/Ifc2x3.h"
+#include "../ifcparse/IfcUtil.h"
+#include "../ifcparse/IfcHierarchyHelper.h"
+#include "../ifcgeom/IfcGeom.h"
+
+// Some convinience typedefs and definitions.
+typedef std::string S;
+typedef IfcWrite::IfcGuidHelper guid;
+typedef std::pair XY;
+boost::none_t const null = (static_cast(0));
+
+// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
+void createGroundShape(TopoDS_Shape& shape);
+
+int main(int argc, char** argv) {
+
+ // The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several convience
+ // functions for working with geometry in IFC files.
+ IfcHierarchyHelper file;
+
+ // Start by adding a wall to the file, initially leaving most attributes blank.
+ Ifc2x3::IfcWallStandardCase* south_wall = new Ifc2x3::IfcWallStandardCase(
+ guid(), // GlobalId
+ 0, // OwnerHistory
+ S("South wall"), // Name
+ null, // Description
+ null, // ObjectType
+ 0, // ObjectPlacement
+ 0, // Representation
+ null // Tag
+ );
+ file.addBuildingProduct(south_wall);
+
+ // By adding a wall, a hierarchy has been automatically created that consists of the following
+ // structure: IfcProject > IfcSite > IfcBuilding > IfcBuildingStorey > IfcWall
+
+ // Lateron changing the name of the IfcProject can be done by obtaining a reference to the
+ // project, which was automatically created. since we know it exists.
+ file.getSingle()->setName("IfcOpenHouse");
+
+ // An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
+ south_wall->setOwnerHistory(file.getSingle());
+
+ // The wall will be shaped as a box, with the dimensions specified in millimeters.
+ Ifc2x3::IfcProductDefinitionShape* south_wall_shape = file.addBox(10000, 360, 3000);
+
+ // The shape has to be assigned to the representation of the wall and is placed at the origin
+ // of the coordinate system.
+ south_wall->setRepresentation(south_wall_shape);
+ south_wall->setObjectPlacement(file.addLocalPlacement());
+
+ // A pale white colour is assigned to the wall.
+ Ifc2x3::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
+ south_wall->Representation(), 0.75, 0.73, 0.68);
+
+ // Now create a footing for the wall to rest on.
+ Ifc2x3::IfcFooting* footing = new Ifc2x3::IfcFooting(guid(), file.getSingle(),
+ S("Footing"), null, null, 0, 0, null, Ifc2x3::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
+
+ file.addBuildingProduct(footing);
+
+ // The footing will span the entire floor plan of our building. The IfcRepresentationContext is
+ // something that has been created automatically as well, but representations could have been
+ // assigned to a specific context, for example to add a two dimensional plan representation as well.
+ footing->setRepresentation(file.addBox(10100, 5460, 2000, 0, 0, 0, file.getSingle()));
+ footing->setObjectPlacement(file.addLocalPlacement(0, 2500, -2000));
+ // The footing will have a dark gray colour
+ Ifc2x3::IfcPresentationStyleAssignment* footing_colour = file.setSurfaceColour(footing->Representation(), 0.26, 0.22, 0.18);
+
+ // IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
+ // to clip geometry to a surface, for example to a slanted roof. For openings that are filled
+ // with another element, for example a door or a window, an IfcOpeningElement is used instead.
+ // An opening element is created with rectangular geometry
+ Ifc2x3::IfcOpeningElement* west_opening = new Ifc2x3::IfcOpeningElement(guid(), file.getSingle(),
+ null, null, null, file.addLocalPlacement(-2500, 0, 400),
+ file.addBox(6000, 3630, 1600, 0, 0, 0, file.getSingle()), null);
+ file.AddEntity(west_opening);
+
+ // Relate the opening element to the wall.
+ Ifc2x3::IfcRelVoidsElement* void_element = new Ifc2x3::IfcRelVoidsElement(guid(), file.getSingle(),
+ null, null, south_wall, west_opening);
+ file.AddEntity(void_element);
+
+ // Now create an additional opening
+ Ifc2x3::IfcOpeningElement* south_opening = new Ifc2x3::IfcOpeningElement(guid(), file.getSingle(),
+ null, null, null, file.addLocalPlacement(3000, 0, 400),
+ file.addBox(1860, 3000, 1600, 0, 0, 0, file.getSingle()), null);
+ file.AddEntity(south_opening);
+ file.AddEntity(new Ifc2x3::IfcRelVoidsElement(guid(), file.getSingle(), null, null, south_wall, south_opening));
+
+ // Create a roof element
+ Ifc2x3::IfcRoof* south_roof = new Ifc2x3::IfcRoof(guid(), file.getSingle(), S("South roof"), null, null,
+ 0, 0, null, Ifc2x3::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
+
+ // The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
+ south_roof->setRepresentation(file.addBox(10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
+ file.addTriplet(0, -sqrt(0.5), sqrt(0.5)), file.getSingle()));
+ south_roof->setObjectPlacement(file.addLocalPlacement(0, -400, 2700));
+ file.addBuildingProduct(south_roof);
+
+ // The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
+ // the local placement the roof is rotated 180 degrees around the Z-axis
+ Ifc2x3::IfcRoof* north_roof = new Ifc2x3::IfcRoof(guid(), file.getSingle(), S("North roof"),
+ null, null, 0, 0, null, Ifc2x3::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
+ north_roof->setOwnerHistory(file.getSingle());
+ north_roof->setRepresentation(south_roof->Representation());
+ north_roof->setObjectPlacement(file.addLocalPlacement(0, 5400, 2700, 0, 0, 1, -1, 0, 0));
+ file.addBuildingProduct(north_roof);
+
+ // By specifying a surface style for the south part of the roof, it gets assigned to the other
+ // roof part as well, because they share the same representation.
+ file.setSurfaceColour(south_roof->Representation(), 0.24, 0.08, 0.04);
+
+ // Copy the south wall to the north
+ file.addBuildingProduct(new Ifc2x3::IfcWallStandardCase(guid(), file.getSingle(), S("North wall"),
+ null, null, file.addLocalPlacement(0, 5000, 0), south_wall->Representation(), null));
+
+ // Now create a wall on the east of the building, again starting with just a box shape
+ Ifc2x3::IfcWallStandardCase* east_wall = new Ifc2x3::IfcWallStandardCase(guid(), file.getSingle(),
+ S("East wall"), null, null, file.addLocalPlacement(4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addBox(5000, 360, 6000), null);
+ file.addBuildingProduct(east_wall);
+
+ // The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
+ // 'axis 3d placement' that specifies the plane against which the geometry is clipped.
+ file.clipRepresentation(east_wall->Representation(), file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
+ file.clipRepresentation(east_wall->Representation(), file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
+
+ file.setSurfaceColour(east_wall->Representation(), wall_colour);
+
+ // The east wall is copied to the west location of the house
+ Ifc2x3::IfcWallStandardCase* west_wall = new Ifc2x3::IfcWallStandardCase(guid(), file.getSingle(),
+ S("West wall"), null, null, file.addLocalPlacement(-4820, 2500, 0, 0, 0, 1, 0, -1, 0), east_wall->Representation(), null);
+ file.addBuildingProduct(west_wall);
+
+ // The west wall is assigned an opening element we created for the south wall, opening elements are
+ // not shared accross building elements, even if they share the same representation. Hence, the east
+ // wall will not feature this opening.
+ file.AddEntity(new Ifc2x3::IfcRelVoidsElement(guid(), file.getSingle(), null, null, west_wall, west_opening));
+
+ // Up until now we have only used simple extrusions for the creation of the geometry. For the
+ // ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
+ // will be tesselated using the deflection specified.
+ TopoDS_Shape shape;
+ createGroundShape(shape);
+ IfcEntities geometrical_entities(new IfcEntityList());
+ Ifc2x3::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
+ file.getSingle()->setRepresentation(ground_representation);
+ file.AddEntities(geometrical_entities);
+ Ifc2x3::IfcShapeRepresentation::list ground_reps = geometrical_entities->as();
+ for (Ifc2x3::IfcShapeRepresentation::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
+ (*it)->setContextOfItems(file.getSingle());
+ }
+ file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
+
+ // According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
+ // assigned. Note that this material definition is independent of the surface styles we have
+ // been assigning to the walls already. The surface styles determine the colour in the
+ // '3D viewport' of most applications.
+ // Some BIM authoring applications, such as Autodesk Revit, ignore the geometrical representation
+ // by and large and construct native walls using the layer thickness and reference line offset
+ // provided here.
+ Ifc2x3::IfcMaterial* material = new Ifc2x3::IfcMaterial("Brick");
+ Ifc2x3::IfcMaterialLayer* layer = new Ifc2x3::IfcMaterialLayer(material, 360, null);
+ Ifc2x3::IfcMaterialLayer::list layers (new IfcTemplatedEntityList());
+ layers->push(layer);
+ Ifc2x3::IfcMaterialLayerSet* layer_set = new Ifc2x3::IfcMaterialLayerSet(layers, S("Wall"));
+ Ifc2x3::IfcMaterialLayerSetUsage* layer_usage = new Ifc2x3::IfcMaterialLayerSetUsage(layer_set,
+ Ifc2x3::IfcLayerSetDirectionEnum::IfcLayerSetDirection_AXIS2,
+ Ifc2x3::IfcDirectionSenseEnum::IfcDirectionSense_POSITIVE, -180);
+
+ Ifc2x3::IfcRelAssociatesMaterial* associates_material = new Ifc2x3::IfcRelAssociatesMaterial(guid(),
+ file.getSingle(), null, null,
+ file.EntitiesByType()->as(), layer_usage);
+
+ file.AddEntity(material);
+ file.AddEntity(layer);
+ file.AddEntity(layer_set);
+ file.AddEntity(layer_usage);
+ file.AddEntity(associates_material);
+
+ // In addition, another common way to represent geometry in IFC files is to use extrusions of
+ // planar areas bounded by a polygon.
+ std::vector stair_points;
+ stair_points.push_back(XY( 0, 0));
+ stair_points.push_back(XY(250, 0));
+ stair_points.push_back(XY(250, 200));
+ stair_points.push_back(XY(500, 200));
+ stair_points.push_back(XY(500, 400));
+ stair_points.push_back(XY( 0, 400));
+ Ifc2x3::IfcStairFlight* stair = new Ifc2x3::IfcStairFlight(guid(), file.getSingle(),
+ null, null, null, file.addLocalPlacement(5050, 1000, 0, 0, 1, 0, 1, 0, 0),
+ file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25);
+
+ file.addBuildingProduct(stair);
+ file.setSurfaceColour(stair->Representation(), footing_colour);
+
+ Ifc2x3::IfcOpeningElement* door_opening = new Ifc2x3::IfcOpeningElement(guid(), file.getSingle(),
+ null, null, null, file.addLocalPlacement(5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null);
+ file.AddEntity(door_opening);
+ file.AddEntity(new Ifc2x3::IfcRelVoidsElement(guid(), file.getSingle(), null, null, east_wall, door_opening));
+
+ // A single shape representation can contain multiple representiation items. This way a product
+ // can be a composition of multiple solids. The following door will be composed of four boxes
+ // which constitute the door and its frame.
+ Ifc2x3::IfcDoor* door = new Ifc2x3::IfcDoor(guid(), file.getSingle(), null, null, null,
+ file.addLocalPlacement(4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2120, 1000);
+ door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
+ Ifc2x3::IfcRepresentation::list door_representations = door->Representation()->Representations();
+ Ifc2x3::IfcShapeRepresentation* door_body = 0;
+ for (Ifc2x3::IfcRepresentation::it i = door_representations->begin(); i != door_representations->end(); ++i) {
+ Ifc2x3::IfcRepresentation* rep = *i;
+ if (rep->is(Ifc2x3::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
+ door_body = (Ifc2x3::IfcShapeRepresentation*) rep;
+ }
+ }
+ file.addBox(door_body, 80, 80, 2120, 0, file.addPlacement3d(-460, 0, 0));
+ file.addBox(door_body, 1000, 80, 80, 0, file.addPlacement3d( 0, 0, 2120));
+ file.addBox(door_body, 860, 30, 2120);
+ file.addBuildingProduct(door);
+ file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
+ file.AddEntity(new Ifc2x3::IfcRelFillsElement(guid(), file.getSingle(), null, null, door_opening, 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.
+ // Therefore we will construct the window as a decomposition of beams and a plate, in which
+ // only the plate will have a transparent material assigned.
+
+ // The window frame will consists of four seperate beams.
+ Ifc2x3::IfcProductDefinitionShape::list frame_representations (new IfcTemplatedEntityList());
+ frame_representations->push(file.addBox(1860, 90, 90));
+ frame_representations->push(*frame_representations->begin()); // Add a reference to the shape created above
+ frame_representations->push(file.addBox(90, 90, 1420));
+ frame_representations->push(*(frame_representations->end()-1)); // Add a reference to the shape created above
+
+ // The beams all have the same surface style assigned
+ Ifc2x3::IfcPresentationStyleAssignment* frame_style = 0;
+ for (Ifc2x3::IfcProductDefinitionShape::it i = frame_representations->begin(); i != frame_representations->end(); ++i) {
+ if (frame_style) {
+ file.setSurfaceColour(*i, frame_style);
+ } else {
+ frame_style = file.setSurfaceColour(*i, 0.5, 0.4, 0.3);
+ }
+ }
+
+ // This window will be placed at five locations within the building. A list of placements is
+ // created and is iterated over to create all window instances.
+ Ifc2x3::IfcLocalPlacement::list window_placements (new IfcTemplatedEntityList());
+ window_placements->push(file.addLocalPlacement(2*-1770-430, 0, 400));
+ window_placements->push(file.addLocalPlacement( -1770-430, 0, 400));
+ window_placements->push(file.addLocalPlacement( -430, 0, 400));
+ window_placements->push(file.addLocalPlacement( 3000, 0, 400));
+ window_placements->push(file.addLocalPlacement( -4855, 885, 400, 0, 0, 1, 0, 1, 0));
+
+ for (Ifc2x3::IfcLocalPlacement::it it = window_placements->begin(); it != window_placements->end(); ++it) {
+
+ // Create the window at the current location
+ Ifc2x3::IfcLocalPlacement* place = *it;
+ Ifc2x3::IfcWindow* window = new Ifc2x3::IfcWindow(guid(), file.getSingle(),
+ null, null, null, place, 0, null, 2000, 1600);
+ file.addBuildingProduct(window);
+
+ // Initalize a list of parts for the window to be composed of
+ Ifc2x3::IfcObjectDefinition::list window_parts(new IfcTemplatedEntityList());
+
+ // The placements for the beams are not shared accross the different windows because every
+ // beam is placed relative to its parent window entity.
+ Ifc2x3::IfcLocalPlacement::list frame_placements (new IfcTemplatedEntityList());
+ frame_placements->push(file.addLocalPlacement());
+ frame_placements->push(file.addLocalPlacement( 0, 0, 1510));
+ frame_placements->push(file.addLocalPlacement(-885, 0, 90));
+ frame_placements->push(file.addLocalPlacement( 885, 0, 90));
+
+ // Now iterate over the placements and representations of the beam and add them to list of parts
+ Ifc2x3::IfcLocalPlacement::it frame_placement;
+ Ifc2x3::IfcProductDefinitionShape::it frame_representation;
+ for (frame_placement = frame_placements->begin(), frame_representation = frame_representations->begin();
+ frame_placement != frame_placements->end() && frame_representation != frame_representations->end();
+ ++frame_placement, ++frame_representation)
+ {
+ Ifc2x3::IfcMember* frame_part = new Ifc2x3::IfcMember(guid(), file.getSingle(),
+ null, null, null, *frame_placement, *frame_representation, null);
+ file.AddEntity(frame_part);
+ window_parts->push(frame_part);
+ file.relatePlacements(window, frame_part);
+ }
+
+ // Add the glass plate to the list of parts
+ Ifc2x3::IfcPlate* glass_part = new Ifc2x3::IfcPlate(guid(), file.getSingle(), null,
+ null, null, file.addLocalPlacement(0, 0, 90), file.addBox(1680, 10, 1420), null);
+ file.AddEntity(glass_part);
+ window_parts->push(glass_part);
+ file.relatePlacements(window, glass_part);
+ file.setSurfaceColour(glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
+
+ // Now create a decomposition relation between the window and the parts. Most viewers and authoring
+ // tools will consider the window a single entity that can be selected as a whole.
+ Ifc2x3::IfcRelDecomposes* decomposition = new Ifc2x3::IfcRelAggregates(guid(), file.getSingle(),
+ null, null, window, window_parts);
+ file.AddEntity(decomposition);
+ }
+
+ // Finally create a file stream for our output and write the IFC file to it.
+ std::ofstream f("IfcOpenHouse.ifc");
+ f << file;
+}
+
+void createGroundShape(TopoDS_Shape& shape) {
+ TColgp_Array2OfPnt cv (0, 4, 0, 4);
+ cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
+ cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
+ cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
+ cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
+ cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
+ cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
+ cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
+ cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
+ cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
+ cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
+ cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
+ cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
+ cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
+ cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
+ cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
+ cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
+ cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
+ cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
+ cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
+ cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
+ cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
+ cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
+ cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
+ cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
+ cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
+ TColStd_Array1OfReal knots(0, 1);
+ knots(0) = 0;
+ knots(1) = 1;
+ TColStd_Array1OfInteger mult(0, 1);
+ mult(0) = 5;
+ mult(1) = 5;
+ Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
+ shape = BRepBuilderAPI_MakeFace(surf, 1);
+}
\ No newline at end of file
diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h
index c750cdd0f2..a9a94b185e 100644
--- a/src/ifcgeom/IfcGeom.h
+++ b/src/ifcgeom/IfcGeom.h
@@ -96,6 +96,7 @@ namespace IfcGeom {
double face_area(const TopoDS_Face& f);
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
+ Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
namespace Cache {
void Purge();
diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp
index d727d02549..d3ee6aa1a2 100644
--- a/src/ifcgeom/IfcGeomFunctions.cpp
+++ b/src/ifcgeom/IfcGeomFunctions.cpp
@@ -86,6 +86,12 @@
#include
+#include
+#include
+
+#include
+#include
+
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
@@ -489,4 +495,68 @@ double IfcGeom::GetValue(GeomValue var) {
}
assert(!"never reach here");
return 0;
+}
+
+Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es) {
+ BRepMesh::Mesh(shape, deflection);
+
+ Ifc2x3::IfcFace::list faces (new IfcTemplatedEntityList());
+
+ for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
+ const TopoDS_Face& face = TopoDS::Face(exp.Current());
+ TopLoc_Location loc;
+ Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
+
+ if (! tri.IsNull()) {
+ const TColgp_Array1OfPnt& nodes = tri->Nodes();
+ std::vector vertices;
+ for (int i = 1; i <= nodes.Length(); ++i) {
+ const gp_Pnt& pnt = nodes(i);
+ std::vector xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
+ Ifc2x3::IfcCartesianPoint* cpnt = new Ifc2x3::IfcCartesianPoint(xyz);
+ vertices.push_back(cpnt);
+ es->push(cpnt);
+ }
+ const Poly_Array1OfTriangle& triangles = tri->Triangles();
+ for (int i = 1; i <= triangles.Length(); ++ i) {
+ int n1, n2, n3;
+ triangles(i).Get(n1, n2, n3);
+ Ifc2x3::IfcCartesianPoint::list points (new IfcTemplatedEntityList());
+ points->push(vertices[n1-1]);
+ points->push(vertices[n2-1]);
+ points->push(vertices[n3-1]);
+ Ifc2x3::IfcPolyLoop* loop = new Ifc2x3::IfcPolyLoop(points);
+ Ifc2x3::IfcFaceOuterBound* bound = new Ifc2x3::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
+ Ifc2x3::IfcFaceBound::list bounds (new IfcTemplatedEntityList());
+ bounds->push(bound);
+ Ifc2x3::IfcFace* face = new Ifc2x3::IfcFace(bounds);
+ es->push(loop);
+ es->push(bound);
+ es->push(face);
+ faces->push(face);
+ }
+ }
+ }
+ Ifc2x3::IfcOpenShell* shell = new Ifc2x3::IfcOpenShell(faces);
+ Ifc2x3::IfcConnectedFaceSet::list shells (new IfcTemplatedEntityList());
+ shells->push(shell);
+ Ifc2x3::IfcFaceBasedSurfaceModel* surface_model = new Ifc2x3::IfcFaceBasedSurfaceModel(shells);
+
+ Ifc2x3::IfcRepresentation::list reps (new IfcTemplatedEntityList());
+ Ifc2x3::IfcRepresentationItem::list items (new IfcTemplatedEntityList());
+
+ items->push(surface_model);
+
+ Ifc2x3::IfcShapeRepresentation* rep = new Ifc2x3::IfcShapeRepresentation(
+ 0, std::string("Facetation"), std::string("SurfaceModel"), items);
+
+ reps->push(rep);
+ Ifc2x3::IfcProductDefinitionShape* shapedef = new Ifc2x3::IfcProductDefinitionShape(0, 0, reps);
+
+ es->push(shell);
+ es->push(surface_model);
+ es->push(rep);
+ es->push(shapedef);
+
+ return shapedef;
}
\ No newline at end of file
diff --git a/src/ifcparse/IfcHierarchyHelper.cpp b/src/ifcparse/IfcHierarchyHelper.cpp
new file mode 100644
index 0000000000..e6ea5e1ed8
--- /dev/null
+++ b/src/ifcparse/IfcHierarchyHelper.cpp
@@ -0,0 +1,386 @@
+/********************************************************************************
+ * *
+ * 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 . *
+ * *
+ ********************************************************************************/
+
+/********************************************************************************
+ * *
+ * This class is a subclass of the regular IfcFile class that implements *
+ * several convenience functions for creating geometrical representations and *
+ * spatial containers. *
+ * *
+ ********************************************************************************/
+
+#include
+
+#include "../ifcparse/IfcHierarchyHelper.h"
+
+Ifc2x3::IfcAxis2Placement3D* IfcHierarchyHelper::addPlacement3d(
+ double ox, double oy, double oz,
+ double zx, double zy, double zz,
+ double xx, double xy, double xz)
+{
+ Ifc2x3::IfcDirection* x = addTriplet(xx, xy, xz);
+ Ifc2x3::IfcDirection* z = addTriplet(zx, zy, zz);
+ Ifc2x3::IfcCartesianPoint* o = addTriplet(ox, oy, oz);
+ Ifc2x3::IfcAxis2Placement3D* p3d = new Ifc2x3::IfcAxis2Placement3D(o, z, x);
+ AddEntity(p3d);
+ return p3d;
+}
+
+Ifc2x3::IfcAxis2Placement2D* IfcHierarchyHelper::addPlacement2d(
+ double ox, double oy,
+ double xx, double xy)
+{
+ Ifc2x3::IfcDirection* x = addDoublet(xx, xy);
+ Ifc2x3::IfcCartesianPoint* o = addDoublet(ox, oy);
+ Ifc2x3::IfcAxis2Placement2D* p2d = new Ifc2x3::IfcAxis2Placement2D(o, x);
+ AddEntity(p2d);
+ return p2d;
+}
+
+Ifc2x3::IfcLocalPlacement* IfcHierarchyHelper::addLocalPlacement(
+ double ox, double oy, double oz,
+ double zx, double zy, double zz,
+ double xx, double xy, double xz)
+{
+ Ifc2x3::IfcLocalPlacement* lp = new Ifc2x3::IfcLocalPlacement(0,
+ addPlacement3d(ox, oy, oz, zx, zy, zz, xx, xy, xz));
+
+ AddEntity(lp);
+ return lp;
+}
+
+Ifc2x3::IfcOwnerHistory* IfcHierarchyHelper::addOwnerHistory() {
+ Ifc2x3::IfcPerson* person = new Ifc2x3::IfcPerson(boost::none, boost::none, std::string(""),
+ boost::none, boost::none, boost::none, boost::none, boost::none);
+
+ Ifc2x3::IfcOrganization* organization = new Ifc2x3::IfcOrganization(boost::none,
+ "IfcOpenShell", boost::none, boost::none, boost::none);
+
+ Ifc2x3::IfcPersonAndOrganization* person_and_org = new Ifc2x3::IfcPersonAndOrganization(person, organization, boost::none);
+ Ifc2x3::IfcApplication* application = new Ifc2x3::IfcApplication(organization,
+ IFCOPENSHELL_VERSION, "IfcOpenShell", "IfcOpenShell");
+
+ int timestamp = (int) time(0);
+ Ifc2x3::IfcOwnerHistory* owner_hist = new Ifc2x3::IfcOwnerHistory(person_and_org, application,
+ boost::none, Ifc2x3::IfcChangeActionEnum::IfcChangeAction_ADDED, boost::none, person_and_org, application, timestamp);
+
+ AddEntity(person);
+ AddEntity(organization);
+ AddEntity(person_and_org);
+ AddEntity(application);
+ AddEntity(owner_hist);
+
+ return owner_hist;
+}
+
+Ifc2x3::IfcProject* IfcHierarchyHelper::addProject(Ifc2x3::IfcOwnerHistory* owner_hist) {
+ Ifc2x3::IfcRepresentationContext::list rep_contexts (new IfcTemplatedEntityList());
+ Ifc2x3::IfcGeometricRepresentationContext* rep_context = new Ifc2x3::IfcGeometricRepresentationContext(
+ std::string("Plan"), std::string("Model"), 3, 1e-5, addPlacement3d(), addTriplet(0, 1, 0));
+
+ rep_contexts->push(rep_context);
+
+ IfcEntities units (new IfcEntityList());
+ Ifc2x3::IfcDimensionalExponents* dimexp = new Ifc2x3::IfcDimensionalExponents(0, 0, 0, 0, 0, 0, 0);
+ Ifc2x3::IfcSIUnit* unit1 = new Ifc2x3::IfcSIUnit(dimexp, Ifc2x3::IfcUnitEnum::IfcUnit_LENGTHUNIT,
+ Ifc2x3::IfcSIPrefix::IfcSIPrefix_MILLI, Ifc2x3::IfcSIUnitName::IfcSIUnitName_METRE);
+ Ifc2x3::IfcSIUnit* unit2a = new Ifc2x3::IfcSIUnit(dimexp, Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT,
+ boost::none, Ifc2x3::IfcSIUnitName::IfcSIUnitName_RADIAN);
+ Ifc2x3::IfcMeasureWithUnit* unit2b = new Ifc2x3::IfcMeasureWithUnit(
+ new IfcWrite::IfcSelectHelper(0.017453293, Ifc2x3::Type::IfcPlaneAngleMeasure), unit2a);
+ Ifc2x3::IfcConversionBasedUnit* unit2 = new Ifc2x3::IfcConversionBasedUnit(dimexp,
+ Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT, "Degrees", unit2b);
+
+ units->push(unit1);
+ units->push(unit2);
+
+ Ifc2x3::IfcUnitAssignment* unit_assignment = new Ifc2x3::IfcUnitAssignment(units);
+
+ Ifc2x3::IfcProject* project = new Ifc2x3::IfcProject(IfcWrite::IfcGuidHelper(), owner_hist, boost::none, boost::none,
+ boost::none, boost::none, boost::none, rep_contexts, unit_assignment);
+
+ AddEntity(rep_context);
+ AddEntity(dimexp);
+ AddEntity(unit1);
+ AddEntity(unit2a);
+ AddEntity(unit2b);
+ AddEntity(unit2);
+ AddEntity(unit_assignment);
+ AddEntity(project);
+
+ return project;
+}
+
+void IfcHierarchyHelper::relatePlacements(Ifc2x3::IfcProduct* parent, Ifc2x3::IfcProduct* product) {
+ Ifc2x3::IfcObjectPlacement* place = product->hasObjectPlacement() ? product->ObjectPlacement() : 0;
+ if (place && place->is(Ifc2x3::Type::IfcLocalPlacement)) {
+ Ifc2x3::IfcLocalPlacement* local_place = (Ifc2x3::IfcLocalPlacement*) place;
+ if (parent->hasObjectPlacement()) {
+ local_place->setPlacementRelTo(parent->ObjectPlacement());
+ }
+ }
+}
+
+Ifc2x3::IfcSite* IfcHierarchyHelper::addSite(Ifc2x3::IfcProject* proj, Ifc2x3::IfcOwnerHistory* owner_hist) {
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ if (! proj) {
+ proj = getSingle();
+ }
+ if (! proj) {
+ proj = addProject(owner_hist);
+ }
+
+ Ifc2x3::IfcSite* site = new Ifc2x3::IfcSite(IfcWrite::IfcGuidHelper(), owner_hist, boost::none,
+ boost::none, boost::none, addLocalPlacement(), 0, boost::none,
+ Ifc2x3::IfcElementCompositionEnum::IfcElementComposition_ELEMENT,
+ boost::none, boost::none, boost::none, boost::none, 0);
+
+ AddEntity(site);
+ addRelatedObject(proj, site);
+ return site;
+}
+
+Ifc2x3::IfcBuilding* IfcHierarchyHelper::addBuilding(Ifc2x3::IfcSite* site, Ifc2x3::IfcOwnerHistory* owner_hist) {
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ if (! site) {
+ site = getSingle();
+ }
+ if (! site) {
+ site = addSite(0, owner_hist);
+ }
+ Ifc2x3::IfcBuilding* building = new Ifc2x3::IfcBuilding(IfcWrite::IfcGuidHelper(), owner_hist, boost::none, boost::none, boost::none,
+ addLocalPlacement(), 0, boost::none, Ifc2x3::IfcElementCompositionEnum::IfcElementComposition_ELEMENT,
+ boost::none, boost::none, 0);
+
+ AddEntity(building);
+ addRelatedObject(site, building);
+ relatePlacements(site, building);
+
+ return building;
+}
+
+Ifc2x3::IfcBuildingStorey* IfcHierarchyHelper::addBuildingStorey(Ifc2x3::IfcBuilding* building,
+ Ifc2x3::IfcOwnerHistory* owner_hist)
+{
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ if (! building) {
+ building = getSingle();
+ }
+ if (! building) {
+ building = addBuilding(0, owner_hist);
+ }
+ Ifc2x3::IfcBuildingStorey* storey = new Ifc2x3::IfcBuildingStorey(IfcWrite::IfcGuidHelper(),
+ owner_hist, boost::none, boost::none, boost::none, addLocalPlacement(), 0, boost::none,
+ Ifc2x3::IfcElementCompositionEnum::IfcElementComposition_ELEMENT, boost::none);
+
+ AddEntity(storey);
+ addRelatedObject(building, storey);
+ relatePlacements(building, storey);
+
+ return storey;
+}
+
+Ifc2x3::IfcBuildingStorey* IfcHierarchyHelper::addBuildingProduct(Ifc2x3::IfcProduct* product,
+ Ifc2x3::IfcBuildingStorey* storey, Ifc2x3::IfcOwnerHistory* owner_hist)
+{
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ if (! storey) {
+ storey = getSingle();
+ }
+ if (! storey) {
+ storey = addBuildingStorey(0, owner_hist);
+ }
+ AddEntity(product);
+ addRelatedObject(storey, product);
+ relatePlacements(storey, product);
+ return storey;
+}
+
+void IfcHierarchyHelper::addExtrudedPolyline(Ifc2x3::IfcShapeRepresentation* rep, const std::vector >& points, double h,
+ Ifc2x3::IfcAxis2Placement2D* place, Ifc2x3::IfcAxis2Placement3D* place2,
+ Ifc2x3::IfcDirection* dir, Ifc2x3::IfcRepresentationContext* context)
+{
+ Ifc2x3::IfcCartesianPoint::list cartesian_points (new IfcTemplatedEntityList());
+ for (std::vector >::const_iterator i = points.begin(); i != points.end(); ++i) {
+ cartesian_points->push(addDoublet(i->first, i->second));
+ }
+ if (cartesian_points->Size()) cartesian_points->push(*cartesian_points->begin());
+ Ifc2x3::IfcPolyline* line = new Ifc2x3::IfcPolyline(cartesian_points);
+ Ifc2x3::IfcArbitraryClosedProfileDef* profile = new Ifc2x3::IfcArbitraryClosedProfileDef(
+ Ifc2x3::IfcProfileTypeEnum::IfcProfileType_AREA, boost::none, line);
+
+ Ifc2x3::IfcExtrudedAreaSolid* solid = new Ifc2x3::IfcExtrudedAreaSolid(
+ profile, place2 ? place2 : addPlacement3d(), dir ? dir : addTriplet(0, 0, 1), h);
+
+ Ifc2x3::IfcRepresentationItem::list items = rep->Items();
+ items->push(solid);
+ rep->setItems(items);
+
+ AddEntity(line);
+ AddEntity(profile);
+ AddEntity(solid);
+}
+
+Ifc2x3::IfcProductDefinitionShape* IfcHierarchyHelper::addExtrudedPolyline(const std::vector >& points, double h,
+ Ifc2x3::IfcAxis2Placement2D* place, Ifc2x3::IfcAxis2Placement3D* place2, Ifc2x3::IfcDirection* dir,
+ Ifc2x3::IfcRepresentationContext* context)
+{
+ Ifc2x3::IfcRepresentation::list reps (new IfcTemplatedEntityList());
+ Ifc2x3::IfcRepresentationItem::list items (new IfcTemplatedEntityList());
+ Ifc2x3::IfcShapeRepresentation* rep = new Ifc2x3::IfcShapeRepresentation(context
+ ? context
+ : getSingle(), std::string("Body"), std::string("SweptSolid"), items);
+ reps->push(rep);
+ Ifc2x3::IfcProductDefinitionShape* shape = new Ifc2x3::IfcProductDefinitionShape(0, 0, reps);
+ AddEntity(rep);
+ AddEntity(shape);
+ addExtrudedPolyline(rep, points, h, place, place2, dir, context);
+
+ return shape;
+}
+
+void IfcHierarchyHelper::addBox(Ifc2x3::IfcShapeRepresentation* rep, double w, double d, double h,
+ Ifc2x3::IfcAxis2Placement2D* place, Ifc2x3::IfcAxis2Placement3D* place2,
+ Ifc2x3::IfcDirection* dir, Ifc2x3::IfcRepresentationContext* context)
+{
+ if (false) {
+ Ifc2x3::IfcRectangleProfileDef* profile = new Ifc2x3::IfcRectangleProfileDef(
+ Ifc2x3::IfcProfileTypeEnum::IfcProfileType_AREA, 0, place ? place : addPlacement2d(), w, d);
+ Ifc2x3::IfcExtrudedAreaSolid* solid = new Ifc2x3::IfcExtrudedAreaSolid(profile,
+ place2 ? place2 : addPlacement3d(), dir ? dir : addTriplet(0, 0, 1), h);
+
+ AddEntity(profile);
+ AddEntity(solid);
+ Ifc2x3::IfcRepresentationItem::list items = rep->Items();
+ items->push(solid);
+ rep->setItems(items);
+ } else {
+ std::vector > points;
+ points.push_back(std::pair(-w/2, -d/2));
+ points.push_back(std::pair(w/2, -d/2));
+ points.push_back(std::pair(w/2, d/2));
+ points.push_back(std::pair(-w/2, d/2));
+ points.push_back(*points.begin());
+ addExtrudedPolyline(rep, points, h, place, place2, dir, context);
+ }
+}
+
+Ifc2x3::IfcProductDefinitionShape* IfcHierarchyHelper::addBox(double w, double d, double h, Ifc2x3::IfcAxis2Placement2D* place,
+ Ifc2x3::IfcAxis2Placement3D* place2, Ifc2x3::IfcDirection* dir, Ifc2x3::IfcRepresentationContext* context)
+{
+ Ifc2x3::IfcRepresentation::list reps (new IfcTemplatedEntityList());
+ Ifc2x3::IfcRepresentationItem::list items (new IfcTemplatedEntityList());
+ Ifc2x3::IfcShapeRepresentation* rep = new Ifc2x3::IfcShapeRepresentation(
+ context ? context : getSingle(), std::string("Body"), std::string("SweptSolid"), items);
+ reps->push(rep);
+ Ifc2x3::IfcProductDefinitionShape* shape = new Ifc2x3::IfcProductDefinitionShape(0, 0, reps);
+ AddEntity(rep);
+ AddEntity(shape);
+ addBox(rep, w, d, h, place, place2, dir, context);
+ return shape;
+}
+
+void IfcHierarchyHelper::clipRepresentation(Ifc2x3::IfcProductRepresentation* shape,
+ Ifc2x3::IfcAxis2Placement3D* place, bool agree)
+{
+ Ifc2x3::IfcPlane* plane = new Ifc2x3::IfcPlane(place);
+ Ifc2x3::IfcHalfSpaceSolid* half_space = new Ifc2x3::IfcHalfSpaceSolid(plane, agree);
+ Ifc2x3::IfcRepresentation::list reps = shape->Representations();
+ for (Ifc2x3::IfcRepresentation::it j = reps->begin(); j != reps->end(); ++j) {
+ Ifc2x3::IfcRepresentation* rep = *j;
+ if (rep->RepresentationIdentifier() != "Body") continue;
+ rep->setRepresentationType("Clipping");
+ Ifc2x3::IfcRepresentationItem::list items = rep->Items();
+ Ifc2x3::IfcRepresentationItem::list new_items (new IfcTemplatedEntityList());
+ AddEntity(plane);
+ AddEntity(half_space);
+ for (Ifc2x3::IfcRepresentationItem::it i = items->begin(); i != items->end(); ++i) {
+ Ifc2x3::IfcRepresentationItem* item = *i;
+ Ifc2x3::IfcBooleanClippingResult* clip = new Ifc2x3::IfcBooleanClippingResult(
+ Ifc2x3::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE, item, half_space);
+ AddEntity(clip);
+ new_items->push(clip);
+ }
+ rep->setItems(new_items);
+ }
+}
+
+Ifc2x3::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour(
+ Ifc2x3::IfcProductRepresentation* shape, double r, double g, double b, double a)
+{
+ Ifc2x3::IfcColourRgb* colour = new Ifc2x3::IfcColourRgb(boost::none, r, g, b);
+ Ifc2x3::IfcSurfaceStyleRendering* rendering = a == 1.0
+ ? new Ifc2x3::IfcSurfaceStyleRendering(colour, boost::none, boost::none, boost::none, boost::none, boost::none,
+ boost::none, boost::none, Ifc2x3::IfcReflectanceMethodEnum::IfcReflectanceMethod_FLAT)
+ : new Ifc2x3::IfcSurfaceStyleRendering(colour, 1.0-a, boost::none, boost::none, boost::none, boost::none,
+ boost::none, boost::none, Ifc2x3::IfcReflectanceMethodEnum::IfcReflectanceMethod_FLAT);
+
+ IfcEntities styles(new IfcEntityList());
+ styles->push(rendering);
+ Ifc2x3::IfcSurfaceStyle* surface_style = new Ifc2x3::IfcSurfaceStyle(
+ boost::none, Ifc2x3::IfcSurfaceSide::IfcSurfaceSide_BOTH, styles);
+ IfcEntities surface_styles(new IfcEntityList());
+ surface_styles->push(surface_style);
+ Ifc2x3::IfcPresentationStyleAssignment* style_assignment =
+ new Ifc2x3::IfcPresentationStyleAssignment(surface_styles);
+ AddEntity(colour);
+ AddEntity(rendering);
+ AddEntity(surface_style);
+ AddEntity(style_assignment);
+ setSurfaceColour(shape, style_assignment);
+ return style_assignment;
+}
+
+void IfcHierarchyHelper::setSurfaceColour(Ifc2x3::IfcProductRepresentation* shape,
+ Ifc2x3::IfcPresentationStyleAssignment* style_assignment)
+{
+ Ifc2x3::IfcPresentationStyleAssignment::list style_assignments (new IfcTemplatedEntityList());
+ style_assignments->push(style_assignment);
+ Ifc2x3::IfcRepresentation::list reps = shape->Representations();
+ for (Ifc2x3::IfcRepresentation::it j = reps->begin(); j != reps->end(); ++j) {
+ Ifc2x3::IfcRepresentation* rep = *j;
+ if (rep->RepresentationIdentifier() != "Body" && rep->RepresentationIdentifier() != "Facetation") continue;
+ Ifc2x3::IfcRepresentationItem::list items = rep->Items();
+ for (Ifc2x3::IfcRepresentationItem::it i = items->begin(); i != items->end(); ++i) {
+ Ifc2x3::IfcRepresentationItem* item = *i;
+ Ifc2x3::IfcStyledItem* styled_item = new Ifc2x3::IfcStyledItem(item, style_assignments, boost::none);
+ AddEntity(styled_item);
+ }
+ }
+}
diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h
new file mode 100644
index 0000000000..9c70147e97
--- /dev/null
+++ b/src/ifcparse/IfcHierarchyHelper.h
@@ -0,0 +1,171 @@
+/********************************************************************************
+ * *
+ * 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 . *
+ * *
+ ********************************************************************************/
+
+/********************************************************************************
+ * *
+ * This class is a subclass of the regular IfcFile class that implements *
+ * several convenience functions for creating geometrical representations and *
+ * spatial containers. *
+ * *
+ ********************************************************************************/
+
+#ifndef IFCHIERARCHYHELPER_H
+#define IFCHIERARCHYHELPER_H
+
+#include "../ifcparse/Ifc2x3.h"
+#include "../ifcparse/IfcFile.h"
+#include "../ifcparse/IfcWrite.h"
+
+class IfcHierarchyHelper : public IfcParse::IfcFile {
+public:
+ template
+ T* addTriplet(double x, double y, double z) {
+ std::vector a; a.push_back(x); a.push_back(y); a.push_back(z);
+ T* t = new T(a);
+ AddEntity(t);
+ return t;
+ }
+
+ template
+ T* addDoublet(double x, double y) {
+ std::vector a; a.push_back(x); a.push_back(y);
+ T* t = new T(a);
+ AddEntity(t);
+ return t;
+ }
+
+ template
+ T* getSingle() {
+ typename T::list ts = EntitiesByType();
+ if (ts->Size() != 1) return 0;
+ return *ts->begin();
+ }
+
+ Ifc2x3::IfcAxis2Placement3D* addPlacement3d(double ox=0.0, double oy=0.0, double oz=0.0,
+ double zx=0.0, double zy=0.0, double zz=1.0,
+ double xx=1.0, double xy=0.0, double xz=0.0);
+
+ Ifc2x3::IfcAxis2Placement2D* addPlacement2d(double ox=0.0, double oy=0.0,
+ double xx=1.0, double xy=0.0);
+
+ Ifc2x3::IfcLocalPlacement* addLocalPlacement(double ox=0.0, double oy=0.0, double oz=0.0,
+ double zx=0.0, double zy=0.0, double zz=1.0,
+ double xx=1.0, double xy=0.0, double xz=0.0);
+
+ template
+ void addRelatedObject(Ifc2x3::IfcObjectDefinition* related_object,
+ Ifc2x3::IfcObjectDefinition* relating_object, Ifc2x3::IfcOwnerHistory* owner_hist = 0)
+ {
+ typename T::list li = EntitiesByType();
+ bool found = false;
+ for (typename T::it i = li->begin(); i != li->end(); ++i) {
+ T* rel = *i;
+ if (rel->RelatingObject() == relating_object) {
+ Ifc2x3::IfcObjectDefinition::list products = rel->RelatedObjects();
+ products->push(related_object);
+ rel->setRelatedObjects(products);
+ found = true;
+ break;
+ }
+ }
+ if (! found) {
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ Ifc2x3::IfcObjectDefinition::list relating_objects (new IfcTemplatedEntityList());
+ relating_objects->push(relating_object);
+ T* t = new T(IfcWrite::IfcGuidHelper(), owner_hist, boost::none, boost::none, related_object, relating_objects);
+ AddEntity(t);
+ }
+ }
+
+ Ifc2x3::IfcOwnerHistory* addOwnerHistory();
+ Ifc2x3::IfcProject* addProject(Ifc2x3::IfcOwnerHistory* owner_hist = 0);
+ void relatePlacements(Ifc2x3::IfcProduct* parent, Ifc2x3::IfcProduct* product);
+ Ifc2x3::IfcSite* addSite(Ifc2x3::IfcProject* proj = 0, Ifc2x3::IfcOwnerHistory* owner_hist = 0);
+ Ifc2x3::IfcBuilding* addBuilding(Ifc2x3::IfcSite* site = 0, Ifc2x3::IfcOwnerHistory* owner_hist = 0);
+
+ Ifc2x3::IfcBuildingStorey* addBuildingStorey(Ifc2x3::IfcBuilding* building = 0,
+ Ifc2x3::IfcOwnerHistory* owner_hist = 0);
+
+ Ifc2x3::IfcBuildingStorey* addBuildingProduct(Ifc2x3::IfcProduct* product,
+ Ifc2x3::IfcBuildingStorey* storey = 0, Ifc2x3::IfcOwnerHistory* owner_hist = 0);
+
+ void addExtrudedPolyline(Ifc2x3::IfcShapeRepresentation* rep, const std::vector >& points, double h,
+ Ifc2x3::IfcAxis2Placement2D* place=0, Ifc2x3::IfcAxis2Placement3D* place2=0,
+ Ifc2x3::IfcDirection* dir=0, Ifc2x3::IfcRepresentationContext* context=0);
+
+ Ifc2x3::IfcProductDefinitionShape* addExtrudedPolyline(const std::vector >& points, double h,
+ Ifc2x3::IfcAxis2Placement2D* place=0, Ifc2x3::IfcAxis2Placement3D* place2=0, Ifc2x3::IfcDirection* dir=0,
+ Ifc2x3::IfcRepresentationContext* context=0);
+
+ void addBox(Ifc2x3::IfcShapeRepresentation* rep, double w, double d, double h,
+ Ifc2x3::IfcAxis2Placement2D* place=0, Ifc2x3::IfcAxis2Placement3D* place2=0,
+ Ifc2x3::IfcDirection* dir=0, Ifc2x3::IfcRepresentationContext* context=0);
+
+ Ifc2x3::IfcProductDefinitionShape* addBox(double w, double d, double h, Ifc2x3::IfcAxis2Placement2D* place=0,
+ Ifc2x3::IfcAxis2Placement3D* place2=0, Ifc2x3::IfcDirection* dir=0, Ifc2x3::IfcRepresentationContext* context=0);
+
+ void clipRepresentation(Ifc2x3::IfcProductRepresentation* shape,
+ Ifc2x3::IfcAxis2Placement3D* place, bool agree);
+
+ Ifc2x3::IfcPresentationStyleAssignment* setSurfaceColour(Ifc2x3::IfcProductRepresentation* shape,
+ double r, double g, double b, double a=1.0);
+
+ void setSurfaceColour(Ifc2x3::IfcProductRepresentation* shape,
+ Ifc2x3::IfcPresentationStyleAssignment* style_assignment);
+
+};
+
+template <>
+inline void IfcHierarchyHelper::addRelatedObject (Ifc2x3::IfcObjectDefinition* related_object,
+ Ifc2x3::IfcObjectDefinition* relating_object, Ifc2x3::IfcOwnerHistory* owner_hist)
+{
+ Ifc2x3::IfcRelContainedInSpatialStructure::list li = EntitiesByType();
+ bool found = false;
+ for (Ifc2x3::IfcRelContainedInSpatialStructure::it i = li->begin(); i != li->end(); ++i) {
+ Ifc2x3::IfcRelContainedInSpatialStructure* rel = *i;
+ if (rel->RelatingStructure() == relating_object) {
+ Ifc2x3::IfcProduct::list products = rel->RelatedElements();
+ products->push((Ifc2x3::IfcProduct*)related_object);
+ rel->setRelatedElements(products);
+ found = true;
+ break;
+ }
+ }
+ if (! found) {
+ if (! owner_hist) {
+ owner_hist = getSingle();
+ }
+ if (! owner_hist) {
+ owner_hist = addOwnerHistory();
+ }
+ Ifc2x3::IfcProduct::list relating_objects (new IfcTemplatedEntityList());
+ relating_objects->push((Ifc2x3::IfcProduct*)relating_object);
+ Ifc2x3::IfcRelContainedInSpatialStructure* t = new Ifc2x3::IfcRelContainedInSpatialStructure(IfcWrite::IfcGuidHelper(), owner_hist,
+ boost::none, boost::none, relating_objects, (Ifc2x3::IfcSpatialStructureElement*)related_object);
+
+ AddEntity(t);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h
index 70b3785b4c..21451fb058 100644
--- a/src/ifcparse/IfcUtil.h
+++ b/src/ifcparse/IfcUtil.h
@@ -74,6 +74,9 @@ typedef IfcBaseClass* IfcSchemaEntity;
}
+template
+class IfcTemplatedEntityList;
+
class IfcEntityList {
std::vector ls;
public:
@@ -86,6 +89,12 @@ public:
it end();
IfcUtil::IfcSchemaEntity operator[] (int i);
int Size() const;
+ template
+ typename U::list as() {
+ typename U::list r(new IfcTemplatedEntityList());
+ for ( it i = begin(); i != end(); ++ i ) if ((*i)->is(U::Class())) r->push((U*)*i);
+ return r;
+ }
};
template
@@ -104,6 +113,12 @@ public:
for ( it i = begin(); i != end(); ++ i ) r->push(*i);
return r;
}
+ template
+ typename U::list as() {
+ typename U::list r(new IfcTemplatedEntityList());
+ for ( it i = begin(); i != end(); ++ i ) if ((*i)->is(U::Class())) r->push(*i);
+ return r;
+ }
};
namespace IfcUtil {
diff --git a/src/ifcparse/IfcWritableEntity.h b/src/ifcparse/IfcWritableEntity.h
index ed919df508..b43eb798fa 100644
--- a/src/ifcparse/IfcWritableEntity.h
+++ b/src/ifcparse/IfcWritableEntity.h
@@ -31,6 +31,8 @@
#ifndef IFCWRITABLEENTITY_H
#define IFCWRITABLEENTITY_H
+#include