Skip to content

Commit 6f1e1c3

Browse files
committed
NOTE: From now on Boost is required in order to compile IfcOpenShell
==================================================================== - Use boost::optional for optional IFC arguments - Use boost::uuid for the creation of GlobalIds - New IfcGeomObjects setting to force alignment of TopoDS_Face normal to CCW orientation - Removed static Ifc class, renamed to non-static IfcFile. IfcFile renamed to IfcSpfStream - Introduced Logger class - Introduced EntityBuffer class that keeps track of all writable entities created to add them all in once to the IfcFile class
1 parent 31daf8d commit 6f1e1c3

29 files changed

Lines changed: 2932 additions & 2683 deletions

src/examples/IfcParseExamples.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ int main(int argc, char** argv) {
2929
}
3030

3131
// Redirect the output (both progress and log) to stdout
32-
Ifc::SetOutput(&std::cout,&std::cout);
32+
Logger::SetOutput(&std::cout,&std::cout);
3333

3434
// Parse the IFC file provided in argv[1]
35-
if ( ! Ifc::Init(argv[1]) ) {
35+
IfcParse::IfcFile file;
36+
if ( ! file.Init(argv[1]) ) {
3637
std::cout << "Unable to parse .ifc file" << std::endl;
3738
return 1;
3839
}
@@ -53,12 +54,7 @@ int main(int argc, char** argv) {
5354
// we need to cast them to IfcWindows. Since these properties
5455
// are optional we need to make sure the properties are
5556
// defined for the window in question before accessing them.
56-
//
57-
// Since we are accessing properties that represent a length
58-
// measure we can multiply the value by Ifc::LengthUnit, which
59-
// contains the ratio of the unit defined in the IfcUnitAssignment
60-
// to the standard SI Unit, the meter.
61-
IfcBuildingElement::list elements = Ifc::EntitiesByType<IfcBuildingElement>();
57+
IfcBuildingElement::list elements = file.EntitiesByType<IfcBuildingElement>();
6258

6359
std::cout << "Found " << elements->Size() << " elements in " << argv[1] << ":" << std::endl;
6460

@@ -71,8 +67,8 @@ int main(int argc, char** argv) {
7167
const IfcWindow::ptr window = reinterpret_pointer_cast<IfcBuildingElement,IfcWindow>(element);
7268

7369
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
74-
const float area = window->OverallWidth()*window->OverallHeight() * (Ifc::LengthUnit*Ifc::LengthUnit);
75-
std::cout << "This window has an area of " << area << "m2" << std::endl;
70+
const double area = window->OverallWidth()*window->OverallHeight();
71+
std::cout << "The area of this window is " << area << std::endl;
7672
}
7773
}
7874

src/ifcexpressparser/IfcExpressParser.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
header = """
1+
header = """
22
/********************************************************************************
33
* *
44
* This file is part of IfcOpenShell. *
@@ -103,7 +103,8 @@ def get():
103103
entity_map = {}
104104

105105
#
106-
# Since inherited arguments of Express entities are placed in sequence before the non-inherited once, we need to keep track of how many inherited arguments exist
106+
# Since inherited arguments of Express entities are placed in sequence before the
107+
# non-inherited ones, we need to keep track of how many inherited arguments exist
107108
#
108109
def argument_start(c):
109110
if c not in parent_relations: return 0
@@ -123,6 +124,19 @@ def parent_arguments(c):
123124
if not (c in parent_relations): break
124125
return []
125126

127+
#
128+
# Every constructor also initializes their parent class members, hence they
129+
# need be stored as well.
130+
#
131+
def parent_arguments(c):
132+
if c not in parent_relations: return []
133+
l = []
134+
while True:
135+
c = parent_relations[c]
136+
i += argument_count[c] if c in argument_count else 0
137+
if not (c in parent_relations): break
138+
return []
139+
126140
#
127141
# Several classes to generate code from Express types and entities
128142
#
@@ -236,11 +250,12 @@ def is_enum(self): return str(self.type) in enumerations
236250
def type_str(self):
237251
if self.type.is_select_list():
238252
# This is extremely hackish indeed
239-
return "IfcEntities"
253+
return "optional<IfcEntities>" if self.optional else "IfcEntities"
240254
elif str(self.type) in entity_names:
241255
return "%(type)s*"%self.__dict__
242256
else:
243-
return "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
257+
t = "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
258+
return "optional<%s>"%t if self.optional else t
244259
class ArgumentList:
245260
def __init__(self,l):
246261
self.l = [Argument(a) for a in l]
@@ -350,10 +365,21 @@ def get_constructor_implementation(self):
350365
i = len(s) + 1
351366
b = 0
352367
for a in self.arguments.l:
368+
is_enumeration = str(a.type) in enumerations
369+
# boost::optional is not used for pointer types, because they are set to NULL using 0
370+
use_boost_optional = a.optional and str(a.type) not in entity_names
371+
# boost::optional types need to be dereferenced before passing to the writable entity
372+
dereference = "*" if use_boost_optional else ""
353373
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr() and not a.type.is_select_list()) else ""
354374
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
355375
continue
356-
s.append("e->setArgument(%d,v%d_%s%s)"%(b+i-1,b+i,a.name,generalize))
376+
if is_enumeration:
377+
impl = "e->setArgument(%d,%sv%d_%s,%s::ToString(%sv%d_%s))"%(b+i-1,dereference,b+i,a.name,str(a.type),dereference,b+i,a.name)
378+
else:
379+
impl = "e->setArgument(%d,(%sv%d_%s)%s)"%(b+i-1,dereference,b+i,a.name,generalize)
380+
if use_boost_optional:
381+
s.append("if (v%d_%s) { %s; } else { e->setArgument(%d); } "%(b+i,a.name,impl,b+i-1))
382+
else: s.append(impl)
357383
b += 1
358384
return s#"; ".join(s)
359385
def __str__(self):
@@ -384,7 +410,7 @@ def __str__(self):
384410
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
385411
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
386412
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }"+
387-
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; }" if len(self.constructor_args_list) else "")
413+
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; EntityBuffer::Add(this); }" if len(self.constructor_args_list) else "")
388414
)%self.__dict__)%self.__dict__
389415

390416

@@ -475,12 +501,15 @@ def __str__(self):
475501
#include <vector>
476502
#include <map>
477503
504+
#include <boost/optional.hpp>
505+
478506
#include "../ifcparse/IfcUtil.h"
479507
#include "../ifcparse/IfcException.h"
480508
#include "../ifcparse/%(schema)senum.h"
481509
482510
using namespace IfcUtil;
483511
using IfcParse::IfcException;
512+
using boost::optional;
484513
485514
#define RETURN_INVERSE(T) \\
486515
IfcEntities e = entity->getInverse(T::Class()); \\

src/ifcgeom/IfcGeom.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,32 @@ namespace IfcGeom {
4747
// Tolerances and settings for various geometrical operations:
4848
enum GeomValue {
4949
// Specifies the deflection of the mesher
50+
// Default: 0.001m / 1mm
5051
GV_DEFLECTION_TOLERANCE,
5152
// Specifies the tolerance of the wire builder, most notably for trimmed curves
53+
// Defailt: 0.0001m / 0.1mm
5254
GV_WIRE_CREATION_TOLERANCE,
5355
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
56+
// Default: 0.000001m 0.01cm2
5457
GV_MINIMAL_FACE_AREA,
5558
// Specifies the treshold distance under which cartesian points are deemed equal
59+
// Default: 0.00001m / 0.01mm
5660
GV_POINT_EQUALITY_TOLERANCE,
5761
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
5862
// that consist of many faces is really detrimental for the performance.
59-
GV_MAX_FACES_TO_SEW
63+
// Default: 1000
64+
GV_MAX_FACES_TO_SEW,
65+
// By default singular faces have no explicitly defined orientation, to
66+
// force faces to be defined CounterClockWise, set this value greater than zero.
67+
GV_FORCE_CCW_FACE_ORIENTATION,
68+
// The length unit used the creation of TopoDS_Shapes, primarily affects the
69+
// interpretation of IfcCartesianPoints and IfcVector magnitudes
70+
// DefaultL 1.0
71+
GV_LENGTH_UNIT,
72+
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
73+
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
74+
// Default: -1.0 (= not set, fist try degrees, then radians)
75+
GV_PLANEANGLE_UNIT,
6076
};
6177

6278
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
@@ -80,7 +96,7 @@ namespace IfcGeom {
8096
double face_area(const TopoDS_Face& f);
8197
void SetValue(GeomValue var, double value);
8298
double GetValue(GeomValue var);
83-
99+
84100
namespace Cache {
85101
void Purge();
86102
void PurgeShapeCache();

src/ifcgeom/IfcGeomCurves.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
#include "../ifcgeom/IfcGeom.h"
7979

8080
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
81-
const double r = l->Radius() * Ifc::LengthUnit;
81+
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
8282
if ( r <= 0.0f ) { return false; }
8383
gp_Trsf trsf;
8484
Ifc2x3::IfcAxis2Placement placement = l->Position();
@@ -94,8 +94,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve)
9494
return true;
9595
}
9696
bool IfcGeom::convert(const Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
97-
double x = l->SemiAxis1() * Ifc::LengthUnit;
98-
double y = l->SemiAxis2() * Ifc::LengthUnit;
97+
double x = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
98+
double y = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
9999
if ( x == 0.0f || y == 0.0f || y > x ) { return false; }
100100
gp_Trsf trsf;
101101
Ifc2x3::IfcAxis2Placement placement = l->Position();

0 commit comments

Comments
 (0)