mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 16:01:36 +00:00
Compare commits
43 Commits
tfk-cli-plot
...
v0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e39cbc6d00 | |||
| 9619543137 | |||
| ab4d3b8cad | |||
| 8c7346a669 | |||
| 65b0f22c76 | |||
| d79120dfcc | |||
| 687cda0c4d | |||
| 2b5f797913 | |||
| d3538cc7d4 | |||
| 6bae80b70f | |||
| 336b07a7a2 | |||
| 3b157b0f3e | |||
| 414b761453 | |||
| 53c95db28f | |||
| d1c91d3c47 | |||
| 61d73ebfd6 | |||
| 0fd88be5a3 | |||
| 5fdefceddd | |||
| d28871e7fc | |||
| 33625c6422 | |||
| f68060f566 | |||
| dce878515e | |||
| 843f08c0a6 | |||
| 577565a494 | |||
| 18620d29ae | |||
| 79839d487a | |||
| f3622f9339 | |||
| 1be3f63d63 | |||
| 6fe2e2366d | |||
| 4242bb7c1b | |||
| d821324e28 | |||
| 1bbd08f1a4 | |||
| 9a1db57f3c | |||
| be8cfeeadf | |||
| f387090078 | |||
| 790bdee195 | |||
| fcbcec78e9 | |||
| bd02aac18a | |||
| b6a811ae7e | |||
| e24260015f | |||
| fa195194c6 | |||
| a5e466b53a | |||
| 896607e535 |
@@ -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():
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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...");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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() ) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user