diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index 13921a682d..797c29a202 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -83,17 +83,23 @@ int main(int argc, char** argv) { // 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. - IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addBox(10000, 360, 3000); + // The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting + // product definition will consist of both a body representation as well as an axis representation + // that runs over the centerline of the box in the X-axis. + IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addAxisBox(10000, 360, 3000); + + // Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy + // of placements for the products + IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle()->ObjectPlacement(); // 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()); + south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement)); // A pale white colour is assigned to the wall. IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour( - south_wall->Representation(), 0.75, 0.73, 0.68); + south_wall_shape, 0.75, 0.73, 0.68); // Now create a footing for the wall to rest on. IfcSchema::IfcFooting* footing = new IfcSchema::IfcFooting(guid(), file.getSingle(), @@ -104,18 +110,19 @@ int main(int argc, char** argv) { // 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)); + footing->setRepresentation(file.addBox(10100, 5460, 2000)); + footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000)); // The footing will have a dark gray colour IfcSchema::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 + + // An opening element is created with rectangular geometry: IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle(), - null, null, null, file.addLocalPlacement(-2500, 0, 400), - file.addBox(6000, 3630, 1600, 0, 0, 0, file.getSingle()), null + null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400), + file.addBox(6000, 3630, 1600), null #ifdef USE_IFC4 , IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING #endif @@ -129,8 +136,8 @@ int main(int argc, char** argv) { // Now create an additional opening IfcSchema::IfcOpeningElement* south_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle(), - null, null, null, file.addLocalPlacement(3000, 0, 400), - file.addBox(1860, 3000, 1600, 0, 0, 0, file.getSingle()), null + null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400), + file.addBox(1860, 3000, 1600), null #ifdef USE_IFC4 , IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING #endif @@ -138,69 +145,104 @@ int main(int argc, char** argv) { file.AddEntity(south_opening); file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle(), null, null, south_wall, south_opening)); - // Create a roof element - IfcSchema::IfcRoof* south_roof = new IfcSchema::IfcRoof(guid(), file.getSingle(), S("South roof"), null, null, - 0, 0, null, IfcSchema::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); + // Create a roof element that will consist of two slabs: + IfcSchema::IfcRoof* roof = new IfcSchema::IfcRoof(guid(), file.getSingle(), S("Roof"), null, null, + file.addLocalPlacement(storey_placement), 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF); + // The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion + IfcSchema::IfcShapeRepresentation* roof_rep = file.addEmptyRepresentation(); + file.addBox(roof_rep, 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))); + + // CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry + IfcSchema::IfcSlab* south_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle(), S("South roof"), + null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF); + + // The geometry is instantiated by using IfcMappedItems. This way geometry definitions can + // be reused while maintaining the cardinality constraint that the ShapeOfProduct relation + // imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4. + south_roof_part->setRepresentation(file.addMappedItem(roof_rep)); + south_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, -400, 2700)); + // 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 - IfcSchema::IfcRoof* north_roof = new IfcSchema::IfcRoof(guid(), file.getSingle(), S("North roof"), - null, null, 0, 0, null, IfcSchema::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); + IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle(), S("North roof"), + null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF); + north_roof_part->setOwnerHistory(file.getSingle()); + north_roof_part->setRepresentation(file.addMappedItem(roof_rep)); + north_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0)); + + IfcSchema::IfcObjectDefinition::list::ptr roof_parts(new IfcSchema::IfcObjectDefinition::list); + roof_parts->push(south_roof_part); + roof_parts->push(north_roof_part); + IfcSchema::IfcRelDecomposes* roof_decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle(), + null, null, roof, roof_parts); + file.AddEntity(roof_decomposition); - // 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); + file.addBuildingProduct(south_roof_part); + file.addBuildingProduct(north_roof_part); + file.addBuildingProduct(roof); + + file.setSurfaceColour(roof_rep, 0.24, 0.08, 0.04); // Copy the south wall to the north - file.addBuildingProduct(new IfcSchema::IfcWallStandardCase(guid(), file.getSingle(), S("North wall"), - null, null, file.addLocalPlacement(0, 5000, 0), south_wall->Representation(), null + IfcSchema::IfcWallStandardCase* north_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle(), S("North wall"), + null, null, file.addLocalPlacement(storey_placement, 0, 5000, 0), file.addAxisBox(10000, 360, 3000), null #ifdef USE_IFC4 , IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD #endif - )); + ); + file.addBuildingProduct(north_wall); + file.setSurfaceColour(north_wall->Representation(), wall_colour); + + IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation(); + file.addBox(clipped_wall_body_rep, 5000, 360, 6000); + // 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(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false); + file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false); // Now create a wall on the east of the building, again starting with just a box shape IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::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 + S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null #ifdef USE_IFC4 , IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD #endif ); 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); + file.setSurfaceColour(clipped_wall_body_rep, wall_colour); // The east wall is copied to the west location of the house IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle(), - S("West wall"), null, null, file.addLocalPlacement(-4820, 2500, 0, 0, 0, 1, 0, -1, 0), east_wall->Representation(), null + S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null #ifdef USE_IFC4 , IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD #endif ); file.addBuildingProduct(west_wall); + for (int i = 0; i < 2; ++i) { + // CV-2x3-161: MappedItems are not allowed for Axis representations + IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall; + IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D"); + file.addAxis(wall_axis_rep, 5000); + IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations(); + reps->push(wall_axis_rep); + wall->Representation()->setRepresentations(reps); + } + // 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. // NB: an Opening Element can only be used to create a single void within a single Element, as per: // http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm + + // Not all viewers support opening elements with mapped representations, hence an exact copy of the + // same subtraction box is instantiated for the otherwise identical opening element. IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle(), - null, null, null, west_opening->ObjectPlacement(), west_opening->Representation(), null + null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0), + file.addBox(6000, 3630, 1600), null #ifdef USE_IFC4 , IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING #endif @@ -219,7 +261,7 @@ int main(int argc, char** argv) { file.AddEntities(geometrical_entities); IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as(); for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) { - (*it)->setContextOfItems(file.getSingle()); + (*it)->setContextOfItems(file.getRepresentationContext("Model")); } file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05); @@ -293,7 +335,7 @@ int main(int argc, char** argv) { stair_points.push_back(XY(500, 400)); stair_points.push_back(XY( 0, 400)); IfcSchema::IfcStairFlight* stair = new IfcSchema::IfcStairFlight(guid(), file.getSingle(), - null, null, null, file.addLocalPlacement(5050, 1000, 0, 0, 1, 0, 1, 0, 0), + null, null, null, file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0), file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25 #ifdef USE_IFC4 , IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT @@ -304,7 +346,7 @@ int main(int argc, char** argv) { file.setSurfaceColour(stair->Representation(), footing_colour); IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle(), - null, null, null, file.addLocalPlacement(5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null + null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null #ifdef USE_IFC4 , IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING #endif @@ -316,7 +358,7 @@ int main(int argc, char** argv) { // can be a composition of multiple solids. The following door will be composed of four boxes // which constitute the door and its frame. IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle(), null, null, null, - file.addLocalPlacement(4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000 + file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000 #ifdef USE_IFC4 , IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR , IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT @@ -350,30 +392,37 @@ int main(int argc, char** argv) { // Therefore the OverallWidth and OverallHeight of the window attributes will need to // match the bounding box of the representation. Furthermore, the window placement needs // to align with the lowerleft corner of the constituent parts. - IfcSchema::IfcProductDefinitionShape::list::ptr 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 + IfcSchema::IfcShapeRepresentation::list::ptr frame_representations(new IfcSchema::IfcShapeRepresentation::list); + + IfcSchema::IfcShapeRepresentation* horizontal_bar = file.addEmptyRepresentation(); + IfcSchema::IfcShapeRepresentation* vertical_bar = file.addEmptyRepresentation(); + file.addBox(horizontal_bar, 1860, 90, 90); + file.addBox(vertical_bar, 90, 90, 1420); + + frame_representations->push(horizontal_bar); + frame_representations->push(horizontal_bar); // Add another reference to the horizontal bar created above + frame_representations->push(vertical_bar); + frame_representations->push(vertical_bar); // Add another reference to the vertical bar created above // The beams all have the same surface style assigned IfcSchema::IfcPresentationStyleAssignment* frame_style = 0; - for (IfcSchema::IfcProductDefinitionShape::list::it i = frame_representations->begin(); i != frame_representations->end(); ++i) { + for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) { if (frame_style) { file.setSurfaceColour(*i, frame_style); } else { frame_style = file.setSurfaceColour(*i, 0.5, 0.4, 0.3); } + // Because of the duplication the iterator is incremented twice } // 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. - IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcTemplatedEntityList()); - window_placements->push(file.addLocalPlacement(2*-1770-430-930, -45, 400)); - window_placements->push(file.addLocalPlacement( -1770-430-930, -45, 400)); - window_placements->push(file.addLocalPlacement( -430-930, -45, 400)); - window_placements->push(file.addLocalPlacement( 3000-930, -45, 400)); - window_placements->push(file.addLocalPlacement( -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0)); + IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcSchema::IfcLocalPlacement::list); + window_placements->push(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400)); + window_placements->push(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400)); + window_placements->push(file.addLocalPlacement(storey_placement, -430-930, -45, 400)); + window_placements->push(file.addLocalPlacement(storey_placement, 3000-930, -45, 400)); + window_placements->push(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0)); for (IfcSchema::IfcLocalPlacement::list::it it = window_placements->begin(); it != window_placements->end(); ++it) { @@ -395,20 +444,20 @@ int main(int argc, char** argv) { // The placements for the beams are not shared accross the different windows because every // beam is placed relative to its parent window entity. IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList()); - frame_placements->push(file.addLocalPlacement( 930,45)); - frame_placements->push(file.addLocalPlacement( 930, 45, 1510)); - frame_placements->push(file.addLocalPlacement(-885+930, 45, 90)); - frame_placements->push(file.addLocalPlacement( 885+930, 45, 90)); + frame_placements->push(file.addLocalPlacement(storey_placement, 930,45)); + frame_placements->push(file.addLocalPlacement(storey_placement, 930, 45, 1510)); + frame_placements->push(file.addLocalPlacement(storey_placement, -885+930, 45, 90)); + frame_placements->push(file.addLocalPlacement(storey_placement, 885+930, 45, 90)); // Now iterate over the placements and representations of the beam and add them to list of parts IfcSchema::IfcLocalPlacement::list::it frame_placement; - IfcSchema::IfcProductDefinitionShape::list::it frame_representation; + IfcSchema::IfcShapeRepresentation::list::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) { IfcSchema::IfcMember* frame_part = new IfcSchema::IfcMember(guid(), file.getSingle(), - null, null, null, *frame_placement, *frame_representation, null + null, null, null, *frame_placement, file.addMappedItem(*frame_representation), null #ifdef USE_IFC4 , IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION #endif @@ -420,7 +469,7 @@ int main(int argc, char** argv) { // Add the glass plate to the list of parts IfcSchema::IfcPlate* glass_part = new IfcSchema::IfcPlate(guid(), file.getSingle(), null, - null, null, file.addLocalPlacement(930, 45, 90), file.addBox(1680, 10, 1420), null + null, null, file.addLocalPlacement(storey_placement, 930, 45, 90), file.addBox(1680, 10, 1420), null #ifdef USE_IFC4 , IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET #endif @@ -479,6 +528,6 @@ void createGroundShape(TopoDS_Shape& shape) { #if OCC_VERSION_HEX < 0x60502 shape = BRepBuilderAPI_MakeFace(surf); #else - shape = BRepBuilderAPI_MakeFace(surf, 1); + shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion()); #endif } diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index 45e5beec3b..c945a57f24 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -657,7 +657,7 @@ void IfcGeomObjects::InitUnits() { } } catch (const IfcParse::IfcException&) {} - if (!units) { + if (!units || !units->Size()) { // No units eh... Since tolerances and deflection are specified internally in meters // we will try to find another indication of the model size. IfcSchema::IfcExtrudedAreaSolid::list::ptr extrusions = ifc_file->EntitiesByType(); diff --git a/src/ifcparse/IfcHierarchyHelper.cpp b/src/ifcparse/IfcHierarchyHelper.cpp index 45f26ed424..c10f6817a8 100644 --- a/src/ifcparse/IfcHierarchyHelper.cpp +++ b/src/ifcparse/IfcHierarchyHelper.cpp @@ -53,12 +53,12 @@ IfcSchema::IfcAxis2Placement2D* IfcHierarchyHelper::addPlacement2d( return p2d; } -IfcSchema::IfcLocalPlacement* IfcHierarchyHelper::addLocalPlacement( +IfcSchema::IfcLocalPlacement* IfcHierarchyHelper::addLocalPlacement(IfcSchema::IfcObjectPlacement* parent, double ox, double oy, double oz, double zx, double zy, double zz, double xx, double xy, double xz) { - IfcSchema::IfcLocalPlacement* lp = new IfcSchema::IfcLocalPlacement(0, + IfcSchema::IfcLocalPlacement* lp = new IfcSchema::IfcLocalPlacement(parent, addPlacement3d(ox, oy, oz, zx, zy, zz, xx, xy, xz)); AddEntity(lp); @@ -78,7 +78,7 @@ IfcSchema::IfcOwnerHistory* IfcHierarchyHelper::addOwnerHistory() { int timestamp = (int) time(0); IfcSchema::IfcOwnerHistory* owner_hist = new IfcSchema::IfcOwnerHistory(person_and_org, application, - boost::none, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, boost::none, person_and_org, application, timestamp); + boost::none, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, timestamp, person_and_org, application, timestamp); AddEntity(person); AddEntity(organization); @@ -91,10 +91,6 @@ IfcSchema::IfcOwnerHistory* IfcHierarchyHelper::addOwnerHistory() { IfcSchema::IfcProject* IfcHierarchyHelper::addProject(IfcSchema::IfcOwnerHistory* owner_hist) { IfcSchema::IfcRepresentationContext::list::ptr rep_contexts (new IfcSchema::IfcRepresentationContext::list); - IfcSchema::IfcGeometricRepresentationContext* rep_context = new IfcSchema::IfcGeometricRepresentationContext( - std::string("Plan"), std::string("Model"), 3, 1e-5, addPlacement3d(), addTriplet(0, 1, 0)); - - rep_contexts->push(rep_context); IfcEntityList::ptr units (new IfcEntityList); IfcSchema::IfcDimensionalExponents* dimexp = new IfcSchema::IfcDimensionalExponents(0, 0, 0, 0, 0, 0, 0); @@ -115,7 +111,6 @@ IfcSchema::IfcProject* IfcHierarchyHelper::addProject(IfcSchema::IfcOwnerHistory IfcSchema::IfcProject* project = new IfcSchema::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); @@ -227,8 +222,24 @@ IfcSchema::IfcBuildingStorey* IfcHierarchyHelper::addBuildingProduct(IfcSchema:: storey = addBuildingStorey(0, owner_hist); } AddEntity(product); - addRelatedObject(storey, product); - relatePlacements(storey, product); + // CV-2x3-158: Don't add decompositions directly to a building storey + bool is_decomposition = false; +#ifdef USE_IFC4 + IfcSchema::IfcRelAggregates::list::ptr decomposes = product->Decomposes(); + for (IfcSchema::IfcRelAggregates::list::it it = decomposes->begin(); it != decomposes->end(); ++it) { +#else + IfcSchema::IfcRelDecomposes::list::ptr decomposes = product->Decomposes(); + for (IfcSchema::IfcRelDecomposes::list::it it = decomposes->begin(); it != decomposes->end(); ++it) { +#endif + if ((*it)->RelatingObject() != product) { + is_decomposition = true; + break; + } + } + if (!is_decomposition) { + addRelatedObject(storey, product); + relatePlacements(storey, product); + } return storey; } @@ -265,7 +276,7 @@ IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addExtrudedPolyline(co IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list); IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context ? context - : getSingle(), std::string("Body"), std::string("SweptSolid"), items); + : getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), items); reps->push(rep); IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps); AddEntity(rep); @@ -301,13 +312,26 @@ void IfcHierarchyHelper::addBox(IfcSchema::IfcShapeRepresentation* rep, double w } } +void IfcHierarchyHelper::addAxis(IfcSchema::IfcShapeRepresentation* rep, double l, IfcSchema::IfcRepresentationContext* context) { + IfcSchema::IfcCartesianPoint* p1 = addDoublet(-l / 2., 0.); + IfcSchema::IfcCartesianPoint* p2 = addDoublet(+l / 2., 0.); + IfcSchema::IfcCartesianPoint::list::ptr pts(new IfcSchema::IfcCartesianPoint::list); + pts->push(p1); pts->push(p2); + IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(pts); + AddEntity(poly); + + IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items(); + items->push(poly); + rep->setItems(items); +} + IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addBox(double w, double d, double h, IfcSchema::IfcAxis2Placement2D* place, IfcSchema::IfcAxis2Placement3D* place2, IfcSchema::IfcDirection* dir, IfcSchema::IfcRepresentationContext* context) { IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list); IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list); IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation( - context ? context : getSingle(), std::string("Body"), std::string("SweptSolid"), items); + context ? context : getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), items); reps->push(rep); IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps); AddEntity(rep); @@ -316,34 +340,61 @@ IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addBox(double w, doubl return shape; } +IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addAxisBox(double w, double d, double h, IfcSchema::IfcRepresentationContext* context) +{ + IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list); + IfcSchema::IfcRepresentationItem::list::ptr body_items(new IfcSchema::IfcRepresentationItem::list); + IfcSchema::IfcRepresentationItem::list::ptr axis_items(new IfcSchema::IfcRepresentationItem::list); + IfcSchema::IfcShapeRepresentation* body_rep = new IfcSchema::IfcShapeRepresentation( + context ? context : getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), body_items); + + IfcSchema::IfcShapeRepresentation* axis_rep = new IfcSchema::IfcShapeRepresentation( + context ? context : getRepresentationContext("Plan"), std::string("Axis"), std::string("Curve2D"), axis_items); + + reps->push(axis_rep); + reps->push(body_rep); + + IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps); + AddEntity(shape); + AddEntity(body_rep); + addBox(body_rep, w, d, h, 0, 0, 0, context); + AddEntity(axis_rep); + addAxis(axis_rep, w); + + return shape; +} + void IfcHierarchyHelper::clipRepresentation(IfcSchema::IfcProductRepresentation* shape, IfcSchema::IfcAxis2Placement3D* place, bool agree) { - IfcSchema::IfcPlane* plane = new IfcSchema::IfcPlane(place); - IfcSchema::IfcHalfSpaceSolid* half_space = new IfcSchema::IfcHalfSpaceSolid(plane, agree); IfcSchema::IfcRepresentation::list::ptr reps = shape->Representations(); for (IfcSchema::IfcRepresentation::list::it j = reps->begin(); j != reps->end(); ++j) { - IfcSchema::IfcRepresentation* rep = *j; - if (rep->RepresentationIdentifier() != "Body") continue; - rep->setRepresentationType("Clipping"); - IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items(); - IfcSchema::IfcRepresentationItem::list::ptr new_items (new IfcSchema::IfcRepresentationItem::list); - AddEntity(plane); - AddEntity(half_space); - for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) { - IfcSchema::IfcRepresentationItem* item = *i; - IfcSchema::IfcBooleanClippingResult* clip = new IfcSchema::IfcBooleanClippingResult( - IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE, item, half_space); - AddEntity(clip); - new_items->push(clip); - } - rep->setItems(new_items); + clipRepresentation(*j, place, agree); } } -IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour( - IfcSchema::IfcProductRepresentation* shape, double r, double g, double b, double a) +void IfcHierarchyHelper::clipRepresentation(IfcSchema::IfcRepresentation* rep, + IfcSchema::IfcAxis2Placement3D* place, bool agree) { + if (rep->RepresentationIdentifier() != "Body") return; + IfcSchema::IfcPlane* plane = new IfcSchema::IfcPlane(place); + IfcSchema::IfcHalfSpaceSolid* half_space = new IfcSchema::IfcHalfSpaceSolid(plane, agree); + AddEntity(plane); + AddEntity(half_space); + rep->setRepresentationType("Clipping"); + IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items(); + IfcSchema::IfcRepresentationItem::list::ptr new_items (new IfcSchema::IfcRepresentationItem::list); + for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) { + IfcSchema::IfcRepresentationItem* item = *i; + IfcSchema::IfcBooleanClippingResult* clip = new IfcSchema::IfcBooleanClippingResult( + IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE, item, half_space); + AddEntity(clip); + new_items->push(clip); + } + rep->setItems(new_items); +} + +IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::addStyleAssignment(double r, double g, double b, double a) { IfcSchema::IfcColourRgb* colour = new IfcSchema::IfcColourRgb(boost::none, r, g, b); IfcSchema::IfcSurfaceStyleRendering* rendering = a == 1.0 ? new IfcSchema::IfcSurfaceStyleRendering(colour, boost::none, boost::none, boost::none, boost::none, boost::none, @@ -363,12 +414,36 @@ IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour( AddEntity(rendering); AddEntity(surface_style); AddEntity(style_assignment); + return style_assignment; +} + +IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour( + IfcSchema::IfcProductRepresentation* shape, double r, double g, double b, double a) +{ + IfcSchema::IfcPresentationStyleAssignment* style_assignment = addStyleAssignment(r, g, b, a); + setSurfaceColour(shape, style_assignment); + return style_assignment; +} + +IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour( + IfcSchema::IfcRepresentation* shape, double r, double g, double b, double a) +{ + IfcSchema::IfcPresentationStyleAssignment* style_assignment = addStyleAssignment(r, g, b, a); setSurfaceColour(shape, style_assignment); return style_assignment; } void IfcHierarchyHelper::setSurfaceColour(IfcSchema::IfcProductRepresentation* shape, IfcSchema::IfcPresentationStyleAssignment* style_assignment) +{ + IfcSchema::IfcRepresentation::list::ptr reps = shape->Representations(); + for (IfcSchema::IfcRepresentation::list::it j = reps->begin(); j != reps->end(); ++j) { + setSurfaceColour(*j, style_assignment); + } +} + +void IfcHierarchyHelper::setSurfaceColour(IfcSchema::IfcRepresentation* rep, + IfcSchema::IfcPresentationStyleAssignment* style_assignment) { #ifdef USE_IFC4 IfcEntityList::ptr style_assignments (new IfcEntityList); @@ -376,15 +451,83 @@ void IfcHierarchyHelper::setSurfaceColour(IfcSchema::IfcProductRepresentation* s IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments (new IfcSchema::IfcPresentationStyleAssignment::list); #endif style_assignments->push(style_assignment); - IfcSchema::IfcRepresentation::list::ptr reps = shape->Representations(); - for (IfcSchema::IfcRepresentation::list::it j = reps->begin(); j != reps->end(); ++j) { - IfcSchema::IfcRepresentation* rep = *j; - if (rep->RepresentationIdentifier() != "Body" && rep->RepresentationIdentifier() != "Facetation") continue; - IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items(); - for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) { - IfcSchema::IfcRepresentationItem* item = *i; - IfcSchema::IfcStyledItem* styled_item = new IfcSchema::IfcStyledItem(item, style_assignments, boost::none); - AddEntity(styled_item); - } + IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items(); + for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) { + IfcSchema::IfcRepresentationItem* item = *i; + IfcSchema::IfcStyledItem* styled_item = new IfcSchema::IfcStyledItem(item, style_assignments, boost::none); + AddEntity(styled_item); } } + +IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addMappedItem( + IfcSchema::IfcShapeRepresentation* rep, + IfcSchema::IfcCartesianTransformationOperator3D* transform, + IfcSchema::IfcProductDefinitionShape* def) +{ + IfcSchema::IfcRepresentationMap::list::ptr maps = rep->RepresentationMap(); + IfcSchema::IfcRepresentationMap* map; + if (maps->Size() == 1) { + map = *maps->begin(); + } else { + map = new IfcSchema::IfcRepresentationMap(addPlacement3d(), rep); + AddEntity(map); + } + + IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list); + if (def) representations = def->Representations(); + + if (!transform) { + transform = new IfcSchema::IfcCartesianTransformationOperator3D(0, 0, addTriplet(0,0,0), boost::none, 0); + AddEntity(transform); + } + IfcSchema::IfcMappedItem* item = new IfcSchema::IfcMappedItem(map, transform); + IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list); + items->push(item); + IfcSchema::IfcRepresentation* new_rep = new IfcSchema::IfcShapeRepresentation(rep->ContextOfItems(), boost::none, std::string("MappedRepresentation"), items); + if (rep->hasRepresentationIdentifier()) { + new_rep->setRepresentationIdentifier(rep->RepresentationIdentifier()); + } + AddEntity(item); + AddEntity(new_rep); + representations->push(new_rep); + if (!def) { + def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, representations); + AddEntity(def); + } else { + def->setRepresentations(representations); + } + return def; +} + +IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addMappedItem( + IfcSchema::IfcShapeRepresentation::list::ptr reps, + IfcSchema::IfcCartesianTransformationOperator3D* transform) +{ + IfcSchema::IfcProductDefinitionShape* def = 0; + for (IfcSchema::IfcShapeRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { + def = addMappedItem(*it, transform, def); + } + return def; +} + +IfcSchema::IfcShapeRepresentation* IfcHierarchyHelper::addEmptyRepresentation(const std::string& repid, const std::string& reptype) { + IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list); + IfcSchema::IfcShapeRepresentation* shape_rep = new IfcSchema::IfcShapeRepresentation(getRepresentationContext(reptype == "Curve2D" ? "Plan" : "Model"), repid, reptype, items); + AddEntity(shape_rep); + return shape_rep; +} + +IfcSchema::IfcGeometricRepresentationContext* IfcHierarchyHelper::getRepresentationContext(const std::string& s) { + std::map::const_iterator it = contexts.find(s); + if (it != contexts.end()) return it->second; + else { + IfcSchema::IfcProject* project = getSingle(); + IfcSchema::IfcRepresentationContext::list::ptr project_contexts = project->RepresentationContexts(); + IfcSchema::IfcGeometricRepresentationContext* context = new IfcSchema::IfcGeometricRepresentationContext( + boost::none, s, 3, 1e-5, addPlacement3d(), addDoublet(0, 1)); + AddEntity(context); + project_contexts->push(context); + project->setRepresentationContexts(project_contexts); + return contexts[s] = context; + } +} \ No newline at end of file diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index b1084cb8cd..9646bcee15 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -28,6 +28,8 @@ #ifndef IFCHIERARCHYHELPER_H #define IFCHIERARCHYHELPER_H +#include + #ifdef USE_IFC4 #include "../ifcparse/Ifc4.h" #else @@ -68,7 +70,8 @@ public: IfcSchema::IfcAxis2Placement2D* addPlacement2d(double ox=0.0, double oy=0.0, double xx=1.0, double xy=0.0); - IfcSchema::IfcLocalPlacement* addLocalPlacement(double ox=0.0, double oy=0.0, double oz=0.0, + IfcSchema::IfcLocalPlacement* addLocalPlacement(IfcSchema::IfcObjectPlacement* parent = 0, + 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); @@ -129,15 +132,43 @@ public: IfcSchema::IfcProductDefinitionShape* addBox(double w, double d, double h, IfcSchema::IfcAxis2Placement2D* place=0, IfcSchema::IfcAxis2Placement3D* place2=0, IfcSchema::IfcDirection* dir=0, IfcSchema::IfcRepresentationContext* context=0); + void addAxis(IfcSchema::IfcShapeRepresentation* rep, double l, IfcSchema::IfcRepresentationContext* context=0); + + IfcSchema::IfcProductDefinitionShape* addAxisBox(double w, double d, double h, IfcSchema::IfcRepresentationContext* context=0); + void clipRepresentation(IfcSchema::IfcProductRepresentation* shape, IfcSchema::IfcAxis2Placement3D* place, bool agree); + void clipRepresentation(IfcSchema::IfcRepresentation* shape, + IfcSchema::IfcAxis2Placement3D* place, bool agree); + + IfcSchema::IfcPresentationStyleAssignment* addStyleAssignment(double r, double g, double b, double a=1.0); + IfcSchema::IfcPresentationStyleAssignment* setSurfaceColour(IfcSchema::IfcProductRepresentation* shape, double r, double g, double b, double a=1.0); + IfcSchema::IfcPresentationStyleAssignment* setSurfaceColour(IfcSchema::IfcRepresentation* shape, + double r, double g, double b, double a=1.0); + void setSurfaceColour(IfcSchema::IfcProductRepresentation* shape, IfcSchema::IfcPresentationStyleAssignment* style_assignment); + void setSurfaceColour(IfcSchema::IfcRepresentation* shape, + IfcSchema::IfcPresentationStyleAssignment* style_assignment); + + IfcSchema::IfcProductDefinitionShape* addMappedItem(IfcSchema::IfcShapeRepresentation*, + IfcSchema::IfcCartesianTransformationOperator3D* transform = 0, + IfcSchema::IfcProductDefinitionShape* def = 0); + + IfcSchema::IfcProductDefinitionShape* addMappedItem(IfcSchema::IfcShapeRepresentation::list::ptr, + IfcSchema::IfcCartesianTransformationOperator3D* transform = 0); + + IfcSchema::IfcShapeRepresentation* addEmptyRepresentation(const std::string& repid = "Body", const std::string& reptype = "SweptSolid"); + + IfcSchema::IfcGeometricRepresentationContext* getRepresentationContext(const std::string&); + +private: + std::map contexts; }; template <> diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index d7caa34cff..3c1292e95d 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -834,6 +834,36 @@ void IfcFile::AddEntity(IfcUtil::IfcBaseClass* entity) { } byid[new_id] = entity; + unsigned arg_count = entity->entity->getArgumentCount(); + for (unsigned i = 0; i < arg_count; ++i) { + Argument* arg = entity->entity->getArgument(i); + IfcEntityList::ptr entity_attributes(new IfcEntityList); + try { + IfcUtil::IfcBaseClass* entity_attribute = *arg; + entity_attributes->push(entity_attribute); + } catch(IfcParse::IfcException&) { + try { + IfcEntityList::ptr entity_list_attribute = *arg; + entity_attributes->push(entity_list_attribute); + } catch(IfcParse::IfcException&) {} + } + for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) { + IfcUtil::IfcBaseClass* entity_attribute = *it; + try { + if (entity_attribute->entity->isWritable()) { + if ( ! entity_attribute->entity->file ) entity_attribute->entity->file = this; + ((IfcWrite::IfcWritableEntity*)(entity_attribute->entity))->setId(); + } + unsigned entity_attribute_id = entity_attribute->entity->id(); + IfcEntityList::ptr refs = EntitiesByReference(entity_attribute_id); + if (!refs) { + refs = IfcEntityList::ptr(new IfcEntityList); + byref[entity_attribute_id] = refs; + } + refs->push(entity); + } catch (IfcParse::IfcException&) {} + } + } } IfcEntityList::ptr IfcFile::EntitiesByType(IfcSchema::Type::Enum t) { MapEntitiesByType::const_iterator it = bytype.find(t); diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index eddff0d0c2..65ca9c050a 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -77,7 +77,8 @@ public: template typename U::list::ptr as() { typename U::list::ptr r(new typename U::list); - for ( it i = begin(); i != end(); ++ i ) if ((*i)->is(U::Class())) r->push((U*)*i); + const bool all = U::Class() == IfcSchema::Type::ALL; + for ( it i = begin(); i != end(); ++ i ) if (all || (*i)->is(U::Class())) r->push((U*)*i); return r; } }; @@ -101,7 +102,8 @@ public: template typename U::list::ptr as() { typename U::list::ptr r(new typename U::list); - for ( it i = begin(); i != end(); ++ i ) if ((*i)->is(U::Class())) r->push(*i); + const bool all = U::Class() == IfcSchema::Type::ALL; + for ( it i = begin(); i != end(); ++ i ) if (all || (*i)->is(U::Class())) r->push(*i); return r; } }; diff --git a/src/ifcparse/IfcWrite.cpp b/src/ifcparse/IfcWrite.cpp index 82cbd05ff2..a4c2e78303 100644 --- a/src/ifcparse/IfcWrite.cpp +++ b/src/ifcparse/IfcWrite.cpp @@ -33,7 +33,16 @@ IfcWritableEntity::~IfcWritableEntity() { delete _id; } int IfcWritableEntity::setId(int i) { - return *(_id = new int(i > 0 ? i : file->FreshId())); + if (i > 0) { + delete _id; + return *(_id = new int(i)); + } else { + if (_id) { return *_id; } + else { + delete _id; + return *(_id = new int(file->FreshId())); + } + } } IfcWritableEntity::IfcWritableEntity(IfcAbstractEntity* e) {