Compare commits

...

43 Commits

Author SHA1 Message Date
Thomas Krijnen e39cbc6d00 Fix ensure_fit_for_subtraction() function when input shape is a solid 2015-06-21 16:14:37 +00:00
Thomas Krijnen 9619543137 Update bl_info structure in blender addon 2015-02-23 19:13:47 +00:00
Thomas Krijnen ab4d3b8cad #include <xlocale.h> header on OS X 2015-02-20 22:02:22 +00:00
Thomas Krijnen 8c7346a669 Correctly cast writable enumeration attributes to string, as reported in: https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/53b70ea0 2015-02-17 22:14:09 +00:00
Thomas Krijnen 65b0f22c76 More fixes related to locales 2015-02-17 20:23:21 +00:00
Thomas Krijnen d79120dfcc Add missing #includes for OCC 6.8.0 specific #if 2015-02-06 14:20:33 +00:00
Thomas Krijnen 687cda0c4d #ifdef away the two trailing precision arguments for gp_Trsf::SetValues() when OCC >= 6.8.0 2015-02-06 12:49:53 +00:00
Thomas Krijnen 2b5f797913 Fix typo in locale code 2015-02-05 10:33:51 +00:00
Thomas Krijnen d3538cc7d4 Make real number parsing and serializing locale-independent, as suggested by Ian Clevy. 2015-02-03 13:53:36 +00:00
Thomas Krijnen 6bae80b70f Fix errors in serialization 2015-01-25 10:50:12 +00:00
Thomas Krijnen 336b07a7a2 Use BRepMesh_IncrementalMesh rather than BRepMesh::Mesh. Thanks lorinma. 2015-01-19 16:02:34 +00:00
Thomas Krijnen 3b157b0f3e Use BRepMesh_IncrementalMesh rather than BRepMesh::Mesh. Thanks lorinma. 2015-01-16 14:32:50 +00:00
Thomas Krijnen 414b761453 Don't rely on operator bool() but on bool operator!() for truthiness of boost::optionals. Fixes compilation with boost 1.56+. 2015-01-16 13:24:40 +00:00
Thomas Krijnen 53c95db28f Fix for IfcSpecularExponent 2015-01-06 14:13:24 +00:00
Thomas Krijnen d1c91d3c47 Bump version number to 0.4.0-rc2 2015-01-06 14:10:10 +00:00
Thomas Krijnen 61d73ebfd6 Improvements for precision handling 2015-01-06 14:09:28 +00:00
Thomas Krijnen 0fd88be5a3 Catch all errors when parsing boost program_options in IfcConvert 2014-11-04 12:45:20 +00:00
Thomas Krijnen 5fdefceddd Reconstruct the form of the transformation to improve the output of the OpenCascade-based serializers 2014-11-04 12:36:59 +00:00
Thomas Krijnen d28871e7fc Don't compare smart pointers to zero, but convert to bool 2014-11-04 12:02:28 +00:00
Thomas Krijnen 33625c6422 More robust processing of IfcPolyline and IfcPolyLoop 2014-07-28 20:03:53 +00:00
Thomas Krijnen f68060f566 Fixes for IfcRectangleHollowProfileDef and filleted profile generation. 2014-07-24 11:14:54 +00:00
Thomas Krijnen dce878515e Correct an invalid default value for IfcCartesianTransformationOperator3D.Axis3. Thanks Stefan. 2014-07-19 10:30:13 +00:00
Thomas Krijnen 843f08c0a6 Remove a duplicated cartesian point from the closed polyline created by the addBox() function as seen in IfcOpenHouse. Thanks Bernd. 2014-06-28 12:39:40 +00:00
Thomas Krijnen 577565a494 - Check the validity of solids created from sewed shells and potentially revert to a shell or compound of faces
- Flag shape representations, for which no item succeeds, as failed
2014-06-27 12:00:41 +00:00
Thomas Krijnen 18620d29ae Apply the same precision value when merging a compound of faces into a solid just-in-time for subtraction 2014-06-11 10:35:06 +00:00
Thomas Krijnen 79839d487a Detect cases where Newell's Method returns a zero-length vector and make no attempt to normalize it in order to prevent an exception. In this case the face will be flagged as invalid down the road, because its perimeter doesn't span any area. 2014-06-11 10:32:15 +00:00
Thomas Krijnen f3622f9339 Increase precision for writing floats 2014-06-11 10:24:11 +00:00
Thomas Krijnen 1be3f63d63 More fixes for parsing files with comments 2014-04-19 09:35:08 +00:00
Thomas Krijnen 6fe2e2366d Process IfcStyledItems directly applied to an IfcFacetedBrep 2014-04-09 10:57:45 +00:00
Thomas Krijnen 4242bb7c1b Account for unit magnitude in matrix translation part when CONVERT_BACK_UNITS is enabled 2014-04-08 07:28:07 +00:00
Thomas Krijnen d821324e28 When writing collada files, postfix geometry instance nodes to make them distinct from their geometry library references 2014-04-07 14:01:16 +00:00
Thomas Krijnen 1bbd08f1a4 Increased verbosity in unsupported entity instances 2014-04-02 15:28:04 +00:00
Thomas Krijnen 9a1db57f3c Fixes for parsing files with comments 2014-04-02 15:04:09 +00:00
Thomas Krijnen be8cfeeadf Measure conversion time of IfcConvert more faithfully 2014-03-31 14:03:06 +00:00
Thomas Krijnen f387090078 Take into account face location when serializing shape as tesselated faceset. 2014-03-22 21:13:02 +00:00
Thomas Krijnen 790bdee195 Correctly treat IfcLShapeProfileDef.Width as optional attribute
Fix IfcCShapeProfileDef having Width and Depth interchanged
2014-03-22 18:46:07 +00:00
Thomas Krijnen fcbcec78e9 IfcConvert: Handle invalid command line options gracefully and notify user 2014-03-22 13:12:22 +00:00
Thomas Krijnen bd02aac18a No longer accept and silently convert invalid REAL tokens to zero 2014-03-22 13:02:21 +00:00
Thomas Krijnen b6a811ae7e Handle missing or invalid unit and precision information more gracefully during IfcGeomObject initialization 2014-03-22 12:56:08 +00:00
Thomas Krijnen e24260015f For .obj conversion terminate lines with "\n" rather than std::endl causing a significant speed increase due to longer intermittently flushing the stream 2014-03-22 11:12:50 +00:00
Thomas Krijnen fa195194c6 Prevent a construction error when trying to normalize a zero length normal during triangulation, which happens very, very rarely. 2014-03-22 10:48:29 +00:00
Thomas Krijnen a5e466b53a Add missing header to installation files. Thanks Fred. 2014-03-22 09:22:27 +00:00
Thomas Krijnen 896607e535 Bump version numbers 2014-01-12 11:03:50 +00:00
19 changed files with 439 additions and 202 deletions
+1
View File
@@ -176,6 +176,7 @@ ADD_SUBDIRECTORY(../src/examples examples)
SET(include_files_geom
../src/ifcgeom/IfcGeom.h
../src/ifcgeom/IfcGeomObjects.h
../src/ifcgeom/IfcGeomRenderStyles.h
../src/ifcgeom/IfcRegister.h
../src/ifcgeom/IfcRegisterConvertCurve.h
../src/ifcgeom/IfcRegisterConvertFace.h
@@ -30,13 +30,10 @@ bl_info = {
"description": "Import files in the "\
"Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 6, 5),
"api": 52851,
"blender": (2, 73, 0),
"location": "File > Import",
"warning": "",
"wiki_url": "http://sourceforge.net/apps/"\
"mediawiki/ifcopenshell/index.php",
"tracker_url": "http://sourceforge.net/tracker/?group_id=543113",
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
"_list/tickets?source=navbar",
"category": "Import-Export"}
if "bpy" in locals():
+1 -1
View File
@@ -259,7 +259,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
scene.add(object_name, object_name, object_name, it->material_references, it->matrix);
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
}
scene.write();
stream.endDocument();
+12 -6
View File
@@ -122,8 +122,15 @@ int main(int argc, char** argv) {
positional_options.add("output-file", 1);
boost::program_options::variables_map vmap;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
options(cmdline_options).positional(positional_options).run(), vmap);
try {
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
options(cmdline_options).positional(positional_options).run(), vmap);
} catch (const boost::program_options::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
// Usage information will be emitted below
} catch (...) {
// Catch other errors such as invalid command line syntax
}
boost::program_options::notify(vmap);
if (vmap.count("version")) {
@@ -184,6 +191,7 @@ int main(int argc, char** argv) {
}
Logger::SetOutput(&std::cout, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
GeometrySerializer* serializer;
if (output_extension == ".obj") {
@@ -211,8 +219,6 @@ int main(int argc, char** argv) {
return 1;
}
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
if (!serializer->ready()) {
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
write_log();
@@ -226,6 +232,8 @@ int main(int argc, char** argv) {
}
}
time_t start,end;
time(&start);
// Parse the file supplied in argv[1]. Returns true on succes.
if ( ! IfcGeomObjects::Init(input_filename, &std::cout, &log_stream) ) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
@@ -243,8 +251,6 @@ int main(int argc, char** argv) {
std::set<std::string> materials;
time_t start,end;
time(&start);
int old_progress = -1;
Logger::Status("Creating geometry...");
+14 -7
View File
@@ -24,6 +24,8 @@
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#include "OpenCascadeBasedSerializer.h"
bool OpenCascadeBasedSerializer::ready() {
@@ -38,14 +40,19 @@ void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomSh
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh().begin(); it != o->mesh().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
// TODO:
gp_GTrsf o_trsf;
int k = 0;
for( int i = 1; i < 5; ++ i )
for ( int j = 1; j < 4; ++ j )
o_trsf.SetValue(j, i, o->matrix()[k++]);
// Convert the matrix back into a transformation object. The tolerance values
// are taken into consideration to reconstruct the form of the transformation.
gp_Trsf o_trsf;
o_trsf.SetValues(
o->matrix()[0], o->matrix()[3], o->matrix()[6], o->matrix()[ 9],
o->matrix()[1], o->matrix()[4], o->matrix()[7], o->matrix()[10],
o->matrix()[2], o->matrix()[5], o->matrix()[8], o->matrix()[11]
#if OCC_VERSION_HEX < 0x60800
, Precision::Angular(), Precision::Confusion()
#endif
);
gtrsf.PreMultiply(o_trsf);
const TopoDS_Shape& s = it->Shape();
bool trsf_valid = false;
+16 -16
View File
@@ -28,7 +28,7 @@ bool WaveFrontOBJSerializer::ready() {
}
void WaveFrontOBJSerializer::writeHeader() {
obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl;
obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
#ifdef WIN32
const char dir_separator = '\\';
#else
@@ -39,29 +39,29 @@ void WaveFrontOBJSerializer::writeHeader() {
if (slash != std::string::npos) {
mtl_basename = mtl_basename.substr(slash+1);
}
obj_stream << "mtllib " << mtl_basename << std::endl;
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl;
obj_stream << "mtllib " << mtl_basename << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style) {
mtl_stream << "newmtl " << style.name() << std::endl;
mtl_stream << "newmtl " << style.name() << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << std::endl;
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
}
if (style.hasSpecular()) {
const double* specular = style.specular();
mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << std::endl;
mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << "\n";
}
if (style.hasSpecularity()) {
mtl_stream << "Ns " << style.specularity() << std::endl;
mtl_stream << "Ns " << style.specularity() << "\n";
}
if (style.hasTransparency()) {
const double transparency = 1.0 - style.transparency();
if (transparency < 1) {
mtl_stream << "Tr " << transparency << std::endl;
mtl_stream << "d " << transparency << std::endl;
mtl_stream << "D " << transparency << std::endl;
mtl_stream << "Tr " << transparency << "\n";
mtl_stream << "d " << transparency << "\n";
mtl_stream << "D " << transparency << "\n";
}
}
}
@@ -71,8 +71,8 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
std::replace( tmp.begin(), tmp.end(), ' ', '_');
const std::string name = tmp;
obj_stream << "g " << name << std::endl;
obj_stream << "s 1" << std::endl;
obj_stream << "g " << name << "\n";
obj_stream << "s 1" << "\n";
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
@@ -81,13 +81,13 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "v " << x << " " << y << " " << z << std::endl;
obj_stream << "v " << x << " " << y << " " << z << "\n";
}
for ( std::vector<float>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "vn " << x << " " << y << " " << z << std::endl;
obj_stream << "vn " << x << " " << y << " " << z << "\n";
}
int previous_material_id = -2;
@@ -104,7 +104,7 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
material = IfcGeomObjects::Material(IfcGeom::get_default_style(o->type()));
}
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << std::endl;
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
materials.insert(material_name);
@@ -115,7 +115,7 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
const int v1 = *(it++)+vcount_total;
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << std::endl;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
}
vcount_total += vcount;
}
+2 -1
View File
@@ -36,6 +36,7 @@
#include <TopoDS_Face.hxx>
#include <Geom_Curve.hxx>
#include <gp_Pln.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcUtil.h"
@@ -103,7 +104,7 @@ namespace IfcGeom {
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
namespace Cache {
+12 -2
View File
@@ -79,7 +79,10 @@
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r <= 0.0f ) { return false; }
if ( r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
if (placement->is(Ifc2x3::Type::IfcAxis2Placement3D)) {
@@ -96,7 +99,14 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve)
bool IfcGeom::convert(const Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
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; }
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
if (y > x) {
Logger::Message(Logger::LOG_ERROR, "Ellipse with SemiAxis2 larger than SemiAxis1 not supported for:", l->entity);
return false;
}
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
if (placement->is(Ifc2x3::Type::IfcAxis2Placement3D)) {
+9 -6
View File
@@ -170,9 +170,12 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
// 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);
if (face_normal2.Magnitude() > ALMOST_ZERO) {
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
}
@@ -243,8 +246,8 @@ 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 * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
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 d1 = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
@@ -269,7 +272,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& fac
}
bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& face) {
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 x = (l->hasWidth() ? l->Width() : l->Depth()) / 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();
+45 -8
View File
@@ -24,6 +24,7 @@
********************************************************************************/
#include <cassert>
#include <algorithm>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
@@ -86,7 +87,7 @@
#include <BRepGProp_Face.hxx>
#include <BRepMesh.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepTools.hxx>
#include <Poly_Triangulation.hxx>
@@ -125,8 +126,16 @@ bool IfcGeom::is_compound(const TopoDS_Shape& shape) {
const TopoDS_Shape& IfcGeom::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) {
const bool is_comp = IfcGeom::is_compound(shape);
if ( ! is_comp ) return shape;
IfcGeom::create_solid_from_compound(shape,solid);
if (!is_comp) {
return solid = shape;
}
IfcGeom::create_solid_from_compound(shape, solid);
// If the SEW_SHELLS option had been set this precision had been applied
// at the end of the generic IfcGeom::convert_shape() call.
const double precision = IfcGeom::GetValue(GV_PRECISION);
IfcGeom::apply_tolerance(solid, precision);
return solid;
}
@@ -330,15 +339,19 @@ bool IfcGeom::profile_helper(int numVerts, double* verts, int numFillets, int* f
IfcGeom::convert_wire_to_face(w.Wire(),face);
if ( numFillets ) {
if ( numFillets && *std::max_element(filletRadii, filletRadii + numFillets) > 1e-7 ) {
BRepFilletAPI_MakeFillet2d fillet (face);
for ( int i = 0; i < numFillets; i ++ ) {
const double radius = filletRadii[i];
if ( radius < 1e-7 ) continue;
if ( radius <= 1e-7 ) continue;
fillet.AddFillet(vertices[filletIndices[i]],radius);
}
fillet.Build();
face = TopoDS::Face(fillet.Shape());
if (fillet.IsDone()) {
face = TopoDS::Face(fillet.Shape());
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to process profile fillets");
}
}
delete[] vertices;
@@ -502,7 +515,7 @@ double IfcGeom::GetValue(GeomValue var) {
}
Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es) {
BRepMesh::Mesh(shape, deflection);
BRepMesh_IncrementalMesh(shape, deflection);
Ifc2x3::IfcFace::list faces (new IfcTemplatedEntityList<Ifc2x3::IfcFace>());
@@ -515,7 +528,7 @@ Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, doubl
const TColgp_Array1OfPnt& nodes = tri->Nodes();
std::vector<Ifc2x3::IfcCartesianPoint*> vertices;
for (int i = 1; i <= nodes.Length(); ++i) {
const gp_Pnt& pnt = nodes(i);
gp_Pnt pnt = nodes(i).Transformed(loc);
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
Ifc2x3::IfcCartesianPoint* cpnt = new Ifc2x3::IfcCartesianPoint(xyz);
vertices.push_back(cpnt);
@@ -563,4 +576,28 @@ Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, doubl
es->push(shapedef);
return shapedef;
}
void IfcGeom::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
if (tol <= 0.) tol = GetValue(GV_POINT_EQUALITY_TOLERANCE);
tol *= tol;
while (true) {
bool removed = false;
int n = polygon.Length() - (closed ? 0 : 1);
for (int i = 1; i <= n; ++i) {
// wrap around to the first point in case of a closed loop
int j = (i % polygon.Length()) + 1;
double dist = polygon.Value(i).SquareDistance(polygon.Value(j));
if (dist < tol) {
// do not remove the first or last point to
// maintain connectivity with other wires
if ((closed && j == 1) || (!closed && j == n)) polygon.Remove(i);
else polygon.Remove(j);
removed = true;
break;
}
}
if (!removed) break;
}
}
+6 -5
View File
@@ -137,11 +137,10 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator3D::ptr l,
IfcGeom::convert(l->LocalOrigin(),origin);
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3;
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
else axis3 = axis1.Crossed(axis2);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
@@ -170,11 +169,10 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator3DnonUnifo
IfcGeom::convert(l->LocalOrigin(),origin);
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3;
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
else axis3 = axis1.Crossed(axis2);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
@@ -238,7 +236,10 @@ bool IfcGeom::convert(const Ifc2x3::IfcAxis2Placement2D::ptr l, gp_Trsf2d& trsf)
}
bool IfcGeom::convert(const Ifc2x3::IfcObjectPlacement::ptr l, gp_Trsf& trsf) {
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
if ( ! l->is(Ifc2x3::Type::IfcLocalPlacement) ) return false;
if ( ! l->is(Ifc2x3::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
return false;
}
Ifc2x3::IfcLocalPlacement::ptr current = reinterpret_pointer_cast<Ifc2x3::IfcObjectPlacement,Ifc2x3::IfcLocalPlacement>(l);
while (1) {
gp_Trsf trsf2;
+88 -48
View File
@@ -32,7 +32,7 @@
#include <BRepTools.hxx>
#include <BRep_Tool.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepMesh.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <TColgp_Array1OfPnt.hxx>
@@ -133,8 +133,7 @@ IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(c
// Triangulate the shape
try {
// BRepTools::Clean(s);
BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
BRepMesh_IncrementalMesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
} catch(...) {
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->EntityById(_id)->entity);
continue;
@@ -175,8 +174,11 @@ IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(c
const gp_Pnt2d& uv = uvs(i);
gp_Pnt p;
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Dir normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > ALMOST_ZERO) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
}
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
@@ -236,9 +238,19 @@ IfcGeomObjects::IfcObject::IfcObject(
, _guid(guid)
{
// Convert the gp_Trsf into a 4x3 Matrix
for( int i = 1; i < 5; ++ i )
for ( int j = 1; j < 4; ++ j )
_matrix.push_back((float)trsf.Value(j,i));
// Note that in case the CONVERT_BACK_UNITS setting is enabled
// the translation component of the matrix needs to be divided
// by the magnitude of the IFC model length unit because
// internally in IfcOpenShell everything is measured in meters.
for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && convert_back_units
? trsf_value / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)
: trsf_value;
_matrix.push_back(static_cast<float>(matrix_value));
}
}
}
IfcGeomObjects::IfcGeomShapeModelObject::IfcGeomShapeModelObject(
@@ -579,35 +591,52 @@ double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) {
else return 1.0f;
}
void IfcGeomObjects::InitPrecision() {
Ifc2x3::IfcGeometricRepresentationContext::list rep_contexts = ifc_file->EntitiesByType<Ifc2x3::IfcGeometricRepresentationContext>();
// Currently, IfcGeometricRepresentationContext aren't used as much as they should be
// in the evaluation of shape representations, hence, we try to find the one with the
// lowest precision. Typically, a value of 1e-5 is encountered. This value is applied
// to all TopoDS_Shapes generated by one of the IfcGeom::convert() functions.
// TODO: Many of the empirically found tolerances should probably be substituted by
// one that is defined in the model file.
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
for (Ifc2x3::IfcGeometricRepresentationContext::it it = rep_contexts->begin(); it != rep_contexts->end(); ++it) {
Ifc2x3::IfcGeometricRepresentationContext* rep_context = *it;
if (rep_context->is(Ifc2x3::Type::IfcGeometricRepresentationSubContext)) continue;
if (rep_context->hasPrecision()) {
const double precision = rep_context->Precision();
if (precision < lowest_precision_encountered) {
any_precision_encountered = true;
lowest_precision_encountered = precision;
}
}
}
if (any_precision_encountered) {
IfcGeom::SetValue(IfcGeom::GV_PRECISION, lowest_precision_encountered);
}
}
static std::string unit_name = "METER";
static float unit_magnitude = 1.0f;
void IfcGeomObjects::InitPrecision() {
IfcGeom::SetValue(IfcGeom::GV_PRECISION, 0.00001);
try {
Ifc2x3::IfcGeometricRepresentationContext::list rep_contexts = ifc_file->EntitiesByType<Ifc2x3::IfcGeometricRepresentationContext>();
// Currently, IfcGeometricRepresentationContext aren't used as much as they should be
// in the evaluation of shape representations, hence, we try to find the one with the
// lowest precision. Typically, a value of 1e-5 is encountered. This value is applied
// to all TopoDS_Shapes generated by one of the IfcGeom::convert() functions.
// TODO: Many of the empirically found tolerances should probably be substituted by
// one that is defined in the model file.
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
for (Ifc2x3::IfcGeometricRepresentationContext::it it = rep_contexts->begin(); it != rep_contexts->end(); ++it) {
Ifc2x3::IfcGeometricRepresentationContext* rep_context = *it;
if (rep_context->is(Ifc2x3::Type::IfcGeometricRepresentationSubContext)) continue;
if (rep_context->hasPrecision()) {
const double precision = rep_context->Precision();
if (precision < lowest_precision_encountered) {
any_precision_encountered = true;
lowest_precision_encountered = precision;
}
}
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
IfcGeom::SetValue(IfcGeom::GV_PRECISION, 1.e-7);
} else {
IfcGeom::SetValue(IfcGeom::GV_PRECISION, lowest_precision_encountered);
}
}
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to determine precision value '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
}
void IfcGeomObjects::InitUnits() {
// Set default units, set length to meters, angles to undefined
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,1.0);
@@ -615,23 +644,32 @@ void IfcGeomObjects::InitUnits() {
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 ) {
try {
if ( unit_assignments->Size() ) {
Ifc2x3::IfcUnitAssignment::ptr unit_assignment = *unit_assignments->begin();
units = unit_assignment->Units();
}
} catch (const IfcParse::IfcException&) {}
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;
try {
const double depth = (*it)->Depth();
if ( depth > max_height ) max_height = depth;
} catch (const IfcParse::IfcException&) {}
}
if ( max_height > 100.0f ) {
IfcGeom::SetValue(IfcGeom::GV_LENGTH_UNIT,0.001);
Logger::Message(Logger::LOG_NOTICE, "Guessed length unit to be in millimeters based on extrusion 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 ) {
std::string current_unit_name = "";
@@ -673,8 +711,10 @@ void IfcGeomObjects::InitUnits() {
}
}
}
} catch ( IfcException ex ) {
Logger::Message(Logger::LOG_ERROR,ex.what());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to determine unit information '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
}
@@ -771,10 +811,10 @@ IfcParse::IfcFile* IfcGeomObjects::GetFile() {
static double black[3] = {0,0,0};
IfcGeomObjects::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
bool IfcGeomObjects::Material::hasDiffuse() const { return style->Diffuse(); }
bool IfcGeomObjects::Material::hasSpecular() const { return style->Specular(); }
bool IfcGeomObjects::Material::hasTransparency() const { return style->Transparency(); }
bool IfcGeomObjects::Material::hasSpecularity() const { return style->Specularity(); }
bool IfcGeomObjects::Material::hasDiffuse() const { return style->Diffuse() ? true : false; }
bool IfcGeomObjects::Material::hasSpecular() const { return style->Specular() ? true : false; }
bool IfcGeomObjects::Material::hasTransparency() const { return style->Transparency() ? true : false; }
bool IfcGeomObjects::Material::hasSpecularity() const { return style->Specularity() ? true : false; }
const double* IfcGeomObjects::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
const double* IfcGeomObjects::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
double IfcGeomObjects::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
+1 -1
View File
@@ -101,7 +101,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(Ifc2x3::IfcRepresentationItem* i
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->is(Ifc2x3::Type::IfcSpecularRoughness)) {
} else if (highlight->is(Ifc2x3::Type::IfcSpecularExponent)) {
surface_style.Specularity().reset(*highlight->wrappedValue());
}
}
+51 -19
View File
@@ -76,6 +76,8 @@
#include <BRepCheck_Analyzer.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
@@ -94,8 +96,10 @@ bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& s
}
bool IfcGeom::convert(const Ifc2x3::IfcFacetedBrep::ptr l, IfcRepresentationShapeItems& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (IfcGeom::convert_shape(l->Outer(),s) ) {
shape.push_back(IfcRepresentationShapeItem(s, get_style(l->Outer())));
const SurfaceStyle* indiv_style = get_style(l->Outer());
shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style));
return true;
}
return false;
@@ -115,7 +119,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcFaceBasedSurfaceModel::ptr l, IfcRepresen
bool IfcGeom::convert(const Ifc2x3::IfcHalfSpaceSolid::ptr l, TopoDS_Shape& shape) {
Ifc2x3::IfcSurface::ptr surface = l->BaseSurface();
if ( ! surface->is(Ifc2x3::Type::IfcPlane) ) {
// Not implemented
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
return false;
}
gp_Pln pln;
@@ -209,6 +213,7 @@ 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();
bool valid_shell = false;
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
@@ -216,7 +221,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
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) > GetValue(GV_MINIMAL_FACE_AREA) ) {
bool converted_face = false;
try {
converted_face = IfcGeom::convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
} else {
@@ -224,20 +233,38 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
}
}
if ( ! facesAdded ) return false;
builder.Perform();
shape = builder.SewedShape();
try {
ShapeFix_Solid solid;
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
shape = solid.SolidFromShell(TopoDS::Shell(shape));
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
} else {
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
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) > GetValue(GV_MINIMAL_FACE_AREA) ) {
bool converted_face = false;
try {
converted_face = IfcGeom::convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
@@ -256,6 +283,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, IfcRepresentationShape
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
Ifc2x3::IfcCartesianTransformationOperator3DnonUniform>(transform),gtrsf);
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
return false;
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3D) ) {
gp_Trsf trsf;
@@ -289,16 +317,20 @@ bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, IfcRepresentationShape
bool IfcGeom::convert(const Ifc2x3::IfcShapeRepresentation::ptr l, IfcRepresentationShapeItems& shapes) {
Ifc2x3::IfcRepresentationItem::list items = l->Items();
if ( ! items->Size() ) return false;
for ( Ifc2x3::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) {
Ifc2x3::IfcRepresentationItem* representation_item = *it;
if ( IfcGeom::is_shape_collection(representation_item) ) IfcGeom::convert_shapes(*it,shapes);
else {
TopoDS_Shape s;
if (IfcGeom::convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
bool part_succes = false;
if ( items->Size() ) {
for ( Ifc2x3::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) {
Ifc2x3::IfcRepresentationItem* representation_item = *it;
if ( IfcGeom::is_shape_collection(representation_item) ) {
part_succes |= IfcGeom::convert_shapes(*it, shapes);
} else {
TopoDS_Shape s;
if (IfcGeom::convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
part_succes |= true;
}
}
}
}
return true;
return part_succes;
}
+48 -23
View File
@@ -262,13 +262,20 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
Ifc2x3::IfcCartesianPoint::list points = l->Points();
BRepBuilderAPI_MakeWire w;
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,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
P1 = P2;
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::convert(*it, pnt);
polygon.Append(pnt);
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, false);
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
result = w.Wire();
@@ -277,23 +284,41 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
Ifc2x3::IfcCartesianPoint::list points = l->Polygon();
BRepBuilderAPI_MakeWire w;
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
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,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
count ++;
} else if ( ! count ) F = P2;
P1 = P2;
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::convert(*it, pnt);
polygon.Append(pnt);
}
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
count ++;
}
if ( count < 3 ) return false;
result = w.Wire();
// A loop should consist of at least three vertices
int original_count = polygon.Length();
if (original_count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, true);
int count = polygon.Length();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
w.Close();
result = w.Wire();
return true;
}
+1 -1
View File
@@ -296,7 +296,7 @@ void IfcHierarchyHelper::addBox(Ifc2x3::IfcShapeRepresentation* rep, double w, d
points.push_back(std::pair<double, double>(w/2, -d/2));
points.push_back(std::pair<double, double>(w/2, d/2));
points.push_back(std::pair<double, double>(-w/2, d/2));
points.push_back(*points.begin());
// The call to addExtrudedPolyline() closes the polyline
addExtrudedPolyline(rep, points, h, place, place2, dir, context);
}
}
+107 -46
View File
@@ -36,6 +36,30 @@
using namespace IfcParse;
// A static locale for the real number parser. strtod() is locale-dependent, causing issues
// in locales that have ',' as a decimal separator. Therefore the non standard _strtod_l() /
// strtod_l() is used and a reference to the "C" locale is obtained here. The alternative is
// to use std::istringstream::imbue(std::locale::classic()), but there are subtleties in
// parsing in MSVC2010 and it appears to be much slower.
#ifdef _MSC_VER
static _locale_t locale = (_locale_t) 0;
void init_locale() {
if (locale == (_locale_t) 0) {
locale = _create_locale(LC_NUMERIC, "C");
}
}
#else
#ifdef __APPLE__
#include <xlocale.h>
#endif
static locale_t locale = (locale_t) 0;
void init_locale() {
if (locale == (locale_t) 0) {
locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
}
}
#endif
//
// Opens the file, gets the filesize and reads a chunk in memory
//
@@ -218,6 +242,40 @@ Tokens::~Tokens() {
delete decoder;
}
unsigned int Tokens::skipWhitespace() {
unsigned int n = 0;
while ( !stream->eof ) {
char c = stream->Peek();
if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) {
stream->Inc();
++n;
}
else break;
}
return n;
}
unsigned int Tokens::skipComment() {
char c = stream->Peek();
if (c != '/') return 0;
stream->Inc();
c = stream->Peek();
if (c != '*') {
stream->Seek(stream->Tell() - 1);
return 0;
}
unsigned int n = 2;
char p = 0;
while ( !stream->eof ) {
c = stream->Peek();
stream->Inc();
++ n;
if (c == '/' && p == '*') break;
p = c;
}
return n;
}
//
// Returns the offset of the current Token and moves cursor to next
//
@@ -225,23 +283,15 @@ Token Tokens::Next() {
if ( stream->eof ) return TokenPtr();
char c;
// Trim whitespace
while ( !stream->eof ) {
c = stream->Peek();
if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) stream->Inc();
else break;
}
while (skipWhitespace() || skipComment()) {}
if ( stream->eof ) return TokenPtr();
unsigned int pos = stream->Tell();
bool inString = false;
bool inComment = false;
char c = stream->Peek();
// If the cursor is at [()=,;$*] we know token consists of single char
if ( c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*' ) {
if (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*') {
stream->Inc();
return TokenPtr(c);
}
@@ -253,18 +303,12 @@ Token Tokens::Next() {
// Read character and increment pointer if not starting a new token
char c = stream->Peek();
if ( len && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break;
if ( len && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break;
stream->Inc();
// Skip whitespace if not in comment or string
if ( !inComment && !inString && (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) continue;
len ++;
// Keep track of whether cursor is inside a string or comment
if ( inComment && p == '*' && c == '/' ) inComment = false;
else if ( !inString && !inComment && p == '/' && c == '*' ) inComment = true;
else if ( !inComment && c == '\'' ) decoder->dryRun();
// If a string is encountered defer processing to the IfcCharacterDecoder
if ( c == '\'' ) decoder->dryRun();
p = c;
}
@@ -280,20 +324,16 @@ std::string Tokens::TokenString(unsigned int 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 ( ! stream->eof ) {
char c = stream->Peek();
if ( buffer.size() && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break;
if ( buffer.size() && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break;
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;
else if ( !inString && !inComment && p == '/' && c == '*' ) inComment = true;
else if ( !inComment && c == '\'' ) return *decoder;
if ( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) continue;
else if ( c == '\'' ) return *decoder;
else buffer.push_back(c);
p = c;
}
if ( was_eof ) stream->eof = true;
@@ -345,7 +385,15 @@ bool TokenFunc::asBool(const Token& t) {
}
double TokenFunc::asFloat(const Token& t) {
const std::string str = asString(t);
return (double) atof(str.c_str());
const char* start = str.c_str();
char* end;
#ifdef _MSC_VER
double result = _strtod_l(start,&end,locale);
#else
double result = strtod_l(start,&end,locale);
#endif
if ( start == end ) throw IfcException("Token is not a real");
return result;
}
std::string TokenFunc::asString(const Token& t) {
if ( isOperator(t,'$') ) return "";
@@ -606,6 +654,8 @@ std::string Entity::toString(bool upper) {
Load(ids, true);
}
std::stringstream ss;
ss.imbue(std::locale::classic());
std::string dt = datatype();
if ( upper ) {
for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p);
@@ -673,6 +723,10 @@ bool IfcFile::Init(void* data, int len) {
return IfcFile::Init(new IfcSpfStream(data,len));
}
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
// Initialize a "C" locale for locale-independent
// number parsing. See comment above on line 41.
init_locale();
Ifc2x3::InitStringMap();
file = f;
if ( ! file->valid ) return false;
@@ -714,40 +768,45 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
Logger::Message(Logger::LOG_ERROR,ex.what());
}
}
Ifc2x3::Type::Enum ty = entity->type();
do {
IfcEntities L = EntitiesByType(ty);
if ( L == 0 ) {
L = IfcEntities(new IfcEntityList());
bytype[ty] = L;
IfcEntities instances_by_type = EntitiesByType(ty);
if (!instances_by_type) {
instances_by_type = IfcEntities(new IfcEntityList());
bytype[ty] = instances_by_type;
}
L->push(entity);
instances_by_type->push(entity);
ty = Ifc2x3::Type::Parent(ty);
} while ( ty > -1 );
if ( byid.find(currentId) != byid.end() ) {
std::stringstream ss;
ss << "Overwriting entity with id " << currentId;
Logger::Message(Logger::LOG_WARNING,ss.str());
}
byid[currentId] = entity;
MaxId = (std::max)(MaxId,currentId);
currentId = 0;
} else {
try { token = tokens->Next(); }
catch (... ) { token = TokenPtr(); }
}
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;
} else if (entity) {
IfcEntities L = EntitiesByReference(id);
if ( L == 0 ) {
L = IfcEntities(new IfcEntityList());
byref[id] = L;
IfcEntities instances_by_ref = EntitiesByReference(id);
if (!instances_by_ref) {
instances_by_ref = IfcEntities(new IfcEntityList());
byref[id] = instances_by_ref;
}
L->push(entity);
instances_by_ref->push(entity);
}
}
previous = token;
@@ -775,16 +834,18 @@ void IfcFile::AddEntity(IfcUtil::IfcSchemaEntity entity) {
Logger::Message(Logger::LOG_ERROR,ex.what());
}
}
Ifc2x3::Type::Enum ty = entity->type();
do {
IfcEntities L = EntitiesByType(ty);
if ( L == 0 ) {
L = IfcEntities(new IfcEntityList());
bytype[ty] = L;
IfcEntities instances_by_type = EntitiesByType(ty);
if (!instances_by_type) {
instances_by_type = IfcEntities(new IfcEntityList());
bytype[ty] = instances_by_type;
}
L->push(entity);
instances_by_type->push(entity);
ty = Ifc2x3::Type::Parent(ty);
} while ( ty > -1 );
int new_id = -1;
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
if ( entity->entity->isWritable() ) {
+3 -1
View File
@@ -27,7 +27,7 @@
#ifndef IFCPARSE_H
#define IFCPARSE_H
#define IFCOPENSHELL_VERSION "0.4.0-dev"
#define IFCOPENSHELL_VERSION "0.4.0-rc2"
#include <string>
#include <sstream>
@@ -96,6 +96,8 @@ namespace IfcParse {
class Tokens {
private:
IfcCharacterDecoder* decoder;
unsigned int skipWhitespace();
unsigned int skipComment();
public:
IfcSpfStream* stream;
IfcFile* file;
+19 -5
View File
@@ -17,6 +17,9 @@
* *
********************************************************************************/
#include <iomanip>
#include <locale>
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
@@ -39,7 +42,6 @@ IfcWritableEntity::IfcWritableEntity(IfcAbstractEntity* e)
{
file = e->file;
_type = e->type();
delete _id;
_id = new int(e->id());
const unsigned int count = e->getArgumentCount();
@@ -80,6 +82,8 @@ Ifc2x3::Type::Enum IfcWritableEntity::type() const { return _type; }
bool IfcWritableEntity::is(Ifc2x3::Type::Enum v) const { return _type == v; }
std::string IfcWritableEntity::toString(bool upper) {
std::stringstream ss;
ss.imbue(std::locale::classic());
std::string dt = datatype();
if ( upper ) {
for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p);
@@ -195,7 +199,8 @@ private:
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
std::string format_double(const double& d) {
std::ostringstream oss;
oss << d;
oss.imbue(std::locale::classic());
oss << std::setprecision(15) << d;
const std::string str = oss.str();
oss.str("");
std::string::size_type e = str.find('e');
@@ -232,8 +237,11 @@ public:
void operator()(const double& i) { data << format_double(i); }
void operator()(const std::string& i) {
std::string s = i;
if (upper) s = IfcCharacterEncoder(s);
data << s;
if (upper) {
data << static_cast<std::string>(IfcCharacterEncoder(s));
} else {
data << '\'' << s << '\'';
}
}
void operator()(const std::vector<int>& i) { serialize(i); }
void operator()(const std::vector<double>& i) { serialize_double(i); }
@@ -263,7 +271,12 @@ public:
IfcWriteArgument::operator int() const { return as<int>(); }
IfcWriteArgument::operator bool() const { return as<bool>(); }
IfcWriteArgument::operator double() const { return as<double>(); }
IfcWriteArgument::operator std::string() const { return as<std::string>(); }
IfcWriteArgument::operator std::string() const {
if (argumentType() == argument_type_enumeration) {
return as<EnumerationReference>().enumeration_value;
}
return as<std::string>();
}
IfcWriteArgument::operator std::vector<double>() const { return as<std::vector<double> >(); }
IfcWriteArgument::operator std::vector<int>() const { return as<std::vector<int> >(); }
IfcWriteArgument::operator std::vector<std::string>() const { return as<std::vector<std::string > >(); }
@@ -273,6 +286,7 @@ bool IfcWriteArgument::isNull() const { return argumentType() == argument_type_n
ArgumentPtr IfcWriteArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); }
std::string IfcWriteArgument::toString(bool upper) const {
std::ostringstream str;
str.imbue(std::locale::classic());
StringBuilderVisitor v(str, upper);
container.apply_visitor(v);
return v;