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 + #include "IfcUtil.h" namespace IfcWrite { @@ -57,6 +59,7 @@ namespace IfcWrite { unsigned int id(); bool isWritable(); void setArgument(int i); + void setArgument(int i,bool v); void setArgument(int i,int v); void setArgument(int i,int v, const char* c); void setArgument(int i,const std::string& v); diff --git a/src/ifcparse/IfcWrite.cpp b/src/ifcparse/IfcWrite.cpp index 2a469d5736..d544addf5b 100644 --- a/src/ifcparse/IfcWrite.cpp +++ b/src/ifcparse/IfcWrite.cpp @@ -17,10 +17,10 @@ * * ********************************************************************************/ -#include "IfcParse.h" -#include "IfcWrite.h" -#include "IfcWritableEntity.h" -#include "IfcCharacterDecoder.h" +#include "../ifcparse/IfcParse.h" +#include "../ifcparse/IfcWrite.h" +#include "../ifcparse/IfcWritableEntity.h" +#include "../ifcparse/IfcCharacterDecoder.h" using namespace IfcWrite; @@ -70,7 +70,7 @@ IfcEntities IfcWritableEntity::getInverse(Ifc2x3::Type::Enum c, int i, const std } std::string IfcWritableEntity::datatype() { return Ifc2x3::Type::ToString(_type); } -ArgumentPtr IfcWritableEntity::getArgument (unsigned int i) { if ( i >= getArgumentCount() ) throw; return args[i]; } +ArgumentPtr IfcWritableEntity::getArgument (unsigned int i) { if ( i >= getArgumentCount() ) throw IfcParse::IfcException("Argument not set"); return args[i]; } unsigned int IfcWritableEntity::getArgumentCount() {return args.size(); } Ifc2x3::Type::Enum IfcWritableEntity::type() const { return _type; } bool IfcWritableEntity::is(Ifc2x3::Type::Enum v) const { return _type == v; } @@ -102,84 +102,89 @@ void IfcWritableEntity::arg_writable(int i, bool b) { } void IfcWritableEntity::setArgument(int i) { if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteNullArgument(); + args[i] = new IfcWriteNullArgument(this); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,int v) { if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); + arg_writable(i,true); +} +void IfcWritableEntity::setArgument(int i,bool v) { + if ( arg_writable(i) ) delete args[i]; + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,int v, const char* c){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteEnumerationArgument(v,c); + args[i] = new IfcWriteEnumerationArgument(this,v,c); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,const std::string& v){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,double v){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,IfcUtil::IfcSchemaEntity v){ if ( arg_writable(i) ) delete args[i]; - if ( v ) args[i] = new IfcWriteIntegralArgument(v); - else args[i] = new IfcWriteNullArgument(); + if ( v ) args[i] = new IfcWriteIntegralArgument(this,v); + else args[i] = new IfcWriteNullArgument(this); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,IfcEntities v){ if ( arg_writable(i) ) delete args[i]; - if ( v.get() ) args[i] = new IfcWriteEntityListArgument(v); - else args[i] = new IfcWriteNullArgument(); + if ( v.get() ) args[i] = new IfcWriteEntityListArgument(this,v); + else args[i] = new IfcWriteNullArgument(this); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,const std::vector& v){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,const std::vector& v){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } void IfcWritableEntity::setArgument(int i,const std::vector& v){ if ( arg_writable(i) ) delete args[i]; - args[i] = new IfcWriteIntegralArgument(v); + args[i] = new IfcWriteIntegralArgument(this,v); arg_writable(i,true); } -IfcWriteNullArgument::operator int() const { throw; } -IfcWriteNullArgument::operator bool() const { throw; } -IfcWriteNullArgument::operator double() const { throw; } -IfcWriteNullArgument::operator std::string() const { throw; } -IfcWriteNullArgument::operator std::vector() const { throw; } -IfcWriteNullArgument::operator std::vector() const { throw; } -IfcWriteNullArgument::operator std::vector() const { throw; } -IfcWriteNullArgument::operator IfcUtil::IfcSchemaEntity() const { throw; } -IfcWriteNullArgument::operator IfcEntities() const { throw; } +IfcWriteNullArgument::operator int() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator bool() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator double() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator std::string() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator IfcUtil::IfcSchemaEntity() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteNullArgument::operator IfcEntities() const { throw IfcParse::IfcException("Invalid cast"); } bool IfcWriteNullArgument::isNull() const { return true; } -ArgumentPtr IfcWriteNullArgument::operator [] (unsigned int i) const { throw; } +ArgumentPtr IfcWriteNullArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteNullArgument::toString(bool upper) const { return "$"; } -unsigned int IfcWriteNullArgument::Size() const { throw; } +unsigned int IfcWriteNullArgument::Size() const { throw IfcParse::IfcException("Invalid cast"); } -IfcWriteEntityListArgument::IfcWriteEntityListArgument(const IfcEntities& v) { value = v; } -IfcWriteEntityListArgument::operator int() const { throw; } -IfcWriteEntityListArgument::operator bool() const { throw; } -IfcWriteEntityListArgument::operator double() const { throw; } -IfcWriteEntityListArgument::operator std::string() const { throw; } -IfcWriteEntityListArgument::operator std::vector() const { throw; } -IfcWriteEntityListArgument::operator std::vector() const { throw; } -IfcWriteEntityListArgument::operator std::vector() const { throw; } -IfcWriteEntityListArgument::operator IfcUtil::IfcSchemaEntity() const { throw; } +IfcWriteEntityListArgument::IfcWriteEntityListArgument(IfcAbstractEntity* e, const IfcEntities& v) : IfcWriteArgument(e) { value = v; } +IfcWriteEntityListArgument::operator int() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator bool() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator double() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator std::string() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEntityListArgument::operator IfcUtil::IfcSchemaEntity() const { throw IfcParse::IfcException("Invalid cast"); } IfcWriteEntityListArgument::operator IfcEntities() const { return value; } bool IfcWriteEntityListArgument::isNull() const { return false; } unsigned int IfcWriteEntityListArgument::Size() const { return value->Size(); } -ArgumentPtr IfcWriteEntityListArgument::operator [] (unsigned int i) const { throw; } +ArgumentPtr IfcWriteEntityListArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteEntityListArgument::toString(bool upper) const { std::ostringstream ss; ss << "("; @@ -189,6 +194,7 @@ std::string IfcWriteEntityListArgument::toString(bool upper) const { if ( Ifc2x3::Type::IsSimple(e->type()) ) { ss << e->toString(upper); } else { + if (!e->file) e->file = entity->file; ss << "#" << e->id(); } } @@ -196,29 +202,29 @@ std::string IfcWriteEntityListArgument::toString(bool upper) const { return ss.str(); } -IfcWriteEnumerationArgument::IfcWriteEnumerationArgument(int v, const char* c) {data=v; enumeration_value = c;} -IfcWriteEnumerationArgument::operator int() const { throw; } -IfcWriteEnumerationArgument::operator bool() const { throw; } -IfcWriteEnumerationArgument::operator double() const { throw; } +IfcWriteEnumerationArgument::IfcWriteEnumerationArgument(IfcAbstractEntity* e, int v, const char* c) : IfcWriteArgument(e) {data=v; enumeration_value = c;} +IfcWriteEnumerationArgument::operator int() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator bool() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator double() const { throw IfcParse::IfcException("Invalid cast"); } IfcWriteEnumerationArgument::operator std::string() const { return std::string(enumeration_value); } -IfcWriteEnumerationArgument::operator std::vector() const { throw; } -IfcWriteEnumerationArgument::operator std::vector() const { throw; } -IfcWriteEnumerationArgument::operator std::vector() const { throw; } -IfcWriteEnumerationArgument::operator IfcUtil::IfcSchemaEntity() const { throw; } -IfcWriteEnumerationArgument::operator IfcEntities() const { throw; } +IfcWriteEnumerationArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator std::vector() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator IfcUtil::IfcSchemaEntity() const { throw IfcParse::IfcException("Invalid cast"); } +IfcWriteEnumerationArgument::operator IfcEntities() const { throw IfcParse::IfcException("Invalid cast"); } bool IfcWriteEnumerationArgument::isNull() const { return false; } -ArgumentPtr IfcWriteEnumerationArgument::operator [] (unsigned int i) const { throw; } +ArgumentPtr IfcWriteEnumerationArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteEnumerationArgument::toString(bool upper) const { return std::string(".") + enumeration_value + '.';} -unsigned int IfcWriteEnumerationArgument::Size() const { throw; } +unsigned int IfcWriteEnumerationArgument::Size() const { throw IfcParse::IfcException("Invalid cast"); } -IfcWriteIntegralArgument::IfcWriteIntegralArgument(int v) {data=new int(v); type = Argument_INT;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(bool v) {data=new bool(v); type = Argument_BOOL;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(double v) {data=new double(v); type = Argument_DOUBLE;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(const std::string& v) {data=new std::string(v); type = Argument_STRING;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(const std::vector v) {data=new std::vector(v); type = Argument_VECTOR_INT;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(const std::vector v) {data=new std::vector(v); type = Argument_VECTOR_DOUBLE;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(const std::vector v) {data=new std::vector(v); type = Argument_VECTOR_STRING;} -IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcUtil::IfcSchemaEntity v) {data=v; type = Argument_ENTITY;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, int v) : IfcWriteArgument(e) {data=new int(v); type = Argument_INT;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, bool v) : IfcWriteArgument(e) {data=new bool(v); type = Argument_BOOL;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, double v) : IfcWriteArgument(e) {data=new double(v); type = Argument_DOUBLE;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::string& v) : IfcWriteArgument(e) {data=new std::string(v); type = Argument_STRING;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v) : IfcWriteArgument(e) {data=new std::vector(v); type = Argument_VECTOR_INT;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v) : IfcWriteArgument(e) {data=new std::vector(v); type = Argument_VECTOR_DOUBLE;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v) : IfcWriteArgument(e) {data=new std::vector(v); type = Argument_VECTOR_STRING;} +IfcWriteIntegralArgument::IfcWriteIntegralArgument(IfcAbstractEntity* e, IfcUtil::IfcSchemaEntity v) : IfcWriteArgument(e) {data=v; type = Argument_ENTITY;} IfcWriteIntegralArgument::~IfcWriteIntegralArgument() { switch ( type ) { case Argument_INT: @@ -246,15 +252,15 @@ IfcWriteIntegralArgument::~IfcWriteIntegralArgument() { break; } } -IfcWriteIntegralArgument::operator int() const { if ( type != Argument_INT ) throw; return *(int*)data; } -IfcWriteIntegralArgument::operator bool() const { if ( type != Argument_BOOL ) throw; return *(bool*)data; } -IfcWriteIntegralArgument::operator double() const { if ( type != Argument_DOUBLE ) throw; return *(double*)data; } -IfcWriteIntegralArgument::operator std::string() const { if ( type != Argument_STRING ) throw; return *(std::string*)data; } -IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_DOUBLE ) throw; return *(std::vector*)data; } -IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_INT ) throw; return *(std::vector*)data; } -IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_STRING ) throw; return *(std::vector*)data; } -IfcWriteIntegralArgument::operator IfcUtil::IfcSchemaEntity() const { if ( type != Argument_ENTITY ) throw; return (IfcUtil::IfcSchemaEntity)data; } -IfcWriteIntegralArgument::operator IfcEntities() const { throw; } +IfcWriteIntegralArgument::operator int() const { if ( type != Argument_INT ) throw IfcParse::IfcException("Invalid cast"); return *(int*)data; } +IfcWriteIntegralArgument::operator bool() const { if ( type != Argument_BOOL ) throw IfcParse::IfcException("Invalid cast"); return *(bool*)data; } +IfcWriteIntegralArgument::operator double() const { if ( type != Argument_DOUBLE ) throw IfcParse::IfcException("Invalid cast"); return *(double*)data; } +IfcWriteIntegralArgument::operator std::string() const { if ( type != Argument_STRING ) throw IfcParse::IfcException("Invalid cast"); return *(std::string*)data; } +IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_DOUBLE ) throw IfcParse::IfcException("Invalid cast"); return *(std::vector*)data; } +IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_INT ) throw IfcParse::IfcException("Invalid cast"); return *(std::vector*)data; } +IfcWriteIntegralArgument::operator std::vector() const { if ( type != Argument_VECTOR_STRING ) throw IfcParse::IfcException("Invalid cast"); return *(std::vector*)data; } +IfcWriteIntegralArgument::operator IfcUtil::IfcSchemaEntity() const { if ( type != Argument_ENTITY ) throw IfcParse::IfcException("Invalid cast"); return (IfcUtil::IfcSchemaEntity)data; } +IfcWriteIntegralArgument::operator IfcEntities() const { throw IfcParse::IfcException("Invalid cast"); } bool IfcWriteIntegralArgument::isNull() const { return false; } unsigned int IfcWriteIntegralArgument::Size() const { switch ( type ) { @@ -268,11 +274,36 @@ unsigned int IfcWriteIntegralArgument::Size() const { return ((std::vector*) data)->size(); break; default: - throw; + throw IfcParse::IfcException("Invalid cast"); break; } } -ArgumentPtr IfcWriteIntegralArgument::operator [] (unsigned int i) const { throw; } + +// The REAL token definition from the IFC SPF standard does not necessarily match +// the output of the C++ ostream formatting operation. +// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] . +std::string format_double(const double& d) { + std::ostringstream oss; + oss << d; + const std::string str = oss.str(); + oss.str(""); + std::string::size_type e = str.find('e'); + if (e == std::string::npos) { + e = str.find('E'); + } + const std::string mantissa = str.substr(0,e); + oss << mantissa; + if (mantissa.find('.') == std::string::npos) { + oss << "."; + } + if (e != std::string::npos) { + oss << "E"; + oss << str.substr(e+1); + } + return oss.str(); +} + +ArgumentPtr IfcWriteIntegralArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteIntegralArgument::toString(bool upper) const { std::ostringstream ss; switch ( type ) { @@ -283,7 +314,7 @@ std::string IfcWriteIntegralArgument::toString(bool upper) const { ss << ((*(bool*) data) ? ".T." : ".F."); break; case Argument_DOUBLE: - ss << *(double*) data; + ss << format_double(*(double*) data); break; case Argument_STRING: { std::string d = *(std::string*) data; @@ -304,7 +335,7 @@ std::string IfcWriteIntegralArgument::toString(bool upper) const { {const std::vector& v = *(std::vector*) data; for ( std::vector::const_iterator it = v.begin(); it != v.end(); ++ it ) { if ( it != v.begin() ) ss << ","; - ss << *it; + ss << format_double(*it); }} ss << ")"; break; @@ -322,19 +353,20 @@ std::string IfcWriteIntegralArgument::toString(bool upper) const { if ( Ifc2x3::Type::IsSimple(e->type()) ) { ss << e->toString(upper); } else { + if (!e->file) e->file = entity->file; ss << "#" << e->id(); }} break; - default: throw; + default: throw IfcParse::IfcException("Invalid cast"); } return ss.str(); } -IfcEntities IfcSelectHelperEntity::getInverse(Ifc2x3::Type::Enum,int,const std::string &) {throw;} -IfcEntities IfcSelectHelperEntity::getInverse(Ifc2x3::Type::Enum) {throw;} +IfcEntities IfcSelectHelperEntity::getInverse(Ifc2x3::Type::Enum,int,const std::string &) {throw IfcParse::IfcException("Invalid cast");} +IfcEntities IfcSelectHelperEntity::getInverse(Ifc2x3::Type::Enum) {throw IfcParse::IfcException("Invalid cast");} std::string IfcSelectHelperEntity::datatype() { return Ifc2x3::Type::ToString(_type); } ArgumentPtr IfcSelectHelperEntity::getArgument(unsigned int i) { - if ( i != 0 ) throw; + if ( i != 0 ) throw IfcParse::IfcException("Invalid cast"); return arg; } unsigned int IfcSelectHelperEntity::getArgumentCount() { return 1; } @@ -349,27 +381,27 @@ std::string IfcSelectHelperEntity::toString(bool upper) { ss << dt << "(" << arg->toString(upper) << ")"; return ss.str(); } -unsigned int IfcSelectHelperEntity::id() { throw; } -bool IfcSelectHelperEntity::isWritable() { throw; } +unsigned int IfcSelectHelperEntity::id() { throw IfcParse::IfcException("Invalid cast"); } +bool IfcSelectHelperEntity::isWritable() { throw IfcParse::IfcException("Invalid cast"); } IfcSelectHelper::IfcSelectHelper(const std::string& v, Ifc2x3::Type::Enum t) { - IfcWriteArgument* a = new IfcWriteIntegralArgument(v); + IfcWriteArgument* a = new IfcWriteIntegralArgument(0,v); this->entity = new IfcSelectHelperEntity(t,a); } IfcSelectHelper::IfcSelectHelper(const char* const v, Ifc2x3::Type::Enum t) { - IfcWriteArgument* a = new IfcWriteIntegralArgument(std::string(v)); + IfcWriteArgument* a = new IfcWriteIntegralArgument(0,std::string(v)); this->entity = new IfcSelectHelperEntity(t,a); } IfcSelectHelper::IfcSelectHelper(int v, Ifc2x3::Type::Enum t) { - IfcWriteArgument* a = new IfcWriteIntegralArgument(v); + IfcWriteArgument* a = new IfcWriteIntegralArgument(0,v); this->entity = new IfcSelectHelperEntity(t,a); } IfcSelectHelper::IfcSelectHelper(double v, Ifc2x3::Type::Enum t) { - IfcWriteArgument* a = new IfcWriteIntegralArgument(v); + IfcWriteArgument* a = new IfcWriteIntegralArgument(0,v); this->entity = new IfcSelectHelperEntity(t,a); } IfcSelectHelper::IfcSelectHelper(bool v, Ifc2x3::Type::Enum t) { - IfcWriteArgument* a = new IfcWriteIntegralArgument(v); + IfcWriteArgument* a = new IfcWriteIntegralArgument(0,v); this->entity = new IfcSelectHelperEntity(t,a); } bool IfcSelectHelper::is(Ifc2x3::Type::Enum t) const { return entity->is(t); } diff --git a/src/ifcparse/IfcWrite.h b/src/ifcparse/IfcWrite.h index dc33159c47..ac385922ea 100644 --- a/src/ifcparse/IfcWrite.h +++ b/src/ifcparse/IfcWrite.h @@ -28,19 +28,22 @@ #ifndef IFCWRITE_H #define IFCWRITE_H -#include "IfcUtil.h" -#include "IfcParse.h" +#include "../ifcparse/IfcUtil.h" +#include "../ifcparse/IfcParse.h" namespace IfcWrite { /// A placeholder class for grouping functionality geared towards writing IFC files class IfcWriteArgument : public Argument { - + protected: + IfcAbstractEntity* entity; + IfcWriteArgument(IfcAbstractEntity* e) : entity(e) {} }; /// A null argument. It will always serialize to $ class IfcWriteNullArgument : public IfcWriteArgument { public: + IfcWriteNullArgument(IfcAbstractEntity* e) : IfcWriteArgument(e) {}; operator int() const; operator bool() const; operator double() const; @@ -63,7 +66,7 @@ namespace IfcWrite { private: IfcEntities value; public: - IfcWriteEntityListArgument(const IfcEntities& v); + IfcWriteEntityListArgument(IfcAbstractEntity* e, const IfcEntities& v); operator int() const; operator bool() const; operator double() const; @@ -90,7 +93,7 @@ namespace IfcWrite { int data; const char* enumeration_value; public: - IfcWriteEnumerationArgument(int v, const char* c); + IfcWriteEnumerationArgument(IfcAbstractEntity* e, int v, const char* c); operator int() const; operator bool() const; operator double() const; @@ -114,14 +117,14 @@ namespace IfcWrite { void* data; IfcUtil::ArgumentType type; public: - IfcWriteIntegralArgument(int v); - IfcWriteIntegralArgument(bool v); - IfcWriteIntegralArgument(double v); - IfcWriteIntegralArgument(const std::string& v); - IfcWriteIntegralArgument(const std::vector v); - IfcWriteIntegralArgument(const std::vector v); - IfcWriteIntegralArgument(const std::vector v); - IfcWriteIntegralArgument(IfcUtil::IfcSchemaEntity v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, int v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, bool v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, double v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::string& v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, const std::vector v); + IfcWriteIntegralArgument(IfcAbstractEntity* e, IfcUtil::IfcSchemaEntity v); ~IfcWriteIntegralArgument(); operator int() const; operator bool() const; diff --git a/win/IfcOpenHouse.vcproj b/win/IfcOpenHouse.vcproj new file mode 100644 index 0000000000..6127b56a31 --- /dev/null +++ b/win/IfcOpenHouse.vcproj @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/IfcOpenShell.sln b/win/IfcOpenShell.sln index 24d0b08edb..b21e1471d7 100644 --- a/win/IfcOpenShell.sln +++ b/win/IfcOpenShell.sln @@ -26,6 +26,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IfcParseExamples", "IfcPars {F7600775-3D48-426A-88E2-F3A4BF4408A2} = {F7600775-3D48-426A-88E2-F3A4BF4408A2} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IfcOpenHouse", "IfcOpenHouse.vcproj", "{163D7E4F-5337-4FAD-AC11-4D40078395A3}" + ProjectSection(ProjectDependencies) = postProject + {BA57AF0F-1D12-4FAC-BD40-7474D729CAE9} = {BA57AF0F-1D12-4FAC-BD40-7474D729CAE9} + {F7600775-3D48-426A-88E2-F3A4BF4408A2} = {F7600775-3D48-426A-88E2-F3A4BF4408A2} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -56,6 +62,10 @@ Global {4DA9E9D7-60A6-4031-BA78-A3741BD62CB9}.Debug|Win32.Build.0 = Debug|Win32 {4DA9E9D7-60A6-4031-BA78-A3741BD62CB9}.Release|Win32.ActiveCfg = Release|Win32 {4DA9E9D7-60A6-4031-BA78-A3741BD62CB9}.Release|Win32.Build.0 = Release|Win32 + {163D7E4F-5337-4FAD-AC11-4D40078395A3}.Debug|Win32.ActiveCfg = Debug|Win32 + {163D7E4F-5337-4FAD-AC11-4D40078395A3}.Debug|Win32.Build.0 = Debug|Win32 + {163D7E4F-5337-4FAD-AC11-4D40078395A3}.Release|Win32.ActiveCfg = Release|Win32 + {163D7E4F-5337-4FAD-AC11-4D40078395A3}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/win/IfcParse.vcproj b/win/IfcParse.vcproj index 266dc18f2f..3cbc9d8ca9 100644 --- a/win/IfcParse.vcproj +++ b/win/IfcParse.vcproj @@ -180,7 +180,11 @@ - + + + + +