Compare commits

...

15 Commits

Author SHA1 Message Date
Thomas Krijnen b2e8219caa Fix 3ds max API version detection 2013-01-13 12:01:20 +00:00
Thomas Krijnen eddf5488dc Update version numbers 2013-01-01 15:11:04 +00:00
Thomas Krijnen 533fd59c14 Better Unicode handling in the 3ds max importer
Don't initiate progress handler until valid file is opened
2013-01-01 15:10:14 +00:00
Thomas Krijnen 55e3d2959f Do revert to unknown plane angle unit state after guessing when creating an IfcCompositeCurve 2012-12-31 15:48:04 +00:00
Thomas Krijnen 0714fbdab5 Getting ready for Blender 2.65 and Python 3.3.0 with universal Unicode according to PEP 393
Allow opening of non-latin filenames on Windows, by using the non-standard _wfopen(), meaning that the IfcSpfStream no longer relies on a std::istream but a FILE* descriptor
2012-12-31 15:13:35 +00:00
Thomas Krijnen 91d6d9f20f Add the LGPL license text supplement to the repository 2012-12-31 14:47:02 +00:00
Thomas Krijnen 0bc187faaa IfcGeom: Use the 'wire creation tolerance' on point projection for trimmed curves
Fall back to trimming by parameter if possible and point projection fails
2012-12-31 14:38:00 +00:00
Jang Myeongho 69384e87aa Added getter to IfcFile object
fixed wrong operator to judge plan angle unit is not exist.
guessed plane angle unit stay in a file processing.
2012-12-31 14:35:14 +00:00
Thomas Krijnen 8895368ae3 Fix some errors and warnings 2012-12-31 14:29:18 +00:00
Thomas Krijnen 22ab3ad06a 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
2012-12-31 14:17:16 +00:00
Thomas Krijnen 23450c7c39 If no plane angle unit is provided in the IFC file, create composite curves using both radians and degrees and see which 'looks best' (=successfully created and/or closed curve)
Forget information about plane angle units in previously processed files
2012-12-31 13:50:33 +00:00
Thomas Krijnen b11f5929bf Remove BOM in Interface.h
Remove dependency on nullptr for older compilers
2012-12-31 13:41:52 +00:00
Thomas Krijnen e2bb18476d Convert all .cpp and .h files to UTF-8 with BOM 2012-12-31 13:28:01 +00:00
Jang Myeongho de756166e0 Added enum 'DEFAULT' to 'IfcCharacterDecoder::ConversionMode': using default converter as system default codepage.
Added IfcCharacterDecoder::compatibility_mode
avoid leaks (compatibility_converter)
fixed wrong assertion.
added break statements.
Only allow character decoder compatibility mode if HAVE_ICU is defined since it relies on ICU to be available.
2012-12-31 13:17:15 +00:00
Thomas Krijnen 43e6d5f105 Apply patch #3537663 by myueho: https://sourceforge.net/tracker/?func=detail&atid=2204968&aid=3537663&group_id=543113 2012-12-31 12:22:36 +00:00
50 changed files with 4113 additions and 3665 deletions
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+7 -11
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -29,10 +29,11 @@ int main(int argc, char** argv) {
}
// Redirect the output (both progress and log) to stdout
Ifc::SetOutput(&std::cout,&std::cout);
Logger::SetOutput(&std::cout,&std::cout);
// Parse the IFC file provided in argv[1]
if ( ! Ifc::Init(argv[1]) ) {
IfcParse::IfcFile file;
if ( ! file.Init(argv[1]) ) {
std::cout << "Unable to parse .ifc file" << std::endl;
return 1;
}
@@ -53,12 +54,7 @@ int main(int argc, char** argv) {
// we need to cast them to IfcWindows. Since these properties
// are optional we need to make sure the properties are
// defined for the window in question before accessing them.
//
// Since we are accessing properties that represent a length
// measure we can multiply the value by Ifc::LengthUnit, which
// contains the ratio of the unit defined in the IfcUnitAssignment
// to the standard SI Unit, the meter.
IfcBuildingElement::list elements = Ifc::EntitiesByType<IfcBuildingElement>();
IfcBuildingElement::list elements = file.EntitiesByType<IfcBuildingElement>();
std::cout << "Found " << elements->Size() << " elements in " << argv[1] << ":" << std::endl;
@@ -71,8 +67,8 @@ int main(int argc, char** argv) {
const IfcWindow::ptr window = reinterpret_pointer_cast<IfcBuildingElement,IfcWindow>(element);
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
const float area = window->OverallWidth()*window->OverallHeight() * (Ifc::LengthUnit*Ifc::LengthUnit);
std::cout << "This window has an area of " << area << "m2" << std::endl;
const double area = window->OverallWidth()*window->OverallHeight();
std::cout << "The area of this window is " << area << std::endl;
}
}
+14 -53
View File
@@ -30,8 +30,8 @@ bl_info = {
"description": "Import files in the "\
"Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 5, 8),
"api": 37702,
"blender": (2, 6, 5),
"api": 52851,
"location": "File > Import",
"warning": "",
"wiki_url": "http://sourceforge.net/apps/"\
@@ -39,14 +39,6 @@ bl_info = {
"tracker_url": "http://sourceforge.net/tracker/?group_id=543113",
"category": "Import-Export"}
import sys
max_unicode = 0x110000-1 if sys.platform[0:5] == 'linux' else 0x10000-1
wrong_unicode = max_unicode != sys.maxunicode
if wrong_unicode:
print("\nWarning: wrong unicode representation detected, switching to "\
"compatibility layer for text transferral, may result in undefined "\
"behaviour, please use offical release from http://blender.org\n")
if "bpy" in locals():
import imp
if "IfcImport" in locals():
@@ -71,15 +63,9 @@ bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
def import_ifc(filename, use_names, process_relations):
global wrong_unicode
from . import IfcImport
print("Reading %s..."%bpy.path.basename(filename))
if wrong_unicode:
valid_file = IfcImport.InitUCS2(
''.join(['\0']+['\0%s'%s for s in filename]+['\0\0'])
)
else:
valid_file = IfcImport.Init(filename)
valid_file = IfcImport.Init(filename)
if not valid_file:
IfcImport.CleanUp()
return False
@@ -91,19 +77,12 @@ def import_ifc(filename, use_names, process_relations):
print("Creating geometry...")
while True:
ob = IfcImport.Get()
if wrong_unicode:
ob_name = ''.join([chr(c) for c in ob.name_as_intvector()])
ob_type = ''.join([chr(c) for c in ob.type_as_intvector()])
ob_guid = ''.join([chr(c) for c in ob.guid_as_intvector()])
else:
ob_name, ob_type, ob_guid = ob.name, ob.type, ob.guid
f = ob.mesh.faces
v = ob.mesh.verts
m = ob.matrix
t = ob_type[0:21]
nm = ob_name if len(ob_name) and use_names else ob_guid
t = ob.type[0:21]
nm = ob.name if len(ob.name) and use_names else ob.guid
verts = [[v[i], v[i + 1], v[i + 2]] \
for i in range(0, len(v), 3)]
@@ -138,9 +117,9 @@ def import_ifc(filename, use_names, process_relations):
bpy.ops.object.mode_set(mode='OBJECT')
bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = \
ob.id, ob_guid, ob_name, ob_type
ob.id, ob.guid, ob.name, ob.type
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
bob.hide = ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement'
bob.hide_render = bob.hide
if ob.id not in id_to_object: id_to_object[ob.id] = []
@@ -173,20 +152,9 @@ def import_ifc(filename, use_names, process_relations):
if parent_ob.id == -1:
bob = None
else:
if wrong_unicode:
parent_ob_name = ''.join(
[chr(c) for c in parent_ob.name_as_intvector()])
parent_ob_type = ''.join(
[chr(c) for c in parent_ob.type_as_intvector()])
parent_ob_guid = ''.join(
[chr(c) for c in parent_ob.guid_as_intvector()])
else:
parent_ob_name, parent_ob_type, parent_ob_guid = \
parent_ob.name, parent_ob.type, parent_ob.guid
m = parent_ob.matrix
nm = parent_ob_name if len(parent_ob_name) and use_names \
else parent_ob_guid
nm = parent_ob.name if len(parent_ob.name) and use_names \
else parent_ob.guid
bob = bpy.data.objects.new(nm, None)
mat = mathutils.Matrix((
@@ -201,7 +169,7 @@ def import_ifc(filename, use_names, process_relations):
bob.ifc_id = parent_ob.id
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
parent_ob_name, parent_ob_type, parent_ob_guid
parent_ob.name, parent_ob.type, parent_ob.guid
if parent_ob.parent_id > 0:
id_to_parent[parent_id] = parent_ob.parent_id
@@ -227,9 +195,8 @@ def import_ifc(filename, use_names, process_relations):
if process_relations:
print("Done processing relations")
if not wrong_unicode:
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt.from_string(IfcImport.GetLog())
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt.from_string(IfcImport.GetLog())
IfcImport.CleanUp()
@@ -253,13 +220,7 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
default=False)
def execute(self, context):
global wrong_unicode
if wrong_unicode and sys.platform[0:5] != 'linux':
self.report({'ERROR'},
'Your version of Blender is incompatible with IfcBlender\n' \
'Please use the offical release from http://blender.org instead'
)
elif not import_ifc(self.filepath, self.use_names, self.process_relations):
if not import_ifc(self.filepath, self.use_names, self.process_relations):
self.report({'ERROR'},
'Unable to parse .ifc file or no geometrical entities found'
)
+7 -7
View File
@@ -122,11 +122,11 @@ class ArrayType:
self.lower = l[1]
def __str__(self):
if self.type in entity_names:
return "SHARED_PTR< IfcTemplatedEntityList<%s> >"%self.type
return "SHARED_PTR< IfcTemplatedEntityList< %s > >"%self.type
elif self.type in selections:
return "SHARED_PTR< IfcTemplatedEntityList<IfcAbstractSelect> >"
return "SHARED_PTR< IfcTemplatedEntityList< IfcAbstractSelect > >"
else:
return "std::vector<%(type)s> /*[%(lower)s:%(upper)s]*/"%self.__dict__
return "std::vector< %(type)s > /*[%(lower)s:%(upper)s]*/"%self.__dict__
def type_enum(self):
if self.type in simple_types:
t = simple_types[self.type].type_enum()
@@ -167,7 +167,7 @@ class EnumType:
elif generator_mode == 'SOURCE_TO':
return '{ "%s" }'%'","'.join([v1 for v1,v2 in self.v])
elif generator_mode == 'SOURCE_FROM':
return "".join([' if(s=="%s"%s) return %s::%s;\n'%(v1.upper()," "*(self.maxlen-len(v1)),"%(name)s",v2) for v1,v2 in self.v])
return "".join([' if(s=="%s"%s) return ::%s::%s::%s;\n'%(v1.upper()," "*(self.maxlen-len(v1)),schema_version,"%(name)s",v2) for v1,v2 in self.v])
def __len__(self): return len(self.v)
def type_enum(self):
return "Argument_ENUMERATION"
@@ -292,7 +292,7 @@ class InverseList:
s = ""
for i in self.l:
if generator_mode == 'HEADER':
s += "\n SHARED_PTR< IfcTemplatedEntityList<%s> > %s(); // INVERSE %s::%s"%(i.type.type,i.name,i.type.type,i.reference)
s += "\n SHARED_PTR< IfcTemplatedEntityList< %s > > %s(); // INVERSE %s::%s"%(i.type.type,i.name,i.type.type,i.reference)
elif generator_mode == 'SOURCE':
s += "\n%s::list %s::%s() { RETURN_INVERSE(%s) }"%(i.type.type,"%(class_name)s",i.name,i.type.type)
return s
@@ -317,8 +317,8 @@ class Classdef:
"\n static Type::Enum Class();"+
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
"\n typedef %(class_name)s* ptr;"+
"\n typedef SHARED_PTR< IfcTemplatedEntityList<%(class_name)s> > list;"+
"\n typedef IfcTemplatedEntityList<%(class_name)s>::it it;")%self.__dict__
"\n typedef SHARED_PTR< IfcTemplatedEntityList< %(class_name)s > > list;"+
"\n typedef IfcTemplatedEntityList< %(class_name)s >::it it;")%self.__dict__
)
elif generator_mode == 'SOURCE':
self.arguments.argstart = argument_start(self.class_name)
+36 -15
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -42,21 +42,39 @@
#include "../ifcgeom/IfcShapeList.h"
// Tolerances for various geometrical operations:
// Specifies the deflection of the mesher
#define DEFLECTION_TOLERANCE 0.001
// Specifies the tolerance of the wire builder, most notably for trimmed curves
#define WIRE_CREATION_TOLERANCE 0.0001
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
#define MINIMAL_FACE_AREA 0.000001
// Specifies the treshold distance under which cartesian points are deemed equal
#define POINT_EQUALITY_TOLERANCE 0.00001
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
#define MAX_FACES_TO_SEW 1000
namespace IfcGeom {
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Default: 0.000001m 0.01cm2
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
};
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ShapeList& result);
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
@@ -76,6 +94,9 @@ namespace IfcGeom {
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face);
double shape_volume(const TopoDS_Shape& s);
double face_area(const TopoDS_Face& f);
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
namespace Cache {
void Purge();
void PurgeShapeCache();
+4 -4
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -78,7 +78,7 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r <= 0.0f ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
@@ -94,8 +94,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve)
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
double x = l->SemiAxis1() * Ifc::LengthUnit;
double y = l->SemiAxis2() * Ifc::LengthUnit;
double x = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double y = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x == 0.0f || y == 0.0f || y > x ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
+92 -32
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -74,6 +74,7 @@
#include <ShapeFix_Solid.hxx>
#include <TopLoc_Location.hxx>
#include <BRepGProp_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
@@ -81,15 +82,15 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
Ifc2x3::IfcFaceBound::list bounds = l->Bounds();
Ifc2x3::IfcFaceBound::it it = bounds->begin();
Ifc2x3::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire wire;
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
BRepBuilderAPI_MakeFace mf (wire);
TopoDS_Wire outer_wire;
if ( ! IfcGeom::convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(wire);
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
er = mf.Error();
}
if ( er != BRepBuilderAPI_FaceDone ) return false;
@@ -116,6 +117,65 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
return false;
}
}
if ( IfcGeom::GetValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(face);
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
int n = 0;
// Iterate over the vertices of the outer wire (discarding
// any potential holes)
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
unsigned has_more = exp.More();
if ( has_more ) {
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
current = BRep_Tool::Pnt(v);
} else {
current = first;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
// It might be a good idea to globally discard faces
// smaller than a certain treshold value. But for now
// only when processing IfcConnectedFacesets the small
@@ -145,11 +205,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcArbitraryProfileDefWithVoids::ptr l, Topo
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->XDim() / 2.0f * Ifc::LengthUnit;
const double y = l->YDim() / 2.0f * Ifc::LengthUnit;
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x == 0.0f || y == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -159,18 +219,18 @@ bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face&
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->OverallWidth() / 2.0f * Ifc::LengthUnit;
const double y = l->OverallDepth() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WebThickness() / 2.0f * Ifc::LengthUnit;
const double d2 = l->FlangeThickness() * Ifc::LengthUnit;
const double x = l->OverallWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
double f;
if ( doFillet ) {
f = l->FilletRadius() * Ifc::LengthUnit;
f = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -183,19 +243,19 @@ bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& face) {
const double x = l->Depth() / 2.0f * Ifc::LengthUnit;
const double y = l->Width() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WallThickness() * Ifc::LengthUnit;
const double d2 = l->Girth() * Ifc::LengthUnit;
const double x = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
double f1,f2;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * Ifc::LengthUnit;
f1 = l->InternalFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = f1 + d1;
}
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -208,21 +268,21 @@ bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& face) {
const double y = l->Depth() / 2.0f * Ifc::LengthUnit;
const double x = l->Width() / 2.0f * Ifc::LengthUnit;
const double d = l->Thickness() * Ifc::LengthUnit;
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doEdgeFillet = l->hasEdgeRadius();
bool doFillet = l->hasFilletRadius();
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * Ifc::LengthUnit;
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * Ifc::LengthUnit;
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || d == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -235,9 +295,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& face) {
const double r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -252,11 +312,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::convert_wire_to_face(w,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleHollowProfileDef::ptr l, TopoDS_Face& face) {
const double r = l->Radius() * Ifc::LengthUnit;
const double t = l->WallThickness() * Ifc::LengthUnit;
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f || t == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
+87 -19
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -23,6 +23,8 @@
* *
********************************************************************************/
#include <cassert>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
@@ -88,9 +90,9 @@
bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetMaxTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetMinTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
TopExp_Explorer exp(compound,TopAbs_FACE);
if ( ! exp.More() ) return false;
for ( ; exp.More(); exp.Next() ) {
@@ -101,7 +103,7 @@ bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Sh
shape = builder.SewedShape();
try {
ShapeFix_Solid sf_solid;
sf_solid.LimitTolerance(POINT_EQUALITY_TOLERANCE);
sf_solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
shape = sf_solid.SolidFromShell(TopoDS::Shell(shape));
} catch(...) {}
return true;
@@ -161,7 +163,7 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
} else {
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
@@ -173,17 +175,17 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it4->second),opening_shape_solid);
const gp_GTrsf& opening_shape_gtrsf = *(it4->first);
if ( opening_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to opening of:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity);
}
const TopoDS_Shape& opening_shape = opening_shape_gtrsf.Form() == gp_Other
? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape()
: opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf());
double opening_volume, original_shape_volume;
if ( Ifc::Verbosity > 1 ) {
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
opening_volume = shape_volume(opening_shape);
if ( opening_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty opening for:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity->entity);
original_shape_volume = shape_volume(entity_shape);
}
@@ -196,17 +198,17 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
bool is_valid = analyser.IsValid() != 0;
if ( is_valid ) {
entity_shape = brep_cut;
if ( Ifc::Verbosity > 1 ) {
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
const double volume_after_subtraction = shape_volume(entity_shape);
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity);
}
} else {
Ifc::LogMessage("Error","Invalid result from subtraction:",entity->entity);
Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity);
}
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",entity->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
}
}
@@ -272,7 +274,7 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
} else {
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
@@ -293,7 +295,7 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const
// Apparently processing the boolean operation failed or resulted in an invalid result
// in which case the original shape without the subtractions is returned instead
// we try convert the openings in the original way, one by one.
Ifc::LogMessage("Warning","Subtracting combined openings compound failed:",entity->entity);
Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity->entity);
return false;
}
@@ -369,8 +371,8 @@ bool IfcGeom::is_convex(const TopoDS_Wire& wire) {
edge_points.push_back(P2);
}
if ( edge_points.size() != 2 ) continue;
if ( edge_points[0].IsEqual(P1,POINT_EQUALITY_TOLERANCE)) neighbors.push_back(edge_points[1]);
else if ( edge_points[1].IsEqual(P1,POINT_EQUALITY_TOLERANCE)) neighbors.push_back(edge_points[0]);
if ( edge_points[0].IsEqual(P1,GetValue(GV_POINT_EQUALITY_TOLERANCE))) neighbors.push_back(edge_points[1]);
else if ( edge_points[1].IsEqual(P1, GetValue(GV_POINT_EQUALITY_TOLERANCE))) neighbors.push_back(edge_points[0]);
}
// There should be two of these
if ( neighbors.size() != 2 ) return false;
@@ -379,10 +381,10 @@ bool IfcGeom::is_convex(const TopoDS_Wire& wire) {
for ( TopExp_Explorer exp2(wire,TopAbs_VERTEX); exp2.More(); exp2.Next() ) {
TopoDS_Vertex V2 = TopoDS::Vertex(exp2.Current());
gp_Pnt P2 = BRep_Tool::Pnt(V2);
if ( P1.IsEqual(P2,POINT_EQUALITY_TOLERANCE) ) continue;
if ( P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) continue;
bool found = false;
for( std::vector<gp_Pnt>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++ it ) {
if ( (*it).IsEqual(P2,POINT_EQUALITY_TOLERANCE) ) { found = true; break; }
if ( (*it).IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) { found = true; break; }
}
if ( ! found ) non_neighbors.push_back(P2);
}
@@ -421,4 +423,70 @@ gp_Pnt IfcGeom::point_above_plane(const gp_Pln& pln, bool agree) {
} else {
return pln.Location().Translated(-pln.Axis().Direction());
}
}
static double deflection_tolerance = 0.001;
static double wire_creation_tolerance = 0.0001;
static double minimal_face_area = 0.000001;
static double point_equality_tolerance = 0.00001;
static double max_faces_to_sew = -1.0;
static double ifc_length_unit = 1.0;
static double ifc_planeangle_unit = -1.0;
static double force_ccw_face_orientation = -1.0;
void IfcGeom::SetValue(GeomValue var, double value) {
switch (var) {
case GV_DEFLECTION_TOLERANCE:
deflection_tolerance = value;
break;
case GV_WIRE_CREATION_TOLERANCE:
wire_creation_tolerance = value;
break;
case GV_MINIMAL_FACE_AREA:
minimal_face_area = value;
break;
case GV_POINT_EQUALITY_TOLERANCE:
point_equality_tolerance = value;
break;
case GV_MAX_FACES_TO_SEW:
max_faces_to_sew = value;
break;
case GV_LENGTH_UNIT:
ifc_length_unit = value;
break;
case GV_PLANEANGLE_UNIT:
ifc_planeangle_unit = value;
break;
case GV_FORCE_CCW_FACE_ORIENTATION:
force_ccw_face_orientation = value;
break;
default:
assert(!"never reach here");
}
}
double IfcGeom::GetValue(GeomValue var) {
switch (var) {
case GV_DEFLECTION_TOLERANCE:
return deflection_tolerance;
case GV_WIRE_CREATION_TOLERANCE:
return wire_creation_tolerance;
case GV_MINIMAL_FACE_AREA:
return minimal_face_area;
case GV_POINT_EQUALITY_TOLERANCE:
return point_equality_tolerance;
case GV_MAX_FACES_TO_SEW:
return max_faces_to_sew;
case GV_LENGTH_UNIT:
return ifc_length_unit;
break;
case GV_PLANEANGLE_UNIT:
return ifc_planeangle_unit;
break;
case GV_FORCE_CCW_FACE_ORIENTATION:
return force_ccw_face_orientation;
break;
}
assert(!"never reach here");
return 0;
}
+5 -5
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -91,9 +91,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianPoint::ptr l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
std::vector<double> xyz = l->Coordinates();
point = gp_Pnt(
xyz.size() ? (xyz[0]*Ifc::LengthUnit) : 0.0f,
xyz.size() > 1 ? (xyz[1]*Ifc::LengthUnit) : 0.0f,
xyz.size() > 2 ? (xyz[2]*Ifc::LengthUnit) : 0.0f
xyz.size() ? (xyz[0]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 1 ? (xyz[1]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 2 ? (xyz[2]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f
);
CACHE(IfcCartesianPoint,l,point)
return true;
@@ -113,7 +113,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcVector::ptr l, gp_Vec& v) {
IN_CACHE(IfcVector,l,gp_Vec,v)
gp_Dir d;
IfcGeom::convert(l->Orientation(),d);
v = l->Magnitude() * Ifc::LengthUnit * d;
v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d;
CACHE(IfcVector,l,v)
return true;
}
+114 -19
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -51,9 +51,9 @@ bool convert_back_units = false;
bool use_faster_booleans = false;
int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
const float X = convert_back_units ? (float) (p.X() / Ifc::LengthUnit) : (float)p.X();
const float Y = convert_back_units ? (float) (p.Y() / Ifc::LengthUnit) : (float)p.Y();
const float Z = convert_back_units ? (float) (p.Z() / Ifc::LengthUnit) : (float)p.Z();
const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X();
const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y();
const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z();
int i = (int) verts.size() / 3;
if ( weld_vertices ) {
const VertKey key = VertKey(X,std::pair<float,float>(Y,Z));
@@ -71,6 +71,8 @@ int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
bool use_world_coords = false;
bool use_brep_data = false;
static IfcParse::IfcFile* ifc_file = 0;
IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
id = i;
@@ -102,10 +104,10 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
// Triangulate the shape
try {
//BRepTools::Clean(s);
BRepMesh::Mesh(s,DEFLECTION_TOLERANCE);
// BRepTools::Clean(s);
BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
} catch(...) {
Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate mesh:",ifc_file->EntityById(i)->entity);
continue;
}
TopExp_Explorer exp;
@@ -401,7 +403,7 @@ IfcGeomObjects::IfcGeomObject* _get() {
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
}
} catch(...) {
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",ifc_product->entity);
}
if ( use_world_coords ) {
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
@@ -452,7 +454,8 @@ bool IfcGeomObjects::Next() {
}
std::vector<IfcGeomObjects::IfcObject*> returned_objects;
bool IfcGeomObjects::CleanUp() {
Ifc::Dispose();
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
IfcGeom::Cache::Purge();
for ( std::vector<IfcGeomObjects::IfcObject*>::const_iterator it = returned_objects.begin();
it != returned_objects.end();
@@ -465,7 +468,7 @@ bool IfcGeomObjects::CleanUp() {
const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
IfcObject* ifc_object = 0;
try {
const IfcEntity& ifc_entity = Ifc::EntityById(id);
const IfcParse::IfcEntity& ifc_entity = ifc_file->EntityById(id);
if ( ifc_entity->is(Ifc2x3::Type::IfcProduct) ) {
Ifc2x3::IfcProduct::ptr ifc_product = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,Ifc2x3::IfcProduct>(ifc_entity);
int parent_id = -1;
@@ -488,11 +491,93 @@ const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() {
return current_geom_obj;
}
double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_EXA ) return (double) 1e18;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PETA ) return (double) 1e15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_TERA ) return (double) 1e12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_GIGA ) return (double) 1e9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MEGA ) return (double) 1e6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_KILO ) return (double) 1e3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_HECTO ) return (double) 1e2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECA ) return (double) 1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECI ) return (double) 1e-1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_CENTI ) return (double) 1e-2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MILLI ) return (double) 1e-3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MICRO ) return (double) 1e-6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_NANO ) return (double) 1e-9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PICO ) return (double) 1e-12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_FEMTO ) return (double) 1e-15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_ATTO ) return (double) 1e-18;
else return 1.0f;
}
void IfcGeomObjects::InitUnits() {
// Set default units, set length to meters, angles to undefined
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,1.0);
IfcGeom::SetValue(IfcGeom::GV_PLANEANGLE_UNIT,-1.0);
Ifc2x3::IfcUnitAssignment::list unit_assignments = ifc_file->EntitiesByType<Ifc2x3::IfcUnitAssignment>();
IfcUtil::IfcAbstractSelect::list units = IfcUtil::IfcAbstractSelect::list();
if ( unit_assignments->Size() ) {
Ifc2x3::IfcUnitAssignment::ptr unit_assignment = *unit_assignments->begin();
units = unit_assignment->Units();
}
if ( ! units ) {
// No units eh... Since tolerances and deflection are specified internally in meters
// we will try to find another indication of the model size.
Ifc2x3::IfcExtrudedAreaSolid::list extrusions = ifc_file->EntitiesByType<Ifc2x3::IfcExtrudedAreaSolid>();
if ( ! extrusions->Size() ) return;
double max_height = -1.0f;
for ( Ifc2x3::IfcExtrudedAreaSolid::it it = extrusions->begin(); it != extrusions->end(); ++ it ) {
const double depth = (*it)->Depth();
if ( depth > max_height ) max_height = depth;
}
if ( max_height > 100.0f ) IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,0.001);
return;
}
try {
for ( IfcUtil::IfcAbstractSelect::it it = units->begin(); it != units->end(); ++ it ) {
const IfcUtil::IfcAbstractSelect::ptr base = *it;
Ifc2x3::IfcSIUnit::ptr unit = Ifc2x3::IfcSIUnit::ptr();
double value = 1.0f;
if ( base->is(Ifc2x3::Type::IfcConversionBasedUnit) ) {
const Ifc2x3::IfcConversionBasedUnit::ptr u = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcConversionBasedUnit>(base);
const Ifc2x3::IfcMeasureWithUnit::ptr u2 = u->ConversionFactor();
Ifc2x3::IfcUnit u3 = u2->UnitComponent();
if ( u3->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = (Ifc2x3::IfcSIUnit*) u3;
}
Ifc2x3::IfcValue v = u2->ValueComponent();
IfcUtil::IfcArgumentSelect* v2 = (IfcUtil::IfcArgumentSelect*) v;
const double f = *v2->wrappedValue();
value *= f;
} else if ( base->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcSIUnit>(base);
}
if ( unit ) {
if ( unit->hasPrefix() ) {
value *= UnitPrefixToValue(unit->Prefix());
}
Ifc2x3::IfcUnitEnum::IfcUnitEnum type = unit->UnitType();
if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_LENGTHUNIT ) {
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,value);
} else if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) {
IfcGeom::SetValue(IfcGeom::GV_PLANEANGLE_UNIT,value);
}
}
}
} catch ( IfcException ex ) {
Logger::Message(Logger::LOG_ERROR,ex.what());
}
}
bool IfcGeomObjects::Init(const std::string fn) {
return IfcGeomObjects::Init(fn, 0, 0);
}
bool _Init() {
shapereps = Ifc::EntitiesByType<Ifc2x3::IfcShapeRepresentation>();
IfcGeomObjects::InitUnits();
shapereps = ifc_file->EntitiesByType<Ifc2x3::IfcShapeRepresentation>();
if ( ! shapereps ) return false;
outer = shapereps->begin();
@@ -506,18 +591,21 @@ bool _Init() {
return true;
}
bool IfcGeomObjects::Init(const std::string fn, std::ostream* log1, std::ostream* log2) {
Ifc::SetOutput(log1,log2);
if ( !Ifc::Init(fn) ) return false;
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(fn) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(std::istream& f, int len, std::ostream* log1, std::ostream* log2) {
Ifc::SetOutput(log1,log2);
if ( !Ifc::Init(f, len) ) return false;
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(f, len) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(void* data, int len) {
Ifc::SetOutput(0,0);
if ( !Ifc::Init(data, len) ) return false;
Logger::SetOutput(0,0);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(data, len) ) return false;
return _Init();
}
void IfcGeomObjects::Settings(int setting, bool value) {
@@ -538,7 +626,10 @@ void IfcGeomObjects::Settings(int setting, bool value) {
use_faster_booleans = value;
break;
case SEW_SHELLS:
Ifc::SewShells = value;
IfcGeom::SetValue(IfcGeom::GV_MAX_FACES_TO_SEW,value ? 1000 : -1);
break;
case IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION:
IfcGeom::SetValue(IfcGeom::GV_FORCE_CCW_FACE_ORIENTATION,value ? 1 : -1);
break;
}
}
@@ -546,5 +637,9 @@ int IfcGeomObjects::Progress() {
return 100 * done / total;
}
std::string IfcGeomObjects::GetLog() {
return Ifc::GetLog();
return Logger::GetLog();
}
IfcParse::IfcFile* IfcGeomObjects::GetFile() {
return ifc_file;
}
+6 -2
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -94,6 +94,9 @@ namespace IfcGeomObjects {
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
const int FASTER_BOOLEANS = 6;
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise set this to true.
const int FORCE_CCW_FACE_ORIENTATION = 7;
// End of settings enumeration.
@@ -143,6 +146,7 @@ namespace IfcGeomObjects {
IfcGeomObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf, IfcMesh* m);
};
void InitUnits();
bool Init(const std::string fn);
bool Init(void* data, int len);
bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0);
@@ -154,7 +158,7 @@ namespace IfcGeomObjects {
int Progress();
const IfcObject* GetObject(int id);
std::string GetLog();
IfcParse::IfcFile* GetFile();
}
#endif
+17 -17
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -81,7 +81,7 @@
bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * Ifc::LengthUnit;
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
@@ -158,11 +158,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty solid for:",l->FirstOperand()->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
shape = s1;
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
return true;
}
@@ -176,7 +176,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( ! is_halfspace ) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty solid for:",operand2->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
}
bool valid_cut = false;
@@ -211,7 +211,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( is_valid ) {
shape = result;
valid_cut = true;
Ifc::LogMessage("Warning","Slightly nudged the SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Slightly nudged the SecondOperand of:",l->entity);
}
}
}
@@ -281,9 +281,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
shape = s1;
}
@@ -294,18 +294,18 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
Ifc2x3::IfcFace::list faces = l->CfsFaces();
bool facesAdded = false;
const unsigned int num_faces = faces->Size();
if ( Ifc::SewShells && num_faces < MAX_FACES_TO_SEW ) {
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetMaxTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetMinTolerance(POINT_EQUALITY_TOLERANCE);
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
if ( IfcGeom::convert_face(*it,face) && face_area(face) > MINIMAL_FACE_AREA ) {
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
} else {
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
@@ -313,7 +313,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
shape = builder.SewedShape();
try {
ShapeFix_Solid solid;
solid.LimitTolerance(POINT_EQUALITY_TOLERANCE);
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
shape = solid.SolidFromShell(TopoDS::Shell(shape));
} catch(...) {}
} else {
@@ -322,11 +322,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
builder.MakeCompound(compound);
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
if ( IfcGeom::convert_face(*it,face) && face_area(face) > MINIMAL_FACE_AREA ) {
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
+115 -62
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -83,27 +83,60 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire) {
if ( ! Ifc::hasPlaneAngleUnit ) {
Ifc::LogMessage("Warning","Creating a composite curve without unit information:",l->entity);
Ifc::hasPlaneAngleUnit = true;
if ( IfcGeom::GetValue(GV_PLANEANGLE_UNIT)<0 ) {
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
// Temporarily pretend we do have unit information
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,1.0);
bool succes_radians = false;
bool succes_degrees = false;
bool use_radians = false;
bool use_degrees = false;
// First try radians
Ifc::PlaneAngleUnit = 1.0f;
bool succes_radians = IfcGeom::convert(l,wire);
bool succes_degrees;
if ( succes_radians ) {
Ifc::LogMessage("Notice","Used radians to create composite curve");
} else {
// Now try degrees
Ifc::PlaneAngleUnit = 0.0174532925199433f;
succes_degrees = IfcGeom::convert(l,wire);
if ( succes_degrees ) {
Ifc::LogMessage("Notice","Used degrees to create composite curve");
TopoDS_Wire wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::convert(l,wire_radians);
} catch (...) {}
// Now try degrees
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::convert(l,wire_degrees);
} catch (...) {}
// Restore to unknown unit state
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,-1.0);
if ( succes_degrees && ! succes_radians ) {
use_degrees = true;
} else if ( succes_radians && ! succes_degrees ) {
use_radians = true;
} else if ( succes_radians && succes_degrees ) {
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
use_degrees = true;
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
use_radians = true;
} else {
// No heuristic left to prefer the one over the other,
// apparently both variants are equally succesful.
// The curve might be composed of only straight segments.
// Let's go with the wire created using radians as that
// at least is a SI unit.
use_radians = true;
}
// Restore to radians
Ifc::PlaneAngleUnit = 1.0f;
}
Ifc::hasPlaneAngleUnit = false;
return succes_radians || succes_degrees;
if ( use_radians ) {
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
wire = wire_radians;
} else if ( use_degrees ) {
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
wire = wire_degrees;
}
return use_radians || use_degrees;
}
Ifc2x3::IfcCompositeCurveSegment::list segments = l->Segments();
BRepBuilderAPI_MakeWire w;
@@ -112,12 +145,12 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
const Ifc2x3::IfcCurve::ptr curve = (*it)->ParentCurve();
TopoDS_Wire wire2;
if ( ! IfcGeom::convert_wire(curve,wire2) ) {
Ifc::LogMessage("Error","Failed to convert curve:",curve->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire2, WIRE_CREATION_TOLERANCE, TopAbs_WIRE);
FTol.SetTolerance(wire2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
/*if ( it != segments->begin() ) {
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
@@ -131,7 +164,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
return false;
}
}
@@ -141,7 +174,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
Ifc2x3::IfcCurve::ptr basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(Ifc2x3::Type::IfcConic);
double parameterFactor = isConic ? Ifc::PlaneAngleUnit : Ifc::LengthUnit;
double parameterFactor = isConic ? IfcGeom::GetValue(GV_PLANEANGLE_UNIT) : IfcGeom::GetValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
@@ -149,53 +182,73 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
bool sense_agreement = l->SenseAgreement();
double flt1;
gp_Pnt pnt1;
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(Ifc2x3::Type::IfcCartesianPoint) && trim_cartesian ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt1 );
trimmed1 = true;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian ) {
if ( i->is(Ifc2x3::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) ) {
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
flt1 = value * parameterFactor;
trimmed1 = true;
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcUtil::IfcAbstractSelect::it it = trims2->begin(); it != trims2->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(Ifc2x3::Type::IfcCartesianPoint) && trim_cartesian && trimmed1 ) {
gp_Pnt pnt2;
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt2 );
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
w.Add(BRepBuilderAPI_MakeEdge(sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1));
Ifc::LogMessage("Warning","Point projection failed for:",l->entity);
}
} else {
w.Add(e.Edge());
}
trimmed2 = true;
break;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian && trimmed1 ) {
if ( i->is(Ifc2x3::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) ) {
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
double flt2 = value * parameterFactor;
if ( isConic && ALMOST_THE_SAME(fmod(flt2-flt1,(double)(M_PI*2.0)),0.0f) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? flt1 : flt2,sense_agreement ? flt2 : flt1);
w.Add(e.Edge());
}
trimmed2 = true;
break;
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
}
if ( trimmed2 ) wire = w.Wire();
return trimmed2;
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < GetValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
trim_cartesian_failed = true;
}
} else {
w.Add(e.Edge());
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
w.Add(e.Edge());
}
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
}
if ( w.IsDone() ) {
wire = w.Wire();
return true;
} else {
return false;
}
}
bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
Ifc2x3::IfcCartesianPoint::list points = l->Points();
@@ -204,7 +257,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
gp_Pnt P1;gp_Pnt P2;
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( !P1.IsEqual(P2,POINT_EQUALITY_TOLERANCE) ) )
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
P1 = P2;
}
@@ -220,13 +273,13 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
int count = 0;
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( !P1.IsEqual(P2,POINT_EQUALITY_TOLERANCE) ) ) {
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
count ++;
} else if ( ! count ) F = P2;
P1 = P2;
}
if ( !P1.IsEqual(F,POINT_EQUALITY_TOLERANCE) ) {
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
count ++;
}
+6 -6
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -33,7 +33,7 @@ using namespace IfcUtil;
bool IfcGeom::convert_shapes(const IfcBaseClass* l, ShapeList& r) {
#include "IfcRegisterConvertShapes.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
@@ -45,21 +45,21 @@ const TopoDS_Shape* IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape&
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
if ( it != Cache::Shape.end() ) { r = it->second; return &(it->second); }
#include "IfcRegisterConvertShape.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return 0;
}
bool IfcGeom::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
#include "IfcRegisterConvertWire.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Face& r) {
#include "IfcRegisterConvertFace.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
#include "IfcRegisterConvertCurve.h"
Ifc::LogMessage("Error","No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
+2 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -38,6 +38,7 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
using namespace Ifc2x3;
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define CURVE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define FACE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
+3 -3
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( l->is(T::Class()) ) { \
try { \
@@ -7,8 +7,8 @@
return &(Cache::Shape[id]); \
} \
} catch(...) { } \
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
return false; \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return 0; \
}
#include "IfcRegisterDef.h"
+2 -2
View File
@@ -1,10 +1,10 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) { \
try { \
return IfcGeom::convert((T*)l,r); \
} catch (...) { } \
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define CLASS(T,V) \
std::map<int,V> T;
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef SHAPES
#ifndef SHAPES
#define SHAPES(T)
#endif
#ifndef SHAPE
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define CLASS(T,V) bool convert(const T::ptr L, V& r);
#define SHAPES(T) CLASS(T,ShapeList)
#define SHAPE(T) CLASS(T,TopoDS_Shape)
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) return true;
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#include "IfcRegisterUndef.h"
#include "IfcRegisterUndef.h"
#define CLASS(T,V) \
T.clear();
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#ifdef SHAPES
#ifdef SHAPES
#undef SHAPES
#endif
#ifdef SHAPE
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -1,4 +1,4 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_ifcopenshell_IfcOpenShellModel */
+31 -12
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -17,9 +17,9 @@
* *
********************************************************************************/
#include "Max.h"
#include "stdmat.h"
#include "istdplug.h"
#include <Max.h>
#include <stdmat.h>
#include <istdplug.h>
#include "../ifcmax/IfcMax.h"
#include "../ifcmax/MaxMaterials.h"
@@ -103,13 +103,21 @@ DWORD WINAPI fn(LPVOID arg) { return 0; }
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
itfc->ProgressStart("Importing file...", TRUE, fn, NULL);
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true);
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
if ( ! IfcGeomObjects::Init((char*)name,0,0) ) return false;
#ifdef _UNICODE
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
char* fn_mb = new char[fn_buffer_size];
WideCharToMultiByte(CP_UTF8, 0, name, -1, fn_mb, fn_buffer_size, 0, 0);
#else
const char* fn_mb = name;
#endif
if ( ! IfcGeomObjects::Init(fn_mb,0,0) ) return false;
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
//std::map<int, TriObject*> dict;
MtlBaseLib* mats = itfc->GetSceneMtls();
@@ -117,14 +125,25 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
do{
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
#if MAX_RELEASE > 14000
TSTR o_type = TSTR::FromCStr(o->type.c_str());
TSTR o_guid = TSTR::FromCStr(o->guid.c_str());
#elif defined(_UNICODE)
TSTR o_type = WStr(o->type.c_str());
TSTR o_guid = WStr(o->guid.c_str());
#else
TSTR o_type = CStr(o->type.c_str());
TSTR o_guid = CStr(o->guid.c_str());
#endif
Mtl *m;
const int matIndex = mats->FindMtlByName(MSTR(o->type.c_str()));
const int matIndex = mats->FindMtlByName(o_type);
if ( matIndex == -1 ) {
StdMat2* stdm = GetMaterial(o->type);
m = stdm;
m->SetName(o->type.c_str());
m->SetName(o_type);
mats->Add(m);
itfc->PutMtlToMtlEditor(m,slot++);
} else {
@@ -169,13 +188,13 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
ImpNode* node = impitfc->CreateNode();
node->Reference(tri);
node->SetName(o->guid.c_str());
node->SetName(o_guid);
node->GetINode()->SetMtl(m);
node->SetTransform(0,Matrix3 ( Point3(o->matrix[0],o->matrix[1],o->matrix[2]),Point3(o->matrix[3],o->matrix[4],o->matrix[5]),
Point3(o->matrix[6],o->matrix[7],o->matrix[8]),Point3(o->matrix[9],o->matrix[10],o->matrix[11]) ));
impitfc->AddNodeToScene(node);
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,"");
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T(""));
} while ( IfcGeomObjects::Next() );
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+2 -2
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -70,7 +70,7 @@ int main ( int argc, char** argv ) {
std::cout << "Creating geometry..." << std::endl;
// The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file.
// IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcObjects.h for definition)
// IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcGeomObjects.h for definition)
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
int vcount_total = 1;
do {
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../IfcObj/Materials.h"
#include "../IfcObj/Materials.h"
void InitMaterials() {
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+1443 -1443
View File
File diff suppressed because it is too large Load Diff
+1556 -1556
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+56 -12
View File
@@ -87,20 +87,35 @@ void IfcCharacterDecoder::addChar(std::stringstream& s,const UChar32& ch) {
s.put(substitution_character);
#endif
}
IfcCharacterDecoder::IfcCharacterDecoder(IfcParse::File* f) {
file = f;
IfcCharacterDecoder::IfcCharacterDecoder(IfcParse::IfcSpfStream* f) {
file = f;
#ifdef HAVE_ICU
if ( ! destination && mode == UTF8 ) {
destination = ucnv_open("utf-8", &status);
} else if ( ! destination && mode == LATIN ) {
destination = ucnv_open("iso-8859-1", &status);
}
if (destination) ucnv_close(destination);
if (compatibility_converter) ucnv_close(compatibility_converter);
destination = 0;
compatibility_converter = 0;
if (mode == DEFAULT) {
destination = ucnv_open(0, &status);
} else if (mode == UTF8) {
destination = ucnv_open("utf-8", &status);
} else if (mode == LATIN) {
destination = ucnv_open("iso-8859-1", &status);
}
if (compatibility_charset.empty()) {
compatibility_charset = ucnv_getDefaultName();
}
compatibility_converter = ucnv_open(compatibility_charset.c_str(), &status);
#endif
}
IfcCharacterDecoder::~IfcCharacterDecoder() {
#ifdef HAVE_ICU
if ( destination ) ucnv_close(destination);
if ( converter ) ucnv_close(converter);
if ( destination ) ucnv_close(destination);
if ( converter ) ucnv_close(converter);
if ( compatibility_converter ) ucnv_close(compatibility_converter);
destination = 0;
converter = 0;
compatibility_converter = 0;
#endif
}
IfcCharacterDecoder::operator std::string() {
@@ -111,6 +126,9 @@ IfcCharacterDecoder::operator std::string() {
int codepage = 1;
unsigned int hex = 0;
unsigned int hex_count = 0;
#ifdef HAVE_ICU
unsigned int old_hex = 0; // for compatibility_mode
#endif
while ( current_char = file->Peek() ) {
if ( EXPECTS_CHARACTER(parse_state) ) {
#ifdef HAVE_ICU
@@ -164,7 +182,24 @@ IfcCharacterDecoder::operator std::string() {
if ( (hex_count == 2 && !(parse_state & EXTENDED2)) ||
(hex_count == 4 && !(parse_state & EXTENDED4)) ||
(hex_count == 8) ) {
addChar(s,(UChar32) hex);
#ifdef HAVE_ICU
if (compatibility_mode) {
if (old_hex == 0) {
old_hex = hex;
} else {
char characters[3] = { old_hex, hex };
const char* char_array = &characters[0];
UChar32 ch = ucnv_getNextUChar(compatibility_converter,&char_array,char_array+2,&status);
addChar(s,ch);
old_hex = 0;
}
}
else {
#endif
addChar(s,(UChar32) hex);
#ifdef HAVE_ICU
}
#endif
if ( hex_count == 2 ) parse_state = 0;
else CLEAR_HEX(parse_state);
hex = hex_count = 0;
@@ -177,8 +212,8 @@ IfcCharacterDecoder::operator std::string() {
throw IfcException("Invalid character encountered");
} else {
parse_state = hex = hex_count = 0;
// NOTE: this is in fact wrong, this ought to be the representation of the character.
// In UTF-8 this is the same, but we should not rely on that.
// NOTE: this is in fact wrong, this ought to be the representation of the character.
// In UTF-8 this is the same, but we should not rely on that.
s.put(current_char);
}
file->Inc();
@@ -246,9 +281,18 @@ void IfcCharacterDecoder::dryRun() {
#ifdef HAVE_ICU
UConverter* IfcCharacterDecoder::destination = 0;
UConverter* IfcCharacterDecoder::converter = 0;
UConverter* IfcCharacterDecoder::compatibility_converter = 0;
int IfcCharacterDecoder::previous_codepage = -1;
UErrorCode IfcCharacterDecoder::status = U_ZERO_ERROR;
#endif
#ifdef HAVE_ICU
IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::JSON;
// Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior
bool IfcCharacterDecoder::compatibility_mode = false;
std::string IfcCharacterDecoder::compatibility_charset = "";
#else
char IfcCharacterDecoder::substitution_character = '_';
#endif
+36 -28
View File
@@ -1,29 +1,29 @@
/********************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Implementation of character decoding as described in ISO 10303-21 table 2 and *
* table 4 *
* *
********************************************************************************/
* *
* Implementation of character decoding as described in ISO 10303-21 table 2 and *
* table 4 *
* *
********************************************************************************/
#ifndef IFCCHARACTERDECODER_H
#define IFCCHARACTERDECODER_H
@@ -42,22 +42,30 @@ namespace IfcParse {
class IfcCharacterDecoder {
private:
IfcParse::File* file;
IfcParse::IfcSpfStream* file;
#ifdef HAVE_ICU
static UConverter* destination;
static UConverter* converter;
static UConverter* compatibility_converter;
static int previous_codepage;
static UErrorCode status;
#endif
void addChar(std::stringstream& s,const UChar32& ch);
public:
#ifdef HAVE_ICU
enum ConversionMode {UTF8,LATIN,JSON,PYTHON};
enum ConversionMode {DEFAULT,UTF8,LATIN,JSON,PYTHON};
static ConversionMode mode;
// Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior to encode characters.
// It just translate to extended string in system default code page, not unicode.
// If you want to process these strings, set true.
static bool compatibility_mode;
static std::string compatibility_charset;
#else
static char substitution_character;
#endif
IfcCharacterDecoder(IfcParse::File* file);
IfcCharacterDecoder(IfcParse::IfcSpfStream* file);
~IfcCharacterDecoder();
void dryRun();
operator std::string();
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+9 -9
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -34,21 +34,21 @@
// loads a file on disk into multiple chunks, has been disabled.
// It proved to be an inefficient way of working with large files,
// as often these did not facilitate to be parsed in a sequential
// manner efficiently, to enable the paging functionality uncomment
// manner efficiently. To enable the paging functionality uncomment
// the following statement.
//const int BUF_SIZE = (128 * 1024 * 1024);
// #define BUF_SIZE (8 * 1024 * 1024)
namespace IfcParse {
/// The File class represents a ISO 10303-21 IFC-SPF file in memory.
/// The IfcSpfStream class represents a ISO 10303-21 IFC-SPF file in memory.
/// The file is interpreted as a sequence of tokens which are lazily
/// interpreted only when requested. If the size of the file is
/// larger than BUF_SIZE, the file is split into seperate pages, of
/// which only one is simultaneously kept in memory, for files
/// that define their entities not in a sequential nature, this is
/// detrimental for the performance of the parser.
class File {
class IfcSpfStream {
private:
std::ifstream stream;
FILE* stream;
char* buffer;
unsigned int ptr;
unsigned int len;
@@ -61,9 +61,9 @@ namespace IfcParse {
bool valid;
bool eof;
unsigned int size;
File(const std::string& fn);
File(std::istream& f, int len);
File(void* data, int len);
IfcSpfStream(const std::string& fn);
IfcSpfStream(std::istream& f, int len);
IfcSpfStream(void* data, int len);
/// Returns the character at the cursor
char Peek();
/// Returns the character at specified offset
+152 -237
View File
@@ -22,6 +22,10 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#include <Windows.h>
#endif
#include "../ifcparse/IfcCharacterDecoder.h"
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcException.h"
@@ -33,17 +37,25 @@ using namespace IfcParse;
//
// Opens the file, gets the filesize and reads a chunk in memory
//
File::File(const std::string& fn) {
IfcSpfStream::IfcSpfStream(const std::string& fn) {
eof = false;
stream.open(fn.c_str(),std::ios_base::binary);
if ( ! stream.good() ) {
#ifdef _MSC_VER
int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0);
wchar_t* fn_wide = new wchar_t[fn_buffer_size];
MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, fn_wide, fn_buffer_size);
stream = _wfopen(fn_wide, L"rb");
delete[] fn_wide;
#else
stream = fopen(fn.c_str(), "rb");
#endif
if (stream == NULL) {
valid = false;
return;
}
valid = true;
stream.seekg(0,std::ios_base::end);
size = (unsigned int) stream.tellg();
stream.seekg(0,std::ios_base::beg);
fseek(stream, 0, SEEK_END);
size = (unsigned int) ftell(stream);;
rewind(stream);
#ifdef BUF_SIZE
offset = 0;
paging = size > BUF_SIZE;
@@ -56,7 +68,7 @@ File::File(const std::string& fn) {
ReadBuffer(false);
}
File::File(std::istream& f, int l) {
IfcSpfStream::IfcSpfStream(std::istream& f, int l) {
eof = false;
size = l;
#ifdef BUF_SIZE
@@ -70,7 +82,7 @@ File::File(std::istream& f, int l) {
len = l;
}
File::File(void* data, int l) {
IfcSpfStream::IfcSpfStream(void* data, int l) {
eof = false;
size = l;
#ifdef BUF_SIZE
@@ -83,37 +95,43 @@ File::File(void* data, int l) {
len = l;
}
void File::Close() {
stream.close();
void IfcSpfStream::Close() {
#ifdef BUF_SIZE
if ( paging ) fclose(stream);
#endif
delete[] buffer;
}
//
// Reads a chunk of BUF_SIZE in memory and increments cursor if requested
//
void File::ReadBuffer(bool inc) {
void IfcSpfStream::ReadBuffer(bool inc) {
#ifdef BUF_SIZE
if ( inc ) {
offset += len;
stream.seekg(offset,std::ios_base::beg);
fseek(stream, offset, SEEK_SET);
}
#endif
eof = stream.eof();
eof = feof(stream) != 0;
if ( eof ) return;
#ifdef BUF_SIZE
stream.read(buffer,size < BUF_SIZE ? size : BUF_SIZE);
len = (unsigned int) fread(buffer, 1, size < BUF_SIZE ? size : BUF_SIZE, stream);
#else
stream.read(buffer,size);
len = (unsigned int) fread(buffer, 1, size, stream);
#endif
len = (unsigned int) stream.gcount();
eof = len == 0;
ptr = 0;
#ifdef BUF_SIZE
if (!paging) fclose(stream);
#else
fclose(stream);
#endif
}
//
// Seeks an arbitrary position in the file
//
void File::Seek(unsigned int o) {
void IfcSpfStream::Seek(unsigned int o) {
#ifdef BUF_SIZE
if ( !paging ) {
#endif
@@ -125,8 +143,8 @@ void File::Seek(unsigned int o) {
ptr = o - offset;
} else {
offset = o;
stream.clear();
stream.seekg(o,std::ios_base::beg);
clearerr(stream);
fseek(stream, o, SEEK_SET);
ReadBuffer(false);
}
#endif
@@ -135,14 +153,14 @@ void File::Seek(unsigned int o) {
//
// Returns the character at the cursor
//
char File::Peek() {
char IfcSpfStream::Peek() {
return buffer[ptr];
}
//
// Returns the character at specified offset
//
char File::Read(unsigned int o) {
char IfcSpfStream::Read(unsigned int o) {
#ifdef BUF_SIZE
if ( ! paging ) {
#endif
@@ -151,9 +169,9 @@ char File::Read(unsigned int o) {
} else if ( o >= offset && (o < (offset+len)) ) {
return buffer[o-offset];
} else {
stream.clear();
stream.seekg(o,std::ios_base::beg);
return stream.peek();
clearerr(stream);
fseek(stream, o, SEEK_SET);
return ungetc(getc(stream), stream);
}
#endif
}
@@ -161,7 +179,7 @@ char File::Read(unsigned int o) {
//
// Returns the cursor position
//
unsigned int File::Tell() {
unsigned int IfcSpfStream::Tell() {
#ifdef BUF_SIZE
return offset + ptr;
#else
@@ -172,7 +190,7 @@ unsigned int File::Tell() {
//
// Increments cursor and reads new chunk if necessary
//
void File::Inc() {
void IfcSpfStream::Inc() {
if ( ++ptr == len ) {
#ifdef BUF_SIZE
if ( paging ) ReadBuffer();
@@ -184,13 +202,14 @@ void File::Inc() {
}
#endif
}
const char current = File::Peek();
if ( current == '\n' || current == '\r' ) File::Inc();
const char current = IfcSpfStream::Peek();
if ( current == '\n' || current == '\r' ) IfcSpfStream::Inc();
}
Tokens::Tokens(IfcParse::File *f) {
Tokens::Tokens(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
file = f;
decoder = new IfcCharacterDecoder(f);
stream = s;
decoder = new IfcCharacterDecoder(s);
}
Tokens::~Tokens() {
@@ -202,38 +221,38 @@ Tokens::~Tokens() {
//
Token Tokens::Next() {
if ( file->eof ) return TokenPtr();
if ( stream->eof ) return TokenPtr();
char c;
// Trim whitespace
while ( !file->eof ) {
c = file->Peek();
if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) file->Inc();
while ( !stream->eof ) {
c = stream->Peek();
if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) stream->Inc();
else break;
}
if ( file->eof ) return TokenPtr();
unsigned int pos = file->Tell();
if ( stream->eof ) return TokenPtr();
unsigned int pos = stream->Tell();
bool inString = false;
bool inComment = false;
// If the cursor is at [()=,;$*] we know token consists of single char
if ( c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*' ) {
file->Inc();
stream->Inc();
return TokenPtr(c);
}
int len = 0;
char p = 0;
while ( ! file->eof ) {
while ( ! stream->eof ) {
// Read character and increment pointer if not starting a new token
char c = file->Peek();
char c = stream->Peek();
if ( len && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break;
file->Inc();
stream->Inc();
// Skip whitespace if not in comment or string
if ( !inComment && !inString && (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) continue;
@@ -247,7 +266,7 @@ Token Tokens::Next() {
p = c;
}
if ( len ) return TokenPtr(pos);
if ( len ) return TokenPtr(this,pos);
else return TokenPtr();
}
@@ -256,18 +275,18 @@ Token Tokens::Next() {
// Omits whitespace and comments
//
std::string Tokens::TokenString(unsigned int offset) {
const bool was_eof = file->eof;
unsigned int old_offset = file->Tell();
file->Seek(offset);
const bool was_eof = stream->eof;
unsigned int old_offset = stream->Tell();
stream->Seek(offset);
bool inString = false;
bool inComment = false;
std::string buffer;
buffer.reserve(128);
char p = 0;
while ( ! file->eof ) {
char c = file->Peek();
while ( ! stream->eof ) {
char c = stream->Peek();
if ( buffer.size() && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break;
file->Inc();
stream->Inc();
if ( !inComment && !inString && (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) continue;
if ( !inComment ) buffer.push_back(c);
if ( inComment && p == '*' && c == '/' ) inComment = false;
@@ -275,8 +294,8 @@ std::string Tokens::TokenString(unsigned int offset) {
else if ( !inComment && c == '\'' ) return *decoder;
p = c;
}
if ( was_eof ) file->eof = true;
else file->Seek(old_offset);
if ( was_eof ) stream->eof = true;
else stream->Seek(old_offset);
return buffer;
}
@@ -284,33 +303,32 @@ std::string Tokens::TokenString(unsigned int offset) {
// Functions for creating Tokens from an arbitary file offset.
// The first 4 bits are reserved for Tokens of type ()=,;$*
//
Token IfcParse::TokenPtr(unsigned int offset) { return offset + 128; }
Token IfcParse::TokenPtr(char c) { return c; }
Token IfcParse::TokenPtr() { return 0; }
Token IfcParse::TokenPtr(Tokens* tokens, unsigned int offset) { return Token(tokens,offset); }
Token IfcParse::TokenPtr(char c) { return Token((Tokens*)0,(unsigned) c); }
Token IfcParse::TokenPtr() { return Token((Tokens*)0,0); }
//
// Functions to convert Tokens to binary data
//
unsigned int TokenFunc::Offset(Token t) { return t - 128; }
bool TokenFunc::startsWith(Token t, char c) {
return Ifc::file->Read(Offset(t)) == c;
bool TokenFunc::startsWith(const Token& t, char c) {
return t.first->stream->Read(t.second) == c;
}
bool TokenFunc::isOperator(Token t, char op) {
return (t < 128) && (!op || op == t);
bool TokenFunc::isOperator(const Token& t, char op) {
return (!t.first) && (!op || op == t.second);
}
bool TokenFunc::isIdentifier(Token t) {
bool TokenFunc::isIdentifier(const Token& t) {
return ! isOperator(t) && startsWith(t, '#');
}
bool TokenFunc::isString(Token t) {
bool TokenFunc::isString(const Token& t) {
return ! isOperator(t) && startsWith(t, '\'');
}
bool TokenFunc::isEnumeration(Token t) {
bool TokenFunc::isEnumeration(const Token& t) {
return ! isOperator(t) && startsWith(t, '.');
}
bool TokenFunc::isDatatype(Token t) {
bool TokenFunc::isDatatype(const Token& t) {
return ! isOperator(t) && startsWith(t, 'I');
}
int TokenFunc::asInt(Token t) {
int TokenFunc::asInt(const Token& t) {
const std::string str = asString(t);
// In case of an ENTITY_INSTANCE_NAME skip the leading #
const char* start = str.c_str() + (isIdentifier(t) ? 1 : 0);
@@ -319,31 +337,31 @@ int TokenFunc::asInt(Token t) {
if ( start == end ) throw IfcException("Token is not an integer or identifier");
return (int) result;
}
bool TokenFunc::asBool(Token t) {
bool TokenFunc::asBool(const Token& t) {
const std::string str = asString(t);
return str == "T";
}
double TokenFunc::asFloat(Token t) {
double TokenFunc::asFloat(const Token& t) {
const std::string str = asString(t);
return (double) atof(str.c_str());
}
std::string TokenFunc::asString(Token t) {
std::string TokenFunc::asString(const Token& t) {
if ( isOperator(t,'$') ) return "";
else if ( isOperator(t) ) throw IfcException("Token is not a string");
std::string str = Ifc::tokens->TokenString(t - 128);
std::string str = t.first->TokenString(t.second);
return isString(t) || isEnumeration(t) ? str.substr(1,str.size()-2) : str;
}
std::string TokenFunc::toString(Token t) {
if ( isOperator(t) ) return std::string ( (char*) &t, 1 );
else return Ifc::tokens->TokenString(t - 128);
std::string TokenFunc::toString(const Token& t) {
if ( isOperator(t) ) return std::string ( (char*) &t.second , 1 );
else return t.first->TokenString(t.second);
}
TokenArgument::TokenArgument(Token t) {
TokenArgument::TokenArgument(const Token& t) {
token = t;
}
EntityArgument::EntityArgument(Ifc2x3::Type::Enum ty, Token t) {
EntityArgument::EntityArgument(Ifc2x3::Type::Enum ty, const Token& t) {
entity = new IfcUtil::IfcArgumentSelect(ty,new TokenArgument(t));
}
@@ -352,10 +370,11 @@ EntityArgument::EntityArgument(Ifc2x3::Type::Enum ty, Token t) {
// Aditionally, stores the ids (i.e. #[\d]+) in a vector
//
ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
while( Token next = t->Next() ) {
if ( TokenFunc::isOperator(next,',') ) continue;
if ( TokenFunc::isOperator(next,')') ) break;
if ( TokenFunc::isOperator(next,'(') ) Push( new ArgumentList(t,ids) );
Token next = t->Next();
while( next.second || next.first ) {
if ( TokenFunc::isOperator(next,',') ) {}
else if ( TokenFunc::isOperator(next,')') ) break;
else if ( TokenFunc::isOperator(next,'(') ) Push( new ArgumentList(t,ids) );
else {
if ( TokenFunc::isIdentifier(next) ) ids.push_back(TokenFunc::asInt(next));
if ( TokenFunc::isDatatype(next) ) {
@@ -363,13 +382,14 @@ ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
try {
Push ( new EntityArgument(Ifc2x3::Type::FromString(TokenFunc::asString(next)),t->Next()) );
} catch ( IfcException& e ) {
Ifc::LogMessage("Error",e.what());
Logger::Message(Logger::LOG_ERROR,e.what());
}
t->Next();
} else {
Push ( new TokenArgument(next) );
}
}
next = t->Next();
}
}
@@ -454,11 +474,7 @@ TokenArgument::operator std::string() const { return TokenFunc::asString(token);
TokenArgument::operator std::vector<double>() const { throw IfcException("Argument is not a list of floats"); }
TokenArgument::operator std::vector<int>() const { throw IfcException("Argument is not a list of ints"); }
TokenArgument::operator std::vector<std::string>() const { throw IfcException("Argument is not a list of strings"); }
TokenArgument::operator IfcUtil::IfcSchemaEntity() const { return Ifc::EntityById(TokenFunc::asInt(token)); }
/*TokenArgument::operator IfcUtil::IfcAbstractSelect::ptr() const {
//TODO Fix memory leak
return new IfcUtil::IfcEntitySelect(*this);
}*/
TokenArgument::operator IfcUtil::IfcSchemaEntity() const { return token.first->file->EntityById(TokenFunc::asInt(token)); }
TokenArgument::operator IfcEntities() const { throw IfcException("Argument is not a list of entities"); }
unsigned int TokenArgument::Size() const { return 1; }
ArgumentPtr TokenArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); }
@@ -496,19 +512,21 @@ EntityArgument::~EntityArgument() { delete entity; }
//
// Reads an Entity from the list of Tokens
//
Entity::Entity(unsigned int i, Tokens* t) {
Token datatype = t->Next();
Entity::Entity(unsigned int i, IfcFile* f) { //: file(f) {
file = f;
Token datatype = f->tokens->Next();
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = Ifc2x3::Type::FromString(TokenFunc::asString(datatype));
_id = i;
args = ArgumentPtr();
offset = TokenFunc::Offset(datatype);
offset = datatype.second;
}
//
// Reads an Entity from the list of Tokens at the specified offset in the file
//
Entity::Entity(unsigned int i, Tokens* t, unsigned int o) {
Entity::Entity(unsigned int i, IfcFile* f, unsigned int o) { // : file(f) {
file = f;
std::vector<unsigned int> ids;
_id = i;
offset = o;
@@ -539,16 +557,16 @@ unsigned int Entity::getArgumentCount() {
//
void Entity::Load(std::vector<unsigned int>& ids, bool seek) {
if ( seek ) {
Ifc::file->Seek(offset);
Token datatype = Ifc::tokens->Next();
file->tokens->stream->Seek(offset);
Token datatype = file->tokens->Next();
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = Ifc2x3::Type::FromString(TokenFunc::asString(datatype));
}
Token open = Ifc::tokens->Next();
args = new ArgumentList(Ifc::tokens, ids);
unsigned int old_offset = Ifc::file->Tell();
Token semilocon = Ifc::tokens->Next();
if ( ! TokenFunc::isOperator(semilocon,';') ) Ifc::file->Seek(old_offset);
Token open = file->tokens->Next();
args = new ArgumentList(file->tokens, ids);
unsigned int old_offset = file->tokens->stream->Tell();
Token semilocon = file->tokens->Next();
if ( ! TokenFunc::isOperator(semilocon,';') ) file->tokens->stream->Seek(old_offset);
}
Ifc2x3::Type::Enum Entity::type() const {
@@ -589,7 +607,7 @@ Entity::~Entity() {
//
IfcEntities Entity::getInverse(Ifc2x3::Type::Enum c) {
IfcEntities l = IfcEntities(new IfcEntityList());
IfcEntities all = Ifc::EntitiesByReference(_id);
IfcEntities all = file->EntitiesByReference(_id);
if ( ! all ) return l;
for( IfcEntityList::it it = all->begin(); it != all->end();++ it ) {
if ( c == Ifc2x3::Type::ALL || (*it)->is(c) ) {
@@ -612,44 +630,55 @@ IfcEntities Entity::getInverse(Ifc2x3::Type::Enum c, int i, const std::string& a
bool Entity::is(Ifc2x3::Type::Enum v) const { return _type == v; }
unsigned int Entity::id() { return _id; }
IfcFile::IfcFile() {
file = 0;
lastId = 0;
tokens = 0;
MaxId = 0;
}
//
// Parses the IFC file in fn
// Creates the maps
// Gets the unit definitins from the file
//
bool Ifc::Init(const std::string& fn) {
return Ifc::Init(new File(fn));
bool IfcFile::Init(const std::string& fn) {
return IfcFile::Init(new IfcSpfStream(fn));
}
bool Ifc::Init(std::istream& f, int len) {
return Ifc::Init(new File(f,len));
bool IfcFile::Init(std::istream& f, int len) {
return IfcFile::Init(new IfcSpfStream(f,len));
}
bool Ifc::Init(void* data, int len) {
return Ifc::Init(new File(data,len));
bool IfcFile::Init(void* data, int len) {
return IfcFile::Init(new IfcSpfStream(data,len));
}
bool Ifc::Init(IfcParse::File* f) {
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
Ifc2x3::InitStringMap();
file = f;
if ( ! file->valid ) return false;
tokens = new Tokens (file);
Token token = 0;
Token previous = 0;
tokens = new Tokens (file,this);
Token token = TokenPtr();
Token previous = TokenPtr();
unsigned int currentId = 0;
lastId = 0;
int x = 0;
EntityPtr e;
IfcUtil::IfcSchemaEntity entity = 0;
if ( log1 ) std::cout << "Scanning file..." << std::endl;
Logger::Status("Scanning file...");
while ( ! file->eof ) {
if ( currentId ) {
try {
e = new Entity(currentId,tokens);
e = new Entity(currentId,this);
entity = Ifc2x3::SchemaEntity(e);
} catch (IfcException ex) {
currentId = 0;
Ifc::LogMessage("Error",ex.what());
Logger::Message(Logger::LOG_ERROR,ex.what());
continue;
}
if ( log1 && !((++x)%1000) ) std::cout << "\r#" << currentId << " " << std::flush;
// Update the status after every 1000 instances parsed
if ( !((++x)%1000) ) {
std::stringstream ss; ss << "\r#" << currentId;
Logger::Status(ss.str(), false);
}
if ( entity->is(Ifc2x3::Type::IfcRoot) ) {
Ifc2x3::IfcRoot::ptr ifc_root = (Ifc2x3::IfcRoot::ptr) entity;
try {
@@ -657,11 +686,11 @@ bool Ifc::Init(IfcParse::File* f) {
if ( byguid.find(guid) != byguid.end() ) {
std::stringstream ss;
ss << "Overwriting entity with guid " << guid;
Ifc::LogMessage("Warning",ss.str());
Logger::Message(Logger::LOG_WARNING,ss.str());
}
byguid[guid] = ifc_root;
} catch (IfcException ex) {
Ifc::LogMessage("Error",ex.what());
Logger::Message(Logger::LOG_ERROR,ex.what());
}
}
Ifc2x3::Type::Enum ty = entity->type();
@@ -677,16 +706,16 @@ bool Ifc::Init(IfcParse::File* f) {
if ( byid.find(currentId) != byid.end() ) {
std::stringstream ss;
ss << "Overwriting entity with id " << currentId;
Ifc::LogMessage("Warning",ss.str());
Logger::Message(Logger::LOG_WARNING,ss.str());
}
byid[currentId] = entity;
currentId = 0;
} else {
try { token = tokens->Next(); }
catch (... ) { token = 0; }
catch (... ) { token = TokenPtr(); }
}
if ( ! token ) break;
if ( previous && TokenFunc::isIdentifier(previous) ) {
if ( ! (token.second || token.first) ) break;
if ( (previous.second || previous.first) && TokenFunc::isIdentifier(previous) ) {
int id = TokenFunc::asInt(previous);
if ( TokenFunc::isOperator(token,'=') ) {
currentId = id;
@@ -701,88 +730,32 @@ bool Ifc::Init(IfcParse::File* f) {
}
previous = token;
}
if ( log1 ) std::cout << "\rDone scanning file " << std::endl;
Ifc2x3::IfcUnitAssignment::list unit_assignments = EntitiesByType<Ifc2x3::IfcUnitAssignment>();
IfcUtil::IfcAbstractSelect::list units = IfcUtil::IfcAbstractSelect::list();
if ( unit_assignments->Size() ) {
Ifc2x3::IfcUnitAssignment::ptr unit_assignment = *unit_assignments->begin();
units = unit_assignment->Units();
}
if ( ! units ) {
// No units eh... Since tolerances and deflection are specified internally in meters
// we will try to find another indication of the model size.
Ifc2x3::IfcExtrudedAreaSolid::list extrusions = EntitiesByType<Ifc2x3::IfcExtrudedAreaSolid>();
if ( ! extrusions->Size() ) return true;
double max_height = -1.0f;
for ( Ifc2x3::IfcExtrudedAreaSolid::it it = extrusions->begin(); it != extrusions->end(); ++ it ) {
const double depth = (*it)->Depth();
if ( depth > max_height ) max_height = depth;
}
if ( max_height > 100.0f ) Ifc::LengthUnit = 0.001f;
return true;
}
try {
for ( IfcUtil::IfcAbstractSelect::it it = units->begin(); it != units->end(); ++ it ) {
const IfcUtil::IfcAbstractSelect::ptr base = *it;
Ifc2x3::IfcSIUnit::ptr unit = Ifc2x3::IfcSIUnit::ptr();
double value = 1.0f;
if ( base->is(Ifc2x3::Type::IfcConversionBasedUnit) ) {
const Ifc2x3::IfcConversionBasedUnit::ptr u = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcConversionBasedUnit>(base);
const Ifc2x3::IfcMeasureWithUnit::ptr u2 = u->ConversionFactor();
Ifc2x3::IfcUnit u3 = u2->UnitComponent();
if ( u3->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = (Ifc2x3::IfcSIUnit*) u3;
}
Ifc2x3::IfcValue v = u2->ValueComponent();
IfcUtil::IfcArgumentSelect* v2 = (IfcUtil::IfcArgumentSelect*) v;
const double f = *v2->wrappedValue();
value *= f;
} else if ( base->is(Ifc2x3::Type::IfcSIUnit) ) {
unit = reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcSIUnit>(base);
}
if ( unit ) {
if ( unit->hasPrefix() ) {
value *= UnitPrefixToValue(unit->Prefix());
}
Ifc2x3::IfcUnitEnum::IfcUnitEnum type = unit->UnitType();
if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_LENGTHUNIT ) {
Ifc::LengthUnit = value;
} else if ( type == Ifc2x3::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) {
Ifc::PlaneAngleUnit = value;
Ifc::hasPlaneAngleUnit = true;
}
}
}
} catch ( IfcException ex ) {
Ifc::LogMessage("Error",ex.what());
}
Logger::Status("\rDone scanning file ");
return true;
}
IfcEntities Ifc::EntitiesByType(Ifc2x3::Type::Enum t) {
IfcEntities IfcFile::EntitiesByType(Ifc2x3::Type::Enum t) {
MapEntitiesByType::const_iterator it = bytype.find(t);
return (it == bytype.end()) ? IfcEntities() : it->second;
}
IfcEntities Ifc::EntitiesByReference(int t) {
IfcEntities IfcFile::EntitiesByReference(int t) {
MapEntitiesByRef::const_iterator it = byref.find(t);
return (it == byref.end()) ? IfcEntities() : it->second;
}
IfcUtil::IfcSchemaEntity Ifc::EntityById(int id) {
IfcUtil::IfcSchemaEntity IfcFile::EntityById(int id) {
MapEntityById::const_iterator it = byid.find(id);
if ( it == byid.end() ) {
MapOffsetById::const_iterator it2 = offsets.find(id);
if ( it2 == offsets.end() ) throw IfcException("Entity not found");
const unsigned int offset = (*it2).second;
EntityPtr e = EntityPtr(new Entity(id,Ifc::tokens,offset));
EntityPtr e = EntityPtr(new Entity(id,this,offset));
IfcUtil::IfcSchemaEntity entity = Ifc2x3::SchemaEntity(e);
byid[id] = entity;
return entity;
}
return it->second;
}
Ifc2x3::IfcRoot::ptr Ifc::EntityByGuid(const std::string& guid) {
Ifc2x3::IfcRoot::ptr IfcFile::EntityByGuid(const std::string& guid) {
MapEntityByGuid::const_iterator it = byguid.find(guid);
if ( it == byguid.end() ) {
throw IfcException("Entity not found");
@@ -795,77 +768,19 @@ IfcException::IfcException(std::string e) { error = e; }
IfcException::~IfcException() throw () {}
const char* IfcException::what() const throw() { return error.c_str(); }
void Ifc::Dispose() {
// FIXME: Test destructor to delete entity and arg allocations
IfcFile::~IfcFile() {
for( MapEntityById::const_iterator it = byid.begin(); it != byid.end(); ++ it ) {
delete it->second->entity;
delete it->second;
}
bytype.clear();
byid.clear();
byref.clear();
file->Close();
delete file;
delete tokens;
offsets.clear();
log_stream.str("");
}
double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_EXA ) return (double) 1e18;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PETA ) return (double) 1e15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_TERA ) return (double) 1e12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_GIGA ) return (double) 1e9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MEGA ) return (double) 1e6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_KILO ) return (double) 1e3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_HECTO ) return (double) 1e2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECA ) return (double) 1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_DECI ) return (double) 1e-1;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_CENTI ) return (double) 1e-2;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MILLI ) return (double) 1e-3;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_MICRO ) return (double) 1e-6;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_NANO ) return (double) 1e-9;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PICO ) return (double) 1e-12;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_FEMTO ) return (double) 1e-15;
else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_ATTO ) return (double) 1e-18;
else return 1.0f;
}
void Ifc::SetOutput(std::ostream* l1, std::ostream* l2) {
log1 = l1;
log2 = l2;
if ( ! log2 ) {
log2 = &log_stream;
}
}
void Ifc::LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity) {
if ( log2 ) {
(*log2) << "[" << type << "] " << message << std::endl;
if ( entity ) (*log2) << entity->toString() << std::endl;
}
}
std::string Ifc::GetLog() {
return log_stream.str();
}
MapEntityById::const_iterator Ifc::First() {
MapEntityById::const_iterator IfcFile::begin() const {
return byid.begin();
}
MapEntityById::const_iterator Ifc::Last() {
MapEntityById::const_iterator IfcFile::end() const {
return byid.end();
}
File* Ifc::file = 0;
std::ostream* Ifc::log1 = 0;
std::ostream* Ifc::log2 = 0;
unsigned int Ifc::lastId = 0;
Tokens* Ifc::tokens = 0;
double Ifc::LengthUnit = 1.0f;
double Ifc::PlaneAngleUnit = 1.0f;
bool Ifc::hasPlaneAngleUnit = false;
bool Ifc::SewShells = false;
int Ifc::CircleSegments = 32;
MapEntitiesByType Ifc::bytype;
MapEntityById Ifc::byid;
MapEntityByGuid Ifc::byguid;
MapEntitiesByRef Ifc::byref;
MapOffsetById Ifc::offsets;
std::stringstream Ifc::log_stream;
int Ifc::Verbosity = 2;
+59 -65
View File
@@ -27,7 +27,7 @@
#ifndef IFCPARSE_H
#define IFCPARSE_H
#define IFCOPENSHELL_VERSION "0.3.0-rc3"
#define IFCOPENSHELL_VERSION "0.3.0"
#include <string>
#include <sstream>
@@ -47,56 +47,59 @@ namespace IfcParse {
class Entity;
class Entities;
class IfcFile;
typedef Entity* EntityPtr;
typedef SHARED_PTR<Entities> EntitiesPtr;
typedef unsigned int Token;
class Tokens;
typedef std::pair<Tokens*,unsigned> Token;
/// Provides functions to convert Tokens to binary data
/// Tokens are merely offsets to where they can be read in the file
class TokenFunc {
private:
static bool startsWith(Token t, char c);
static bool startsWith(const Token& t, char c);
public:
/// Returns the offset at which the token is read from the file
static unsigned int Offset(Token t);
// static unsigned int Offset(const Token& t);
/// Returns whether the token can be interpreted as a string
static bool isString(Token t);
static bool isString(const Token& t);
/// Returns whether the token can be interpreted as an identifier
static bool isIdentifier(Token t);
static bool isIdentifier(const Token& t);
/// Returns whether the token can be interpreted as an syntactical operator
static bool isOperator(Token t, char op = 0);
static bool isOperator(const Token& t, char op = 0);
/// Returns whether the token can be interpreted as an enumerated value
static bool isEnumeration(Token t);
static bool isEnumeration(const Token& t);
/// Returns whether the token can be interpreted as an datatype name
static bool isDatatype(Token t);
static bool isDatatype(const Token& t);
/// Returns the token interpreted as an integer
static int asInt(Token t);
static int asInt(const Token& t);
/// Returns the token interpreted as an boolean (.T. or .F.)
static bool asBool(Token t);
static bool asBool(const Token& t);
/// Returns the token as a floating point number
static double asFloat(Token t);
static double asFloat(const Token& t);
/// Returns the token as a string (without the dot or apostrophe)
static std::string asString(Token t);
static std::string asString(const Token& t);
/// Returns a string representation of the token (including the dot or apostrophe)
static std::string toString(Token t);
static std::string toString(const Token& t);
};
//
// Functions for creating Tokens from an arbitary file offset
// The first 4 bits are reserved for Tokens of type ()=,;$*
//
Token TokenPtr(unsigned int offset);
Token TokenPtr(Tokens* tokens, unsigned int offset);
Token TokenPtr(char c);
Token TokenPtr();
/// A stream of tokens to be read from a File.
/// A stream of tokens to be read from a IfcSpfStream.
class Tokens {
private:
File* file;
IfcCharacterDecoder* decoder;
public:
Tokens(File* f);
IfcSpfStream* stream;
IfcFile* file;
Tokens(IfcSpfStream* s, IfcFile* f);
Token Next();
~Tokens();
std::string TokenString(unsigned int offset);
@@ -136,7 +139,7 @@ namespace IfcParse {
public:
Token token;
TokenArgument(Token t);
TokenArgument(const Token& t);
operator int() const;
operator bool() const;
operator double() const;
@@ -160,7 +163,7 @@ namespace IfcParse {
private:
IfcUtil::IfcArgumentSelect* entity;
public:
EntityArgument(Ifc2x3::Type::Enum ty, Token t);
EntityArgument(Ifc2x3::Type::Enum ty, const Token& t);
~EntityArgument();
operator int() const;
operator bool() const;
@@ -183,15 +186,16 @@ namespace IfcParse {
/// ============================
class Entity : public IfcAbstractEntity {
private:
//IfcFile* file;
ArgumentPtr args;
Ifc2x3::Type::Enum _type;
public:
/// The EXPRESS ENTITY_NAME
/// The EXPRESS ENTITY_INSTANCE_NAME
unsigned int _id;
/// The offset at which the entity is read
unsigned int offset;
Entity(unsigned int i, Tokens* t);
Entity(unsigned int i, Tokens* t, unsigned int o);
Entity(unsigned int i, IfcFile* t);
Entity(unsigned int i, IfcFile* t, unsigned int o);
~Entity();
IfcEntities getInverse(Ifc2x3::Type::Enum c = Ifc2x3::Type::ALL);
IfcEntities getInverse(Ifc2x3::Type::Enum c, int i, const std::string& a);
@@ -204,10 +208,9 @@ namespace IfcParse {
bool is(Ifc2x3::Type::Enum v) const;
unsigned int id();
};
}
typedef IfcUtil::IfcSchemaEntity IfcEntity;
typedef IfcEntities IfcEntities;
//typedef IfcEntities IfcEntities;
typedef std::map<Ifc2x3::Type::Enum,IfcEntities> MapEntitiesByType;
typedef std::map<unsigned int,IfcEntity> MapEntityById;
typedef std::map<std::string,Ifc2x3::IfcRoot::ptr> MapEntityByGuid;
@@ -216,65 +219,56 @@ typedef std::map<unsigned int,unsigned int> MapOffsetById;
/// This class provides several static convenience functions and variables
/// and provide access to the entities in an IFC file
class Ifc {
class IfcFile {
private:
static MapEntityById byid;
static MapEntitiesByType bytype;
static MapEntitiesByRef byref;
static MapEntityByGuid byguid;
static MapOffsetById offsets;
static unsigned int lastId;
static std::ostream* log1;
static std::ostream* log2;
static std::stringstream log_stream;
MapEntityById byid;
MapEntitiesByType bytype;
MapEntitiesByRef byref;
MapEntityByGuid byguid;
MapOffsetById offsets;
unsigned int lastId;
unsigned int MaxId;
public:
/// Returns the first entity in the file, this probably is the entity with the lowest id (EXPRESS ENTITY_NAME)
static MapEntityById::const_iterator First();
/// Returns the last entity in the file, this probably is the entity with the highes id (EXPRESS ENTITY_NAME)
static MapEntityById::const_iterator Last();
/// Determines to what stream respectively progress and errors are logged
static void SetOutput(std::ostream* l1, std::ostream* l2);
/// Log a message to the output stream
static void LogMessage(const std::string& type, const std::string& message, const IfcAbstractEntityPtr entity=0);
static IfcParse::File* file;
static IfcParse::Tokens* tokens;
typedef MapEntityById::const_iterator const_iterator;
IfcFile();
~IfcFile();
/// Returns the first entity in the file, this probably is the entity with the lowest id (EXPRESS ENTITY_INSTANCE_NAME)
const_iterator begin() const;
/// Returns the last entity in the file, this probably is the entity with the highes id (EXPRESS ENTITY_INSTANCE_NAME)
const_iterator end() const;
IfcParse::IfcSpfStream* file;
IfcParse::Tokens* tokens;
/// Returns all entities in the file that match the template argument.
/// NOTE: This also returns subtypes of the requested type, for example:
/// IfcWall will also return IfcWallStandardCase entities
template <class T>
static typename T::list EntitiesByType() {
typename T::list EntitiesByType() {
IfcEntities e = EntitiesByType(T::Class());
typename T::list l ( new IfcTemplatedEntityList<T>() );
if ( e && e->Size() )
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) {
l->push(reinterpret_pointer_cast<IfcUtil::IfcBaseClass,T>(*it));
}
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) {
l->push(reinterpret_pointer_cast<IfcUtil::IfcBaseClass,T>(*it));
}
return l;
}
/// Returns all entities in the file that match the positional argument.
/// NOTE: This also returns subtypes of the requested type, for example:
/// IfcWall will also return IfcWallStandardCase entities
static IfcEntities EntitiesByType(Ifc2x3::Type::Enum t);
IfcEntities EntitiesByType(Ifc2x3::Type::Enum t);
/// Returns all entities in the file that reference the id
static IfcEntities EntitiesByReference(int id);
IfcEntities EntitiesByReference(int id);
/// Returns the entity with the specified id
static IfcEntity EntityById(int id);
IfcEntity EntityById(int id);
/// Returns the entity with the specified GlobalId
static Ifc2x3::IfcRoot::ptr EntityByGuid(const std::string& guid);
static bool Init(const std::string& fn);
static bool Init(std::istream& fn, int len);
static bool Init(void* data, int len);
static bool Init(IfcParse::File* f);
static std::string GetLog();
static void Dispose();
static bool hasPlaneAngleUnit;
static bool SewShells;
static double LengthUnit;
static double PlaneAngleUnit;
static int CircleSegments;
static int Verbosity;
Ifc2x3::IfcRoot::ptr EntityByGuid(const std::string& guid);
bool Init(const std::string& fn);
bool Init(std::istream& fn, int len);
bool Init(void* data, int len);
bool Init(IfcParse::IfcSpfStream* f);
};
double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v );
}
#endif
+33 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -62,3 +62,35 @@ IfcUtil::IfcArgumentSelect::IfcArgumentSelect(Ifc2x3::Type::Enum t, ArgumentPtr
ArgumentPtr IfcUtil::IfcArgumentSelect::wrappedValue() { return arg; }
bool IfcUtil::IfcArgumentSelect::isSimpleType() { return true; }
IfcUtil::IfcArgumentSelect::~IfcArgumentSelect() { delete arg; }
void Logger::SetOutput(std::ostream* l1, std::ostream* l2) {
log1 = l1;
log2 = l2;
if ( ! log2 ) {
log2 = &log_stream;
}
}
void Logger::Message(Logger::Severity type, const std::string& message, const IfcAbstractEntityPtr entity) {
if ( log2 && type >= verbosity ) {
(*log2) << "[" << severity_strings[type] << "] " << message << std::endl;
if ( entity ) (*log2) << entity->toString() << std::endl;
}
}
void Logger::Status(const std::string& message, bool new_line) {
if ( log1 ) {
(*log1) << message;
if ( new_line ) (*log1) << std::endl;
else (*log1) << std::flush;
}
}
std::string Logger::GetLog() {
return log_stream.str();
}
void Logger::Verbosity(Logger::Severity v) { verbosity = v; }
Logger::Severity Logger::Verbosity() { return verbosity; }
std::ostream* Logger::log1 = 0;
std::ostream* Logger::log2 = 0;
std::stringstream Logger::log_stream;
Logger::Severity Logger::verbosity = Logger::LOG_NOTICE;
const char* Logger::severity_strings[] = { "Notice","Warning","Error" };
+30 -2
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -22,6 +22,7 @@
#include <string>
#include <vector>
#include <sstream>
#include "../ifcparse/SharedPointer.h"
#include "../ifcparse/Ifc2x3enum.h"
@@ -132,9 +133,14 @@ namespace IfcUtil {
};
}
namespace IfcParse {
class IfcFile;
}
class Argument {
protected:
public:
//void* file;
//public:
virtual operator int() const = 0;
virtual operator bool() const = 0;
virtual operator double() const = 0;
@@ -154,6 +160,7 @@ public:
class IfcAbstractEntity {
public:
IfcParse::IfcFile* file;
virtual IfcEntities getInverse(Ifc2x3::Type::Enum c = Ifc2x3::Type::ALL) = 0;
virtual IfcEntities getInverse(Ifc2x3::Type::Enum c, int i, const std::string& a) = 0;
virtual std::string datatype() = 0;
@@ -166,4 +173,25 @@ public:
virtual unsigned int id() = 0;
};
class Logger {
public:
typedef enum { LOG_NOTICE, LOG_WARNING, LOG_ERROR } Severity;
private:
static std::ostream* log1;
static std::ostream* log2;
static std::stringstream log_stream;
static Severity verbosity;
static const char* severity_strings[];
public:
/// Determines to what stream respectively progress and errors are logged
static void SetOutput(std::ostream* l1, std::ostream* l2);
/// Determines the types of log messages to get logged
static void Verbosity(Severity v);
static Severity Verbosity();
/// Log a message to the output stream
static void Message(Severity type, const std::string& message, const IfcAbstractEntityPtr entity=0);
static void Status(const std::string& message, bool new_line=true);
static std::string GetLog();
};
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+1 -1
View File
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
+2 -19
View File
@@ -24,6 +24,8 @@ namespace IfcGeomObjects {
const int CONVERT_BACK_UNITS = 3;
const int USE_BREP_DATA = 4;
const int SEW_SHELLS = 5;
const int FASTER_BOOLEANS = 6;
const int FORCE_CCW_FACE_ORIENTATION = 7;
class IfcMesh {
public:
@@ -43,21 +45,6 @@ namespace IfcGeomObjects {
std::string type;
std::string guid;
std::vector<float> matrix;
const std::vector<int> name_as_intvector() {
std::vector<int> r;
for ( std::string::const_iterator it = name.begin(); it != name.end(); ++ it ) r.push_back(*it);
return r;
}
const std::vector<int> type_as_intvector() {
std::vector<int> r;
for ( std::string::const_iterator it = type.begin(); it != type.end(); ++ it ) r.push_back(*it);
return r;
}
const std::vector<int> guid_as_intvector() {
std::vector<int> r;
for ( std::string::const_iterator it = guid.begin(); it != guid.end(); ++ it ) r.push_back(*it);
return r;
}
};
class IfcGeomObject : public IfcObject {
@@ -68,13 +55,9 @@ namespace IfcGeomObjects {
bool Next();
const IfcGeomObject* Get();
bool Init(const std::string fn);
bool InitUCS2(const char* fn) {
return Init(std::string(fn+1));
}
void Settings(int setting, bool value);
int Progress();
const IfcObject* GetObject(int id);
bool CleanUp();
std::string GetLog();
};
+2 -1
View File
@@ -63,7 +63,8 @@ scn.render.resolution_x = 2048
scn.render.resolution_y = 2048
scn.world.horizon_color = (1,1,1)
scn.world.ambient_color = (0.05,0.05,0.05)
scn.render.color_mode = 'RGBA'
try: scn.render.color_mode = 'RGBA'
except: scn.render.image_settings.color_mode = 'RGBA'
for m in bpy.data.materials: m.specular_intensity = 0
def material(name,settings):