mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Merge pull request #4 from aothms/ken_first_steps
IfcManifoldSolidBrep and IfcConnectedFaceSet
This commit is contained in:
@@ -9,3 +9,4 @@
|
||||
__pycache__
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
.DS_Store
|
||||
|
||||
@@ -208,7 +208,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(
|
||||
node.addMatrix(matrix_array);
|
||||
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
||||
instanceGeometry.setUrl ("#" + geom_name);
|
||||
foreach(std::string material_name, material_ids) {
|
||||
for (std::string material_name: material_ids) {
|
||||
/// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export.
|
||||
collada_id(material_name);
|
||||
COLLADASW::InstanceMaterial material (material_name, "#" + material_name);
|
||||
@@ -276,7 +276,7 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
foreach(const IfcGeom::Material& material, materials) {
|
||||
for (const IfcGeom::Material& material: materials) {
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect()
|
||||
@@ -307,7 +307,7 @@ void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationEleme
|
||||
const std::string representation_id = "representation-" + boost::lexical_cast<std::string>(o->geometry().id());
|
||||
|
||||
std::vector<std::string> material_references;
|
||||
foreach(const IfcGeom::Material& material, mesh.materials()) {
|
||||
for (const IfcGeom::Material& material: mesh.materials()) {
|
||||
if (!materials.contains(material)) {
|
||||
materials.add(material);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,8 @@ int main(int argc, char** argv) {
|
||||
"Applies --include or --exclude also to the decomposition and/or containment (IsDecomposedBy, "
|
||||
"HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. "
|
||||
"--include --traverse --names \"Level 1\" includes entity with name \"Level 1\" and all of its children.")
|
||||
("kernel", "Geometry kernel to use ('opencascade' or 'cgal'). Defaults to 'cgal'.");
|
||||
// ("kernel", "Geometry kernel to use ('opencascade' or 'cgal'). Defaults to 'cgal'.")
|
||||
("opencascade", "Use opencascade kernel rather than cgal.");
|
||||
|
||||
std::string bounds;
|
||||
boost::program_options::options_description serializer_options("Serialization options");
|
||||
@@ -286,10 +287,11 @@ int main(int argc, char** argv) {
|
||||
const bool traverse = vmap.count("traverse") != 0;
|
||||
const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ;
|
||||
|
||||
if (vmap.count("kernel") == 0) {
|
||||
std::cerr << "Using default CGAL based kernel" << std::endl;
|
||||
kernel = "cgal";
|
||||
}
|
||||
if (vmap.count("opencascade") == 1) {
|
||||
kernel = "opencascade";
|
||||
} else {
|
||||
kernel = "cgal";
|
||||
}
|
||||
|
||||
int bounding_width = -1, bounding_height = -1;
|
||||
if (vmap.count("bounds") == 1) {
|
||||
|
||||
@@ -108,6 +108,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>*
|
||||
|
||||
const bool has_uvs = !mesh.uvs().empty();
|
||||
const bool has_normals = !mesh.normals().empty();
|
||||
// std::cout << mesh.faces().size() << " vertices in face mesh" << std::endl;
|
||||
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
|
||||
@@ -341,16 +341,16 @@ void XmlSerializer::finalize() {
|
||||
ptree root, header, units, decomposition, properties, types, layers;
|
||||
|
||||
// Write the SPF header as XML nodes.
|
||||
foreach(const std::string& s, file->header().file_description().description()) {
|
||||
for (const std::string& s: file->header().file_description().description()) {
|
||||
header.add_child("file_description.description", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_name().author()) {
|
||||
for (const std::string& s: file->header().file_name().author()) {
|
||||
header.add_child("file_name.author", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_name().organization()) {
|
||||
for (const std::string& s: file->header().file_name().organization()) {
|
||||
header.add_child("file_name.organization", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_schema().schema_identifiers()) {
|
||||
for (const std::string& s: file->header().file_schema().schema_identifiers()) {
|
||||
header.add_child("file_schema.schema_identifiers", ptree(s));
|
||||
}
|
||||
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace IfcGeom {
|
||||
void include_entity_names(const std::vector<std::string>& names)
|
||||
{
|
||||
names_to_include_or_exclude.clear();
|
||||
foreach(const std::string &name, names)
|
||||
for (const std::string &name: names)
|
||||
names_to_include_or_exclude.insert(wildcard_string_to_regex(name));
|
||||
include_names_in_processing_ = true;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ namespace IfcGeom {
|
||||
void exclude_entity_names(const std::vector<std::string>& names)
|
||||
{
|
||||
names_to_include_or_exclude.clear();
|
||||
foreach(const std::string &name, names)
|
||||
for (const std::string &name: names)
|
||||
names_to_include_or_exclude.insert(wildcard_string_to_regex(name));
|
||||
include_names_in_processing_ = false;
|
||||
}
|
||||
@@ -347,7 +347,7 @@ namespace IfcGeom {
|
||||
{
|
||||
// Escape all non-"*?" regex special chars
|
||||
std::string special_chars = "\\^.$|()[]+/";
|
||||
foreach(char c, special_chars) {
|
||||
for (char c: special_chars) {
|
||||
std::string char_str(1, c);
|
||||
boost::replace_all(str, char_str, "\\" + char_str);
|
||||
}
|
||||
@@ -540,7 +540,7 @@ namespace IfcGeom {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
bool type_found = false;
|
||||
// The set is iterated over to able to filter on subtypes.
|
||||
foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) {
|
||||
for (IfcSchema::Type::Enum type: entities_to_include_or_exclude) {
|
||||
if (prod->is(type)) {
|
||||
type_found = true;
|
||||
break;
|
||||
@@ -548,7 +548,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
if (!type_found && traverse) {
|
||||
foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) {
|
||||
for (IfcSchema::Type::Enum type: entities_to_include_or_exclude) {
|
||||
IfcSchema::IfcProduct* parent, * current = prod;
|
||||
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel->get_decomposing_entity(current))) != 0) {
|
||||
if (parent->is(type)) {
|
||||
@@ -564,7 +564,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
bool name_found = false;
|
||||
foreach(const boost::regex& r, names_to_include_or_exclude) {
|
||||
for (const boost::regex& r: names_to_include_or_exclude) {
|
||||
if (prod->hasName() && boost::regex_match(prod->Name(), r)) {
|
||||
name_found = true;
|
||||
break;
|
||||
@@ -572,7 +572,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
if (!name_found && traverse) {
|
||||
foreach(const boost::regex& r, names_to_include_or_exclude) {
|
||||
for (const boost::regex& r: names_to_include_or_exclude) {
|
||||
IfcSchema::IfcProduct* parent, *current = prod;
|
||||
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel->get_decomposing_entity(current))) != 0) {
|
||||
if (parent->hasName() && boost::regex_match(parent->Name(), r)) {
|
||||
@@ -702,6 +702,14 @@ namespace IfcGeom {
|
||||
|
||||
try {
|
||||
next_shape_model = create_shape_model_for_next_entity();
|
||||
|
||||
// std::cout << "trsf" << std::endl;
|
||||
// IfcGeom::CgalPlacement *trsf = next_shape_model->transformation().data();
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
} catch (...) {}
|
||||
|
||||
if (next_shape_model) {
|
||||
|
||||
@@ -23,6 +23,216 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_shape_t&) {
|
||||
throw std::runtime_error("Not implemented IfcExtrudedAreaSolid");
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) {
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
if (height < getValue(GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_face_t face;
|
||||
if ( !convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
cgal_placement_t trsf;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf);
|
||||
}
|
||||
|
||||
cgal_direction_t dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
// std::cout << "Direction: " << dir << std::endl;
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
face_list.push_back(face);
|
||||
|
||||
for (std::vector<Kernel::Point_3>::const_iterator current_vertex = face.outer.begin();
|
||||
current_vertex != face.outer.end();
|
||||
++current_vertex) {
|
||||
std::vector<Kernel::Point_3>::const_iterator next_vertex = current_vertex;
|
||||
++next_vertex;
|
||||
if (next_vertex == face.outer.end()) {
|
||||
next_vertex = face.outer.begin();
|
||||
} cgal_face_t side_face;
|
||||
side_face.outer.push_back(*next_vertex);
|
||||
side_face.outer.push_back(*current_vertex);
|
||||
side_face.outer.push_back(*current_vertex+height*dir);
|
||||
side_face.outer.push_back(*next_vertex+height*dir);
|
||||
face_list.push_back(side_face);
|
||||
}
|
||||
|
||||
cgal_face_t top_face;
|
||||
for (std::vector<Kernel::Point_3>::const_reverse_iterator vertex = face.outer.rbegin();
|
||||
vertex != face.outer.rend();
|
||||
++vertex) {
|
||||
top_face.outer.push_back(*vertex+height*dir);
|
||||
} face_list.push_back(top_face);
|
||||
|
||||
// Naive creation
|
||||
cgal_shape_t polyhedron = CGAL::Polyhedron_3<Kernel>();
|
||||
PolyhedronBuilder builder(&face_list);
|
||||
polyhedron.delegate(builder);
|
||||
|
||||
// Stitch edges
|
||||
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);
|
||||
if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) {
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
|
||||
}
|
||||
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
|
||||
shape = polyhedron;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) {
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
if (xyz.size() == 3) {
|
||||
point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f);
|
||||
// std::cout << "Converted Point(" << point << ")" << std::endl;
|
||||
return true;
|
||||
} else {
|
||||
throw std::runtime_error("Point without 3 coordinates");
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) {
|
||||
// IN_CACHE(IfcDirection,l,cgal_direction_t,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = Kernel::Vector_3(xyz.size() ? xyz[0] : 0.0f,
|
||||
xyz.size() > 1 ? xyz[1] : 0.0f,
|
||||
xyz.size() > 2 ? xyz[2] : 0.0f);
|
||||
// CACHE(IfcDirection,l,dir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
cgal_point_t o;
|
||||
cgal_direction_t axis = Kernel::Vector_3(0,0,1);
|
||||
cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check?
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
|
||||
|
||||
// TODO: From Thomas' email. Should be checked.
|
||||
Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection);
|
||||
trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0),
|
||||
refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1),
|
||||
0.0, y.cartesian(2), 1.0, 0.0);
|
||||
|
||||
// CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
cgal_point_t o;
|
||||
cgal_direction_t axis = Kernel::Vector_3(0,0,1);
|
||||
cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check?
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
|
||||
|
||||
// std::cout << "Ref direction: " << refDirection << std::endl;
|
||||
// std::cout << "Axis: " << axis << std::endl;
|
||||
// std::cout << "Origin: " << o << std::endl;
|
||||
|
||||
// TODO: From Thomas' email. Should be checked.
|
||||
Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection);
|
||||
trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0),
|
||||
refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1),
|
||||
refDirection.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2));
|
||||
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
// CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) {
|
||||
// TODO: These macros don't work for the CGAL types. Need to check why.
|
||||
// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf)
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
// std::cout << "initial trsf (identity?)" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
for (;;) {
|
||||
cgal_placement_t trsf2;
|
||||
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
|
||||
// std::cout << "trsf2" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf2.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
trsf = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around?
|
||||
|
||||
// std::cout << "trsf (after multiplication)" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
// CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel::Point_3( x, -y, 0.0));
|
||||
face.outer.push_back(Kernel::Point_3( x, y, 0.0));
|
||||
face.outer.push_back(Kernel::Point_3(-x, y, 0.0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,47 @@
|
||||
#include "CgalConversionResult.h"
|
||||
|
||||
void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
|
||||
throw std::runtime_error("Not implemented Triangulate()");
|
||||
cgal_shape_t s = shape_;
|
||||
const cgal_placement_t& trsf = dynamic_cast<const CgalPlacement*>(place)->trsf();
|
||||
// std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
|
||||
// std::cout << "Valid: " << s.is_valid() << std::endl;
|
||||
|
||||
// Apply transformation
|
||||
if (place != NULL) for (auto &vertex: vertices(s)) {
|
||||
vertex->point() = vertex->point().transform(trsf);
|
||||
}
|
||||
|
||||
// Triangulate the shape and compute the normals
|
||||
std::map<cgal_vertex_descriptor_t, Kernel::Vector_3> vertex_normals;
|
||||
boost::associative_property_map<std::map<cgal_vertex_descriptor_t, Kernel::Vector_3>> vertex_normals_map(vertex_normals);
|
||||
std::map<cgal_face_descriptor_t, Kernel::Vector_3> face_normals;
|
||||
boost::associative_property_map<std::map<cgal_face_descriptor_t, Kernel::Vector_3>> face_normals_map(face_normals);
|
||||
if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) {
|
||||
// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
|
||||
CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map);
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0, num_vertices = 0;
|
||||
for (auto &face: faces(s)) {
|
||||
CGAL::Polyhedron_3<Kernel>::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin();
|
||||
do {
|
||||
t->addVertex(surface_style_id,
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(0)),
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)),
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(2)));
|
||||
for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i)));
|
||||
t->faces().push_back(num_vertices);
|
||||
++num_vertices;
|
||||
++current_halfedge;
|
||||
} while (current_halfedge != face->facet_begin());
|
||||
t->material_ids().push_back(surface_style_id);
|
||||
++num_faces;
|
||||
}
|
||||
|
||||
// std::cout << num_faces << " faces" << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -34,16 +34,17 @@ namespace IfcGeom {
|
||||
operator const cgal_placement_t& () { return trsf_; }
|
||||
|
||||
virtual double Value(int i, int j) const {
|
||||
// Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics.
|
||||
throw std::runtime_error("Not implemented");
|
||||
// TODO: Check
|
||||
// std::cout << "Getting CgalPlacement with i = " << i << " and j = " << j << std::endl;
|
||||
return CGAL::to_double(trsf_.cartesian(i-1, j-1));
|
||||
}
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
// Multiply matrix as implemented in OCCT. We'll have to check exact semantics.
|
||||
throw std::runtime_error("Not implemented");
|
||||
// TODO: Check
|
||||
trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_;
|
||||
}
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
// PreMultiply matrix as implemented in OCCT. We'll have to check exact semantics.
|
||||
throw std::runtime_error("Not implemented");
|
||||
// TODO: Check
|
||||
trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_;
|
||||
}
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new CgalPlacement(trsf_);
|
||||
@@ -51,7 +52,7 @@ namespace IfcGeom {
|
||||
private:
|
||||
cgal_placement_t trsf_;
|
||||
};
|
||||
|
||||
|
||||
class CgalShape : public ConversionResultShape {
|
||||
public:
|
||||
CgalShape(const cgal_shape_t& shape)
|
||||
@@ -74,4 +75,4 @@ namespace IfcGeom {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -67,7 +67,7 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r)
|
||||
}
|
||||
|
||||
if ( processed && success ) {
|
||||
const double precision = getValue(GV_PRECISION);
|
||||
// const double precision = getValue(GV_PRECISION);
|
||||
// apply_tolerance(r, precision);
|
||||
#ifndef NO_CACHE
|
||||
cache.Shape[id] = r;
|
||||
@@ -81,6 +81,79 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) {
|
||||
cgal_shape_t s;
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
if (convert_shape(l->Outer(),s) ) {
|
||||
const SurfaceStyle* indiv_style = get_style(l->Outer());
|
||||
|
||||
IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list);
|
||||
if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) {
|
||||
voids = l->as<IfcSchema::IfcFacetedBrepWithVoids>()->Voids();
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) {
|
||||
voids = l->as<IfcSchema::IfcAdvancedBrepWithVoids>()->Voids();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) {
|
||||
// TopoDS_Shape s2;
|
||||
// /// @todo No extensive shapefixing since shells should be disjoint.
|
||||
// /// @todo Awaiting generalized boolean ops module with appropriate checking
|
||||
// if (convert_shape(l->Outer(), s2)) {
|
||||
// s = BRepAlgoAPI_Cut(s, s2).Shape();
|
||||
// }
|
||||
}
|
||||
|
||||
shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) {
|
||||
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
|
||||
bool success = false;
|
||||
cgal_face_t face;
|
||||
|
||||
try {
|
||||
success = convert_face(*it, face);
|
||||
} catch (...) {}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity);
|
||||
continue;
|
||||
}
|
||||
|
||||
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
|
||||
// for (auto &point: face.outer) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
face_list.push_back(face);
|
||||
}
|
||||
|
||||
// Naive creation
|
||||
cgal_shape_t polyhedron = CGAL::Polyhedron_3<Kernel>();
|
||||
PolyhedronBuilder builder(&face_list);
|
||||
polyhedron.delegate(builder);
|
||||
|
||||
// Stitch edges
|
||||
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);
|
||||
if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) {
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
|
||||
}
|
||||
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
|
||||
shape = polyhedron;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_wire(const IfcBaseClass* l, cgal_wire_t& r) {
|
||||
#include "CgalEntityMappingWire.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
@@ -93,6 +166,94 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++;
|
||||
}
|
||||
|
||||
if (num_outer_bounds != 1) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_face_t mf;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
IfcSchema::IfcLoop* loop = bound->Bound();
|
||||
|
||||
const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound);
|
||||
|
||||
cgal_wire_t wire;
|
||||
if (!convert_wire(loop, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_interior) {
|
||||
mf.outer = wire;
|
||||
} else {
|
||||
mf.inner.push_back(wire);
|
||||
}
|
||||
}
|
||||
|
||||
face = mf;
|
||||
|
||||
// std::cout << "Face: " << std::endl;
|
||||
// for (auto &point: face.outer) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
cgal_wire_t polygon = std::vector<Kernel::Point_3>();
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
cgal_point_t pnt;
|
||||
IfcGeom::CgalKernel::convert(*it, pnt);
|
||||
polygon.push_back(pnt);
|
||||
}
|
||||
|
||||
// A loop should consist of at least three vertices
|
||||
std::size_t original_count = polygon.size();
|
||||
if (original_count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Remove repeated points (and points that are too close to one another?)
|
||||
// remove_duplicate_points_from_loop(polygon, true);
|
||||
|
||||
std::size_t count = polygon.size();
|
||||
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;
|
||||
}
|
||||
|
||||
result = polygon;
|
||||
|
||||
// std::cout << "PolyLoop: " << std::endl;
|
||||
// for (auto &point: polygon) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_curve(const IfcBaseClass* l, cgal_curve_t& r) {
|
||||
#include "CgalEntityMappingCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -29,7 +29,22 @@
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
|
||||
SHAPES(IfcRepresentation);
|
||||
// IfcFacetedBrep included
|
||||
// IfcAdvancedBrep included
|
||||
// IfcFacetedBrepWithVoids included
|
||||
// IfcAdvancedBrepWithVoids included
|
||||
SHAPES(IfcManifoldSolidBrep);
|
||||
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
|
||||
FACE(IfcFace);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
|
||||
WIRE(IfcPolyLoop);
|
||||
|
||||
CLASS(IfcCartesianPoint,cgal_point_t);
|
||||
CLASS(IfcDirection,cgal_direction_t);
|
||||
CLASS(IfcAxis2Placement2D,cgal_placement_t);
|
||||
CLASS(IfcAxis2Placement3D,cgal_placement_t);
|
||||
CLASS(IfcObjectPlacement,cgal_placement_t);
|
||||
|
||||
@@ -94,8 +94,15 @@ IfcGeom::NativeElement<double>* IfcGeom::CgalKernel::create_brep_for_representat
|
||||
|
||||
cgal_placement_t trsf;
|
||||
try {
|
||||
// convert(product->ObjectPlacement(), trsf);
|
||||
convert(product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
|
||||
// std::cout << "trsf" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
@@ -107,9 +114,24 @@ IfcGeom::NativeElement<double>* IfcGeom::CgalKernel::create_brep_for_representat
|
||||
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions");
|
||||
}
|
||||
|
||||
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
|
||||
|
||||
|
||||
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
// TODO: OpenCascade code uses opened_shapes. Check why.
|
||||
for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
it->prepend(new CgalPlacement(trsf));
|
||||
}
|
||||
trsf = Kernel::Aff_transformation_3();
|
||||
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
|
||||
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
it->prepend(new CgalPlacement(trsf));
|
||||
}
|
||||
trsf = Kernel::Aff_transformation_3();
|
||||
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
|
||||
} else {
|
||||
shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes);
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
@@ -146,7 +168,7 @@ IfcGeom::NativeElement<double>* IfcGeom::CgalKernel::create_brep_for_processed_r
|
||||
|
||||
cgal_placement_t trsf;
|
||||
try {
|
||||
// convert(product->ObjectPlacement(), trsf);
|
||||
convert(product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
|
||||
std::string context_string = "";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -37,12 +37,76 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
|
||||
typedef void* cgal_shape_t;
|
||||
typedef void* cgal_face_t;
|
||||
typedef void* cgal_wire_t;
|
||||
typedef void* cgal_curve_t;
|
||||
typedef void* cgal_placement_t;
|
||||
typedef void* cgal_point_t;
|
||||
#undef Handle
|
||||
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
|
||||
typedef Kernel::Aff_transformation_3 cgal_placement_t;
|
||||
typedef Kernel::Point_3 cgal_point_t;
|
||||
typedef Kernel::Vector_3 cgal_direction_t;
|
||||
typedef std::vector<Kernel::Point_3> cgal_curve_t;
|
||||
typedef std::vector<Kernel::Point_3> cgal_wire_t;
|
||||
|
||||
struct cgal_face_t {
|
||||
cgal_wire_t outer;
|
||||
std::vector<cgal_wire_t> inner;
|
||||
};
|
||||
|
||||
typedef CGAL::Polyhedron_3<Kernel> cgal_shape_t;
|
||||
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel>>::vertex_descriptor cgal_vertex_descriptor_t;
|
||||
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel>>::face_descriptor cgal_face_descriptor_t;
|
||||
|
||||
struct PolyhedronBuilder : public CGAL::Modifier_base<CGAL::Polyhedron_3<Kernel>::HalfedgeDS> {
|
||||
private:
|
||||
std::list<cgal_face_t> *face_list;
|
||||
public:
|
||||
PolyhedronBuilder(std::list<cgal_face_t> *face_list) {
|
||||
this->face_list = face_list;
|
||||
}
|
||||
|
||||
void operator()(CGAL::Polyhedron_3<Kernel>::HalfedgeDS &hds) {
|
||||
std::list<Kernel::Point_3> points;
|
||||
std::list<std::list<std::size_t>> facet_vertices;
|
||||
CGAL::Polyhedron_incremental_builder_3<CGAL::Polyhedron_3<Kernel>::HalfedgeDS> builder(hds, true);
|
||||
|
||||
for (auto &face: *face_list) {
|
||||
facet_vertices.push_back(std::list<std::size_t>());
|
||||
for (auto &point: face.outer) {
|
||||
facet_vertices.back().push_back(points.size());
|
||||
points.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
builder.begin_surface(points.size(), facet_vertices.size());
|
||||
|
||||
for (auto &point: points) {
|
||||
// std::cout << "Adding point " << point << std::endl;
|
||||
builder.add_vertex(point);
|
||||
}
|
||||
|
||||
for (auto &facet: facet_vertices) {
|
||||
builder.begin_facet();
|
||||
// std::cout << "Adding facet ";
|
||||
for (auto &vertex: facet) {
|
||||
// std::cout << vertex << " ";
|
||||
builder.add_vertex_to_facet(vertex);
|
||||
}
|
||||
// std::cout << std::endl;
|
||||
builder.end_facet();
|
||||
}
|
||||
|
||||
builder.end_surface();
|
||||
}
|
||||
};
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
@@ -90,4 +154,4 @@ namespace IfcGeom {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#define foreach BOOST_FOREACH
|
||||
//#define foreach BOOST_FOREACH
|
||||
#define rforeach BOOST_REVERSE_FOREACH
|
||||
|
||||
class Argument;
|
||||
|
||||
Reference in New Issue
Block a user