mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 09:32:37 +00:00
Proceed with merge
This commit is contained in:
@@ -44,7 +44,7 @@
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/Serialization.h"
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/Serialization.h"
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
|
||||
@@ -35,10 +35,9 @@
|
||||
#include "../serializers/XmlSerializer.h"
|
||||
#include "../serializers/SvgSerializer.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../ifcgeom/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/Iterator.h"
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "../ifcparse/utils.h"
|
||||
|
||||
@@ -212,6 +211,7 @@ int main(int argc, char** argv) {
|
||||
path_t log_file;
|
||||
path_t cache_file;
|
||||
std::string log_format;
|
||||
std::string geometry_kernel;
|
||||
|
||||
po::options_description generic_options("Command line options");
|
||||
verbosity_counter vcounter;
|
||||
@@ -249,9 +249,19 @@ int main(int argc, char** argv) {
|
||||
|
||||
int num_threads;
|
||||
std::string offset_str, rotation_str;
|
||||
|
||||
std::string default_kernel;
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
default_kernel = "cgal";
|
||||
#endif
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
default_kernel = "opencascade";
|
||||
#endif
|
||||
|
||||
po::options_description geom_options("Geometry options");
|
||||
geom_options.add_options()
|
||||
("kernel", po::value<std::string>(&geometry_kernel)->default_value(default_kernel),
|
||||
"Geometry kernel to use (opencascade or cgal).")
|
||||
("threads,j", po::value<int>(&num_threads)->default_value(1),
|
||||
"Number of parallel processing threads for geometry interpretation.")
|
||||
("plan",
|
||||
@@ -799,7 +809,7 @@ int main(int argc, char** argv) {
|
||||
SerializerSettings settings;
|
||||
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
|
||||
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == OBJ);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == OBJ || output_extension == STP || output_extension == IGS);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, orient_shells || output_extension == SVG); // svg depends on correct solids for boolean subtractions for hlr
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units);
|
||||
@@ -835,7 +845,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (vmap.count("force-space-transparency")) {
|
||||
settings.force_space_transparency(force_space_transparency);
|
||||
IfcGeom::update_default_style("IfcSpace").Transparency().reset(force_space_transparency);
|
||||
IfcGeom::update_default_style("IfcSpace").transparency = force_space_transparency;
|
||||
}
|
||||
|
||||
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
|
||||
@@ -950,7 +960,7 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
IfcGeom::Iterator tmp_context_iterator(settings, ifc_file, filter_funcs, num_threads);
|
||||
IfcGeom::Iterator tmp_context_iterator(geometry_kernel, settings, ifc_file, filter_funcs, num_threads);
|
||||
|
||||
time_t start, end;
|
||||
time(&start);
|
||||
@@ -973,10 +983,10 @@ int main(int argc, char** argv) {
|
||||
time(&end);
|
||||
if (!quiet) Logger::Status("Done ! Bounds computed in " + format_duration(start, end));
|
||||
|
||||
gp_XYZ center = (tmp_context_iterator.bounds_min() + tmp_context_iterator.bounds_max()) * 0.5;
|
||||
offset[0] = -center.X();
|
||||
offset[1] = -center.Y();
|
||||
offset[2] = -center.Z();
|
||||
auto center = (tmp_context_iterator.bounds_min().ccomponents() + tmp_context_iterator.bounds_max().ccomponents()) * 0.5;
|
||||
offset[0] = -center(0);
|
||||
offset[1] = -center(1);
|
||||
offset[2] = -center(2);
|
||||
} else {
|
||||
if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) {
|
||||
cerr_ << "[Error] Invalid use of --model-offset\n";
|
||||
@@ -991,7 +1001,7 @@ int main(int argc, char** argv) {
|
||||
Logger::Notice(msg.str());
|
||||
}
|
||||
|
||||
IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, num_threads);
|
||||
IfcGeom::Iterator context_iterator(geometry_kernel, settings, ifc_file, filter_funcs, num_threads);
|
||||
|
||||
#ifdef WITH_HDF5
|
||||
std::unique_ptr<HdfSerializer> cache;
|
||||
@@ -1107,7 +1117,7 @@ int main(int argc, char** argv) {
|
||||
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
|
||||
// wrap an iterator of all geometrical products in the Ifc file.
|
||||
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
|
||||
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
|
||||
// -BRepElement pointer, based on current settings. (see Iterator.h
|
||||
// for definition) IfcGeom::Iterator::next() is used to poll whether more
|
||||
// geometrical entities are available. None of these functions throw
|
||||
// exceptions, neither for parsing errors or geometrical errors. Upon
|
||||
@@ -1539,7 +1549,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
|
||||
IfcGeom::Iterator context_iterator(settings, &f);
|
||||
IfcGeom::Iterator context_iterator(settings, &f, {}, 1);
|
||||
|
||||
if (!context_iterator.initialize()) {
|
||||
return;
|
||||
@@ -1586,7 +1596,8 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
}
|
||||
|
||||
if (geom_object && geom_object->geometry_pointer() == previous_geometry_pointer) {
|
||||
objects->push(geom_object->product());
|
||||
// @todo
|
||||
objects->push(const_cast<IfcUtil::IfcBaseEntity*>(geom_object->product()));
|
||||
} else {
|
||||
if (quantity) {
|
||||
auto rel = latebound_access::create(f, "IfcRelDefinesByProperties");
|
||||
@@ -1633,7 +1644,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
auto quantity_count = latebound_access::create(f, "IfcQuantityCount");
|
||||
latebound_access::set(quantity_count, "Name", std::string("Surface Genus"));
|
||||
latebound_access::set(quantity_count, "Description", '#' + boost::lexical_cast<std::string>(part.ItemId()));
|
||||
latebound_access::set(quantity_count, "CountValue", IfcGeom::util::surface_genus(part.Shape()));
|
||||
latebound_access::set(quantity_count, "CountValue", part.Shape()->surface_genus());
|
||||
|
||||
quantities_2->push(quantity_count);
|
||||
}
|
||||
@@ -1647,7 +1658,8 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
}
|
||||
|
||||
objects.reset(new aggregate_of_instance);
|
||||
objects->push(geom_object->product());
|
||||
// @todo
|
||||
objects->push(const_cast<IfcUtil::IfcBaseEntity*>(geom_object->product()));
|
||||
}
|
||||
|
||||
previous_geometry_pointer = geom_object->geometry_pointer();
|
||||
|
||||
@@ -43,14 +43,14 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
return;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::settings settings;
|
||||
IfcGeom::IteratorSettings settings;
|
||||
|
||||
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
|
||||
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
|
||||
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
|
||||
ifcopenshell::geometry::Converter c("cgal", &f2, settings);
|
||||
|
||||
@@ -72,7 +72,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
for (auto& e : wire->children) {
|
||||
auto edge = (taxonomy::edge*) e;
|
||||
auto p3 = boost::get<taxonomy::point3>(edge->start);
|
||||
auto p4 = *((taxonomy::geom_item*)item)->matrix.components * p3.components->homogeneous();
|
||||
auto p4 = ((taxonomy::geom_item*)item)->matrix.ccomponents() * p3.ccomponents().homogeneous();
|
||||
Kernel_::Point_3 P(p4(0), p4(1), p4(2));
|
||||
elem_to_space_boundary_coords[{g1, g2}].emplace_back(P);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/Iterator.h"
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
@@ -8,29 +8,29 @@
|
||||
#include <algorithm>
|
||||
|
||||
void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
ifcopenshell::geometry::settings settings;
|
||||
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
|
||||
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
|
||||
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
|
||||
std::vector<ifcopenshell::geometry::filter_t> no_openings_and_spaces = {
|
||||
IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"})
|
||||
};
|
||||
|
||||
ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces);
|
||||
IfcGeom::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces, 1);
|
||||
|
||||
auto get_elevation = [](IfcUtil::IfcBaseClass* a) {
|
||||
return ((IfcUtil::IfcBaseEntity*)a)->get_value_or<double>("Elevation", 0.);
|
||||
auto get_elevation = [](const IfcUtil::IfcBaseClass* a) {
|
||||
return ((const IfcUtil::IfcBaseEntity*)a)->get_value<double>("Elevation", 0.);
|
||||
};
|
||||
|
||||
// latebound inverse attribute lookup not working
|
||||
auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure");
|
||||
std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> elem_to_storey;
|
||||
std::map<const IfcUtil::IfcBaseClass*, const IfcUtil::IfcBaseClass*> elem_to_storey;
|
||||
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](IfcUtil::IfcBaseClass* r) {
|
||||
auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcEntityList::ptr>("RelatedElements");
|
||||
auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value<aggregate_of_instance::ptr>("RelatedElements");
|
||||
auto storey = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcUtil::IfcBaseClass*>("RelatingStructure");
|
||||
|
||||
if (storey->declaration().name() == "IfcBuildingStorey") {
|
||||
@@ -41,8 +41,8 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
});
|
||||
|
||||
auto storeys = f.instances_by_type("IfcBuildingStorey");
|
||||
std::vector<IfcUtil::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
|
||||
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) {
|
||||
std::vector<const IfcUtil::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
|
||||
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](const IfcUtil::IfcBaseClass* a, const IfcUtil::IfcBaseClass* b) {
|
||||
return get_elevation(a) < get_elevation(b);
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
if (num_created) {
|
||||
has_more = context_iterator.next();
|
||||
}
|
||||
ifcopenshell::geometry::NativeElement* geom_object = nullptr;
|
||||
IfcGeom::BRepElement* geom_object = nullptr;
|
||||
if (has_more) {
|
||||
geom_object = context_iterator.get_native();
|
||||
}
|
||||
@@ -132,8 +132,8 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
|
||||
for (auto& g : geom_object->geometry()) {
|
||||
auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape();
|
||||
const auto& m = *g.Placement().components;
|
||||
const auto& n = *geom_object->transformation().data().components;
|
||||
const auto& m = g.Placement().ccomponents();
|
||||
const auto& n = geom_object->transformation().data().ccomponents();
|
||||
|
||||
const cgal_placement_t trsf(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
|
||||
@@ -11,16 +11,16 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress);
|
||||
|
||||
|
||||
ifcopenshell::geometry::settings settings;
|
||||
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
|
||||
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
|
||||
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
|
||||
settings.set(ifcopenshell::geometry::settings::INCLUDE_CURVES, true);
|
||||
settings.set(ifcopenshell::geometry::settings::EXCLUDE_SOLIDS_AND_SURFACES, true);
|
||||
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
|
||||
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, true);
|
||||
|
||||
ifcopenshell::geometry::Converter c("cgal", &f, settings);
|
||||
|
||||
@@ -106,7 +106,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
return;
|
||||
}
|
||||
|
||||
auto get_axis_parameter_min_max = [&c, &x_poly](IfcUtil::IfcBaseEntity* inst) {
|
||||
auto get_axis_parameter_min_max = [&c, &x_poly](const IfcUtil::IfcBaseEntity* inst) {
|
||||
auto item = c.mapping()->map(inst);
|
||||
auto shaperep = ((taxonomy::collection*) item)->children[0];
|
||||
auto loop = ((taxonomy::collection*) shaperep)->children[0];
|
||||
@@ -123,8 +123,8 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
auto p0 = boost::get<taxonomy::point3>(first_vertex);
|
||||
auto p1 = boost::get<taxonomy::point3>(last_vertex);
|
||||
|
||||
auto v0 = *((taxonomy::geom_item*)item)->matrix.components * p0.components->homogeneous();
|
||||
auto v1 = *((taxonomy::geom_item*)item)->matrix.components * p1.components->homogeneous();
|
||||
auto v0 = ((taxonomy::geom_item*)item)->matrix.ccomponents() * p0.ccomponents().homogeneous();
|
||||
auto v1 = ((taxonomy::geom_item*)item)->matrix.ccomponents() * p1.ccomponents().homogeneous();
|
||||
|
||||
auto P0 = Kernel_::Point_3(v0(0), v0(1), v0(2));
|
||||
auto P1 = Kernel_::Point_3(v1(0), v1(1), v1(2));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/Iterator.h"
|
||||
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/minkowski_sum_3.h>
|
||||
@@ -415,7 +415,7 @@ struct remove_thickness {
|
||||
|
||||
|
||||
struct intersection_validator {
|
||||
typedef std::list<std::pair<IfcUtil::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
|
||||
typedef std::list<std::pair<const IfcUtil::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
|
||||
typedef CGAL::Box_intersection_d::Box_with_handle_d<double, 3, nefs_t::value_type*> Box;
|
||||
|
||||
std::vector<Box> boxes;
|
||||
@@ -427,23 +427,23 @@ struct intersection_validator {
|
||||
double total_minkowsky_time = 0.;
|
||||
double total_box_time = 0.;
|
||||
|
||||
std::set<IfcUtil::IfcBaseEntity*> succesfully_processed;
|
||||
std::set<const IfcUtil::IfcBaseEntity*> succesfully_processed;
|
||||
|
||||
intersection_validator(IfcParse::IfcFile& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
|
||||
ifcopenshell::geometry::settings settings;
|
||||
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
|
||||
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
|
||||
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true);
|
||||
|
||||
std::vector<ifcopenshell::geometry::filter_t> spaces_and_walls = {
|
||||
IfcGeom::entity_filter(true, false, entities)
|
||||
};
|
||||
|
||||
ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls);
|
||||
IfcGeom::Iterator context_iterator("cgal", settings, &f, spaces_and_walls, 1);
|
||||
|
||||
if (!context_iterator.initialize()) {
|
||||
return;
|
||||
@@ -460,7 +460,7 @@ struct intersection_validator {
|
||||
if (num_created) {
|
||||
has_more = context_iterator.next();
|
||||
}
|
||||
ifcopenshell::geometry::NativeElement* geom_object = nullptr;
|
||||
IfcGeom::BRepElement* geom_object = nullptr;
|
||||
if (has_more) {
|
||||
geom_object = context_iterator.get_native();
|
||||
}
|
||||
@@ -475,8 +475,8 @@ struct intersection_validator {
|
||||
|
||||
for (auto& g : geom_object->geometry()) {
|
||||
auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape();
|
||||
const auto& m = *g.Placement().components;
|
||||
const auto& n = *geom_object->transformation().data().components;
|
||||
const auto& m = g.Placement().ccomponents();
|
||||
const auto& n = geom_object->transformation().data().ccomponents();
|
||||
|
||||
const cgal_placement_t trsf(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
@@ -566,8 +566,11 @@ struct intersection_validator {
|
||||
" objects ");
|
||||
}
|
||||
|
||||
/*
|
||||
// @todo
|
||||
total_geom_time = context_iterator.converter().total_geom_time;
|
||||
total_map_time = context_iterator.converter().total_map_time;
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "AbstractKernel.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
|
||||
#undef Handle
|
||||
#endif
|
||||
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
|
||||
#endif
|
||||
|
||||
bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, IfcGeom::ConversionResults& results) {
|
||||
// std::stringstream ss;
|
||||
// item->print(ss);
|
||||
// auto sss = ss.str();
|
||||
// std::wcout << sss.c_str() << std::endl;
|
||||
|
||||
try {
|
||||
return dispatch_conversion<0>::dispatch(this, item, results);
|
||||
} catch (std::exception& e) {
|
||||
Logger::Error(e, item->instance);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const ConversionSettings & ifcopenshell::geometry::kernels::AbstractKernel::settings() const
|
||||
{
|
||||
return conv_settings_;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, const ConversionSettings& conv_settings) {
|
||||
const std::string geometry_library_lower = boost::to_lower_copy(geometry_library);
|
||||
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
if (geometry_library_lower == "opencascade") {
|
||||
return new IfcGeom::OpenCascadeKernel(conv_settings);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
if (geometry_library_lower == "cgal") {
|
||||
return new CgalKernel(conv_settings);
|
||||
}
|
||||
#endif
|
||||
|
||||
throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library);
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::collection* collection, IfcGeom::ConversionResults& r) {
|
||||
auto s = r.size();
|
||||
for (auto& c : collection->children) {
|
||||
convert(c, r);
|
||||
}
|
||||
for (auto i = s; i < r.size(); ++i) {
|
||||
r[i].prepend(collection->matrix);
|
||||
if (!r[i].hasStyle() && collection->surface_style) {
|
||||
r[i].setStyle(*collection->surface_style);
|
||||
}
|
||||
}
|
||||
return r.size() > s;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef ABSTRACT_KERNEL_H
|
||||
#define ABSTRACT_KERNEL_H
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
|
||||
static const double ALMOST_ZERO = 1.e-9;
|
||||
|
||||
template <typename T>
|
||||
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = ALMOST_ZERO) {
|
||||
return fabs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
namespace ifcopenshell { namespace geometry { namespace kernels {
|
||||
|
||||
class IFC_GEOM_API AbstractKernel {
|
||||
protected:
|
||||
std::string geometry_library;
|
||||
ConversionSettings conv_settings_;
|
||||
|
||||
public:
|
||||
AbstractKernel(const std::string& geometry_library, const ConversionSettings& settings)
|
||||
: geometry_library(geometry_library)
|
||||
, conv_settings_(settings) {}
|
||||
|
||||
bool convert(const taxonomy::item*, IfcGeom::ConversionResults&);
|
||||
const ConversionSettings& settings() const;
|
||||
|
||||
virtual bool convert_impl(const taxonomy::matrix4*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::point3*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::direction3*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::line*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::circle*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::ellipse*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::bspline_curve*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::edge*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::loop*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::shell*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::face*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::extrusion*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::node*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::colour*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::boolean_result*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::plane*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::offset_curve*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::revolve*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::bspline_surface*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::cylinder*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::solid*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::surface_curve_sweep*, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::collection*, IfcGeom::ConversionResults&);
|
||||
|
||||
/*
|
||||
virtual void set_offset(const std::array<double, 3> &p_offset);
|
||||
virtual void set_rotation(const std::array<double, 4> &p_rotation);
|
||||
*/
|
||||
|
||||
virtual bool apply_layerset(IfcGeom::ConversionResults&, const ifcopenshell::geometry::layerset_information&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool apply_folded_layerset(IfcGeom::ConversionResults&, const ifcopenshell::geometry::layerset_information&, const std::map<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::layerset_information>&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::item*, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes) = 0;
|
||||
|
||||
};
|
||||
|
||||
AbstractKernel* construct(const std::string& geometry_library, const ConversionSettings& conv_settings);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
/* A compile-time for loop over the taxonomy kinds */
|
||||
template <size_t N>
|
||||
struct dispatch_conversion {
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::item* item, IfcGeom::ConversionResults& results) {
|
||||
if (N == item->kind()) {
|
||||
auto concrete_item = static_cast<const ifcopenshell::geometry::taxonomy::type_by_kind::type<N>*>(item);
|
||||
return kernel->convert_impl(concrete_item, results);
|
||||
} else {
|
||||
return dispatch_conversion<N + 1>::dispatch(kernel, item, results);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct dispatch_conversion<ifcopenshell::geometry::taxonomy::type_by_kind::max> {
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item* item, IfcGeom::ConversionResults&) {
|
||||
Logger::Error("No conversion for " + std::to_string(item->kind()));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* A compile-time for loop over the curve kinds */
|
||||
template <typename T, size_t N = 0>
|
||||
struct dispatch_curve_creation {
|
||||
static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) {
|
||||
// @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind()
|
||||
const ifcopenshell::geometry::taxonomy::curves::type<N>* v = dynamic_cast<const ifcopenshell::geometry::taxonomy::curves::type<N>*>(item);
|
||||
if (v) {
|
||||
visitor(*v);
|
||||
return true;
|
||||
} else {
|
||||
return dispatch_curve_creation<T, N + 1>::dispatch(item, visitor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct dispatch_curve_creation<T, ifcopenshell::geometry::taxonomy::curves::max> {
|
||||
static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T&) {
|
||||
Logger::Error("No conversion for " + std::to_string(item->kind()));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,9 @@
|
||||
#ifndef IFCSHAPELIST_H
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom/IteratorSettings.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
@@ -28,37 +30,74 @@
|
||||
#include <vector>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API IfcRepresentationShapeItem {
|
||||
|
||||
namespace Representation {
|
||||
class IFC_GEOM_API Triangulation;
|
||||
}
|
||||
|
||||
class IFC_GEOM_API ConversionResultShape {
|
||||
public:
|
||||
virtual void Triangulate(const IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const = 0;
|
||||
|
||||
virtual void Serialize(std::string&) const = 0;
|
||||
virtual ConversionResultShape* clone() const = 0;
|
||||
virtual int surface_genus() const = 0;
|
||||
virtual bool is_manifold() const = 0;
|
||||
// @todo this must be something with a virtual dtor so that we can delete it.
|
||||
virtual double bounding_box(void*& b) const = 0;
|
||||
virtual int num_vertices() const = 0;
|
||||
virtual void set_box(void* b) = 0;
|
||||
virtual ~ConversionResultShape() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ConversionResult {
|
||||
private:
|
||||
int id;
|
||||
gp_GTrsf placement;
|
||||
TopoDS_Shape shape;
|
||||
std::shared_ptr<const SurfaceStyle> style;
|
||||
ifcopenshell::geometry::taxonomy::matrix4 placement;
|
||||
ConversionResultShape* shape;
|
||||
ifcopenshell::geometry::taxonomy::style style_;
|
||||
public:
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape, std::shared_ptr<const SurfaceStyle> style)
|
||||
: id(id), placement(placement), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape)
|
||||
: id(id), placement(placement), shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape, std::shared_ptr<const SurfaceStyle> style)
|
||||
: id(id), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape)
|
||||
: id(id), shape(shape), style(0) {}
|
||||
void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); }
|
||||
void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); }
|
||||
const TopoDS_Shape& Shape() const { return shape; }
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return !!style; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
const std::shared_ptr<const SurfaceStyle> StylePtr() const { return style; }
|
||||
void setStyle(std::shared_ptr<const SurfaceStyle> newStyle) { style = newStyle; }
|
||||
ConversionResult(int id, const ifcopenshell::geometry::taxonomy::matrix4& placement, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style* style)
|
||||
: id(id), placement(placement), shape(shape->clone())
|
||||
{
|
||||
if (style) {
|
||||
style_ = *style;
|
||||
}
|
||||
}
|
||||
ConversionResult(int id, const ifcopenshell::geometry::taxonomy::matrix4& placement, const ConversionResultShape* shape)
|
||||
: id(id), placement(placement), shape(shape->clone()) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style* style)
|
||||
: id(id), shape(shape->clone())
|
||||
{
|
||||
if (style) {
|
||||
style_ = *style;
|
||||
}
|
||||
}
|
||||
ConversionResult(int id, const ConversionResultShape* shape)
|
||||
: id(id), shape(shape->clone()) {}
|
||||
void append(const ifcopenshell::geometry::taxonomy::matrix4& trsf) {
|
||||
// @todo verify order
|
||||
placement.components() = placement.ccomponents() * trsf.ccomponents();
|
||||
}
|
||||
void prepend(const ifcopenshell::geometry::taxonomy::matrix4& trsf) {
|
||||
// @todo verify order
|
||||
placement.components() = trsf.ccomponents() * placement.ccomponents();
|
||||
}
|
||||
const ConversionResultShape* Shape() const { return shape; }
|
||||
ConversionResultShape* Shape() { return shape; }
|
||||
const ifcopenshell::geometry::taxonomy::matrix4& Placement() const { return placement; }
|
||||
bool hasStyle() const { return !!style_.diffuse; }
|
||||
const ifcopenshell::geometry::taxonomy::style& Style() const { return style_; }
|
||||
void setStyle(const ifcopenshell::geometry::taxonomy::style& newStyle) { style_ = newStyle; }
|
||||
int ItemId() const { return id; }
|
||||
};
|
||||
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
typedef std::vector<ConversionResult> ConversionResults;
|
||||
|
||||
|
||||
namespace util {
|
||||
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse, double tol);
|
||||
// @todo this is now moved to occt kernel, do we need something similar in cgal?
|
||||
// bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, double tol);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "ConversionSettings.h"
|
||||
|
||||
void ifcopenshell::geometry::ConversionSettings::setValue(GeomValue var, double value) {
|
||||
values_[var] = value;
|
||||
}
|
||||
|
||||
double ifcopenshell::geometry::ConversionSettings::getValue(GeomValue var) const {
|
||||
return values_[var];
|
||||
}
|
||||
@@ -1,150 +1,80 @@
|
||||
#ifndef ITERATOR_KERNEL_H
|
||||
#define ITERATOR_KERNEL_H
|
||||
#ifndef CONVERSIONSETTINGS_H
|
||||
#define CONVERSIONSETTINGS_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcRepresentationShapeItem.h"
|
||||
#include <array>
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/preprocessor/seq/pop_back.hpp>
|
||||
#include <boost/preprocessor/comparison/greater.hpp>
|
||||
#include <boost/preprocessor/selection/min.hpp>
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
|
||||
class IFC_GEOM_API ConversionSettings {
|
||||
public:
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
enum GeomValue {
|
||||
// Specifies the deflection of the mesher
|
||||
// Default: 0.001m / 1mm
|
||||
GV_DEFLECTION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Read-only
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the threshold distance under which cartesian points are deemed equal
|
||||
// Read-only
|
||||
GV_POINT_EQUALITY_TOLERANCE,
|
||||
// Specifies maximum number of faces for a shell to be reoriented.
|
||||
// Default: -1
|
||||
GV_MAX_FACES_TO_ORIENT,
|
||||
// The length unit used the creation of TopoDS_Shapes, primarily affects the
|
||||
// interpretation of IfcCartesianPoints and IfcVector magnitudes
|
||||
// DefaultL 1.0
|
||||
GV_LENGTH_UNIT,
|
||||
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
|
||||
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
|
||||
// Default: -1.0 (= not set, fist try degrees, then radians)
|
||||
GV_PLANEANGLE_UNIT,
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY,
|
||||
GV_LAYERSET_FIRST,
|
||||
GV_DISABLE_BOOLEAN_RESULT,
|
||||
GV_NO_WIRE_INTERSECTION_CHECK,
|
||||
GV_PRECISION_FACTOR,
|
||||
GV_NO_WIRE_INTERSECTION_TOLERANCE,
|
||||
GV_DEBUG_BOOLEAN,
|
||||
GV_BOOLEAN_ATTEMPT_2D,
|
||||
NUM_SETTINGS
|
||||
};
|
||||
|
||||
// @tfk A macro cannot define an include (I think), so here we can't
|
||||
// loop over the sequence of schema identifiers, but rather we have
|
||||
// unroll the loop with at least the amount of schemas we'd like support
|
||||
// for and then overflow into an existing empty include file.
|
||||
void setValue(GeomValue var, double value);
|
||||
|
||||
/*
|
||||
#define INCLUDE_SCHEMA(n) \
|
||||
BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(SCHEMA_SEQ), n), BOOST_PP_STRINGIZE(../ifcparse/BOOST_PP_CAT(Ifc,BOOST_PP_SEQ_ELEM(BOOST_PP_MIN(n, BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_POP_BACK(SCHEMA_SEQ))),SCHEMA_SEQ)).h), "empty.h")
|
||||
double getValue(GeomValue var) const;
|
||||
|
||||
#include INCLUDE_SCHEMA(0)
|
||||
#include INCLUDE_SCHEMA(1)
|
||||
#include INCLUDE_SCHEMA(2)
|
||||
#include INCLUDE_SCHEMA(3)
|
||||
#include INCLUDE_SCHEMA(4)
|
||||
#include INCLUDE_SCHEMA(5)
|
||||
#include INCLUDE_SCHEMA(6)
|
||||
#include INCLUDE_SCHEMA(7)
|
||||
#include INCLUDE_SCHEMA(8)
|
||||
#include INCLUDE_SCHEMA(9)
|
||||
*/
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
|
||||
static const double ALMOST_ZERO = 1.e-9;
|
||||
|
||||
template <typename T>
|
||||
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = ALMOST_ZERO) {
|
||||
return fabs(a - b) < tolerance;
|
||||
private:
|
||||
std::array<double, NUM_SETTINGS> values_ = {
|
||||
/* deflection_tolerance = */ 0.001,
|
||||
// @todo make sure these 'read-only' variables work.
|
||||
/* minimal_face_area = */ std::numeric_limits<double>::quiet_NaN(),
|
||||
/* max_faces_to_orient = */ -1.0,
|
||||
/* ifc_length_unit = */ 1.0,
|
||||
/* ifc_planeangle_unit = */ -1.0,
|
||||
/* modelling_precision = */ 0.00001,
|
||||
/* dimensionality = */ 1.,
|
||||
/* layerset_first = */ -1.,
|
||||
/* disable_boolean_result = */ -1.
|
||||
/* no_wire_intersection_check = */ -1.,
|
||||
/* precision_factor = */ 10.,
|
||||
/* no_wire_intersection_tolerance = */ -1.,
|
||||
/* boolean_debug_setting = */ -1.,
|
||||
/* boolean_attempt_2d = */ 1.
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// @todo find a place
|
||||
namespace IfcGeom {
|
||||
|
||||
class BRepElement;
|
||||
|
||||
class Kernel {
|
||||
private:
|
||||
Kernel* implementation_;
|
||||
|
||||
protected:
|
||||
Kernel() {};
|
||||
|
||||
public:
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
enum GeomValue {
|
||||
// Specifies the deflection of the mesher
|
||||
// Default: 0.001m / 1mm
|
||||
GV_DEFLECTION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Read-only
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the threshold distance under which cartesian points are deemed equal
|
||||
// Read-only
|
||||
GV_POINT_EQUALITY_TOLERANCE,
|
||||
// Specifies maximum number of faces for a shell to be reoriented.
|
||||
// Default: -1
|
||||
GV_MAX_FACES_TO_ORIENT,
|
||||
// The length unit used the creation of TopoDS_Shapes, primarily affects the
|
||||
// interpretation of IfcCartesianPoints and IfcVector magnitudes
|
||||
// DefaultL 1.0
|
||||
GV_LENGTH_UNIT,
|
||||
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
|
||||
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
|
||||
// Default: -1.0 (= not set, fist try degrees, then radians)
|
||||
GV_PLANEANGLE_UNIT,
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY,
|
||||
GV_LAYERSET_FIRST,
|
||||
GV_DISABLE_BOOLEAN_RESULT,
|
||||
GV_NO_WIRE_INTERSECTION_CHECK,
|
||||
GV_PRECISION_FACTOR,
|
||||
GV_NO_WIRE_INTERSECTION_TOLERANCE,
|
||||
GV_DEBUG_BOOLEAN,
|
||||
GV_BOOLEAN_ATTEMPT_2D
|
||||
};
|
||||
|
||||
IFC_PARSE_API Kernel(IfcParse::IfcFile* file_);
|
||||
|
||||
virtual ~Kernel() {}
|
||||
|
||||
virtual void setValue(GeomValue var, double value) {
|
||||
implementation_->setValue(var, value);
|
||||
}
|
||||
|
||||
virtual double getValue(GeomValue var) const {
|
||||
return implementation_->getValue(var);
|
||||
}
|
||||
|
||||
virtual BRepElement* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
return implementation_->convert(item);
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
return implementation_->convert_placement(item, trsf);
|
||||
}
|
||||
|
||||
|
||||
IFC_PARSE_API static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings = true);
|
||||
IFC_PARSE_API static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
|
||||
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
|
||||
|
||||
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
|
||||
public:
|
||||
KernelFactoryImplementation();
|
||||
void bind(const std::string& schema_name, kernel_fn);
|
||||
Kernel* construct(const std::string& schema_name, IfcParse::IfcFile*);
|
||||
};
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
}
|
||||
|
||||
class IFC_GEOM_API geometry_exception : public std::exception {
|
||||
protected:
|
||||
std::string message;
|
||||
@@ -163,5 +93,4 @@ namespace IfcGeom {
|
||||
: geometry_exception("Too many faces for operation") {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
#include "Converter.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file, IfcGeom::IteratorSettings& s)
|
||||
: geometry_library_(boost::to_lower_copy(geometry_library))
|
||||
, settings_(s)
|
||||
{
|
||||
mapping_ = impl::mapping_implementations().construct(file, settings_);
|
||||
kernel_ = kernels::construct(geometry_library, mapping_->conversion_settings());
|
||||
}
|
||||
|
||||
namespace {
|
||||
void substitute_with_box_based_on_density(IfcGeom::ConversionResults& items, double& density) {
|
||||
int nv = 0;
|
||||
void* box = nullptr;
|
||||
double volume = 0.;
|
||||
for (auto& i : items) {
|
||||
nv += i.Shape()->num_vertices();
|
||||
volume = i.Shape()->bounding_box(box);
|
||||
}
|
||||
density = nv / volume;
|
||||
if (density > 1e5) {
|
||||
items[0].Shape()->set_box(box);
|
||||
items.erase(items.begin() + 1, items.end());
|
||||
Logger::Notice("Substituted element with " + boost::lexical_cast<std::string>(density) + " vertices / m3 with a bounding box");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(taxonomy::item* representation_node, const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place_) {
|
||||
std::stringstream representation_id_builder;
|
||||
|
||||
auto place = place_;
|
||||
|
||||
representation_id_builder << representation_node->instance->data().id();
|
||||
|
||||
IfcGeom::Representation::BRep* shape;
|
||||
IfcGeom::ConversionResults shapes;
|
||||
|
||||
if (!kernel_->convert(representation_node, shapes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings_.get(IfcGeom::IteratorSettings::APPLY_LAYERSETS)) {
|
||||
TopoDS_Shape merge;
|
||||
|
||||
ifcopenshell::geometry::layerset_information layerinfo;
|
||||
std::vector<ifcopenshell::geometry::endpoint_connection> neighbours;
|
||||
std::map<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::layerset_information> neigbour_layers;
|
||||
int layerset_id, lid;
|
||||
|
||||
if (mapping_->get_layerset_information(product, layerinfo, layerset_id)) {
|
||||
representation_id_builder << "-layerset-" << layerset_id;
|
||||
if (mapping_->get_wall_neighbours(product, neighbours)) {
|
||||
for (auto& n : neighbours) {
|
||||
auto p = std::get<2>(n);
|
||||
mapping_->get_layerset_information(p, neigbour_layers[p], lid);
|
||||
}
|
||||
kernel_->apply_folded_layerset(shapes, layerinfo, neigbour_layers);
|
||||
} else {
|
||||
kernel_->apply_layerset(shapes, layerinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (util::flatten_shape_list(shapes, merge, false, getValue(GV_PRECISION))) {
|
||||
if (util::count(merge, TopAbs_FACE) > 0) {
|
||||
|
||||
if (convert_layerset(product, layers, styles, thickness)) {
|
||||
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (associates_material) {
|
||||
unsigned layerset_id = associates_material->RelatingMaterial()->data().id();
|
||||
representation_id_builder << "-layerset-" << layerset_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (styles.size() > 1) {
|
||||
// If there's only a single layer there is no need to manipulate geometries.
|
||||
bool success = true;
|
||||
if (product->as<IfcSchema::IfcWall>() && fold_layers(product->as<IfcSchema::IfcWall>(), shapes, layers, thickness, folded_layers)) {
|
||||
if (util::apply_folded_layerset(shapes, folded_layers, styles, shapes2, getValue(GV_PRECISION))) {
|
||||
std::swap(shapes, shapes2);
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
if (util::apply_layerset(shapes, layers, styles, shapes2, getValue(GV_PRECISION))) {
|
||||
std::swap(shapes, shapes2);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Error("Failed processing layerset");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool material_style_applied = false;
|
||||
|
||||
auto single_material = mapping_->get_single_material_association(product);
|
||||
if (single_material) {
|
||||
auto s = (taxonomy::style*) mapping_->map(single_material);
|
||||
for (auto it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
if (!it->hasStyle() && s) {
|
||||
it->setStyle(*s);
|
||||
material_style_applied = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool some_items_without_style = false;
|
||||
for (auto it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
// @todo implement num_faces()
|
||||
if (!it->hasStyle() /* && it->Shape()->num_faces() */) {
|
||||
some_items_without_style = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (some_items_without_style) {
|
||||
Logger::Warning("No material and surface styles for:", product);
|
||||
}
|
||||
}
|
||||
|
||||
if (material_style_applied) {
|
||||
representation_id_builder << "-material-" << single_material->data().id();
|
||||
}
|
||||
|
||||
if (settings_.force_space_transparency() >= 0. && product->declaration().is("IfcSpace")) {
|
||||
for (auto& s : shapes) {
|
||||
if (s.hasStyle()) {
|
||||
// @todo the uglyness
|
||||
const_cast<taxonomy::style*>(&s.Style())->transparency = settings_.force_space_transparency();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->get_value<std::string>("Name", "");
|
||||
const std::string guid = product->get_value<std::string>("GlobalId", "");
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
IfcGeom::ElementSettings element_settings(settings_, mapping_->get_length_unit(), product_type);
|
||||
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
auto openings = mapping_->find_openings(product);
|
||||
|
||||
if (!settings_.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
|
||||
representation_id_builder << "-openings";
|
||||
for (auto it = openings->begin(); it != openings->end(); ++it) {
|
||||
representation_id_builder << "-" << (*it)->data().id();
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResults opened_shapes;
|
||||
bool caught_error = false;
|
||||
try {
|
||||
std::vector<std::pair<taxonomy::item*, taxonomy::matrix4>> opening_items;
|
||||
|
||||
std::transform(openings->begin(), openings->end(), std::back_inserter(opening_items), [this](IfcUtil::IfcBaseClass* opening) {
|
||||
auto prod_item = mapping()->map(opening);
|
||||
return std::make_pair(mapping()->map(mapping()->representation_of(opening->as<IfcUtil::IfcBaseEntity>())), ((taxonomy::geom_item*)prod_item)->matrix);
|
||||
});
|
||||
|
||||
kernel_->convert_openings(product, opening_items, shapes, place, opened_shapes);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error processing openings for: ") + e.what() + ":", product);
|
||||
caught_error = true;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Error processing openings for:", product);
|
||||
}
|
||||
|
||||
if (caught_error && opened_shapes.size() < shapes.size()) {
|
||||
opened_shapes = shapes;
|
||||
}
|
||||
|
||||
if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (auto it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
|
||||
it->prepend(place);
|
||||
}
|
||||
place = ifcopenshell::geometry::taxonomy::matrix4();
|
||||
representation_id_builder << "-world-coords";
|
||||
}
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes);
|
||||
} else if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (auto it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
it->prepend(place);
|
||||
}
|
||||
place = ifcopenshell::geometry::taxonomy::matrix4();
|
||||
representation_id_builder << "-world-coords";
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
} else {
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
|
||||
/*
|
||||
// @todo
|
||||
if (representation->RepresentationIdentifier()) {
|
||||
context_string = *representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->ContextType()) {
|
||||
context_string = *representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
*/
|
||||
|
||||
auto elem = new IfcGeom::BRepElement(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
place,
|
||||
boost::shared_ptr<IfcGeom::Representation::BRep>(shape),
|
||||
product
|
||||
);
|
||||
|
||||
/*
|
||||
// @todo
|
||||
if (settings_.get(IteratorSettings::VALIDATE_QUANTITIES)) {
|
||||
auto rels = product->IsDefinedBy();
|
||||
for (auto& rel : *rels) {
|
||||
if (rel->as<IfcSchema::IfcRelDefinesByProperties>()) {
|
||||
auto pdef = rel->as<IfcSchema::IfcRelDefinesByProperties>()->RelatingPropertyDefinition();
|
||||
if (pdef->as<IfcSchema::IfcElementQuantity>()) {
|
||||
std::string organization_name;
|
||||
try {
|
||||
// A couple of files are not according to the schema here.
|
||||
organization_name = pdef->as<IfcSchema::IfcElementQuantity>()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name();
|
||||
} catch (...) {}
|
||||
if (organization_name == "IfcOpenShell") {
|
||||
auto qs = pdef->as<IfcSchema::IfcElementQuantity>()->Quantities();
|
||||
for (auto& q : *qs) {
|
||||
if (q->as<IfcSchema::IfcQuantityArea>() && q->Name() == "Total Surface Area") {
|
||||
double a_calc;
|
||||
double a_file = q->as<IfcSchema::IfcQuantityArea>()->AreaValue();
|
||||
if (elem->geometry().calculate_surface_area(a_calc)) {
|
||||
double diff = std::abs(a_calc - a_file);
|
||||
if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) {
|
||||
Logger::Error("Validation of surface area failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of surface area succeeded for:", product);
|
||||
}
|
||||
} else {
|
||||
Logger::Error("Validation of surface area failed for:", product);
|
||||
}
|
||||
} else if (q->as<IfcSchema::IfcQuantityVolume>() && q->Name() == "Volume") {
|
||||
double v_calc;
|
||||
double v_file = q->as<IfcSchema::IfcQuantityVolume>()->VolumeValue();
|
||||
if (elem->geometry().calculate_volume(v_calc)) {
|
||||
double diff = std::abs(v_calc - v_file);
|
||||
if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) {
|
||||
Logger::Error("Validation of volume failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of volume succeeded for:", product);
|
||||
}
|
||||
} else {
|
||||
Logger::Error("Validation of volume failed for:", product);
|
||||
}
|
||||
} else if (q->as<IfcSchema::IfcPhysicalComplexQuantity>() && q->Name() == "Shape Validation Properties") {
|
||||
auto qs2 = q->as<IfcSchema::IfcPhysicalComplexQuantity>()->HasQuantities();
|
||||
bool all_succeeded = qs2->size() > 0;
|
||||
for (auto& q2 : *qs2) {
|
||||
if (q2->as<IfcSchema::IfcQuantityCount>() && q2->Name() == "Surface Genus" && q2->Description()) {
|
||||
int item_id = boost::lexical_cast<int>((*q2->Description()).substr(1));
|
||||
int genus = (int)q2->as<IfcSchema::IfcQuantityCount>()->CountValue();
|
||||
for (auto& part : elem->geometry()) {
|
||||
if (part.ItemId() == item_id) {
|
||||
if (util::surface_genus(part.Shape()) != genus) {
|
||||
all_succeeded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!all_succeeded) {
|
||||
Logger::Error("Validation of surface genus failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of surface genus succeeded for:", product);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place, IfcGeom::BRepElement* brep) {
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string guid = product->get_value<std::string>("GlobalId");
|
||||
const std::string name = product->get_value<std::string>("Name", "");
|
||||
|
||||
/*
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
*/
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
|
||||
return new IfcGeom::BRepElement(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
// @todo
|
||||
"",
|
||||
place,
|
||||
brep->geometry_pointer(),
|
||||
product
|
||||
);
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product) {
|
||||
return create_brep_for_representation_and_product(
|
||||
mapping_->map(representation),
|
||||
product,
|
||||
((taxonomy::geom_item*)mapping_->map(product))->matrix
|
||||
);
|
||||
}
|
||||
|
||||
//#include "../../ifcparse/Ifc2x3.h"
|
||||
//#include "../../ifcparse/Ifc4.h"
|
||||
//
|
||||
//// @todo remove
|
||||
//#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
//
|
||||
//#include <TopExp.hxx>
|
||||
//#include <TopTools_ListOfShape.hxx>
|
||||
//#include <TopTools_IndexedMapOfShape.hxx>
|
||||
//#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
//
|
||||
//IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
// if (file != 0) {
|
||||
// if (file->schema() == 0) {
|
||||
// throw IfcParse::IfcException("No schema associated with file");
|
||||
// }
|
||||
//
|
||||
// const std::string& schema_name = file->schema()->name();
|
||||
// implementation_ = impl::kernel_implementations().construct(schema_name, geometry_library, file);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//int IfcGeom::Kernel::count(const ConversionResultShape* s_, int t_, bool unique) {
|
||||
// // @todo make kernel agnostic
|
||||
// const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
|
||||
// TopAbs_ShapeEnum t = (TopAbs_ShapeEnum) t_;
|
||||
//
|
||||
// if (unique) {
|
||||
// TopTools_IndexedMapOfShape map;
|
||||
// TopExp::MapShapes(s, t, map);
|
||||
// return map.Extent();
|
||||
// } else {
|
||||
// int i = 0;
|
||||
// TopExp_Explorer exp(s, t);
|
||||
// for (; exp.More(); exp.Next()) {
|
||||
// ++i;
|
||||
// }
|
||||
// return i;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//int IfcGeom::Kernel::surface_genus(const ConversionResultShape* s_) {
|
||||
// // @todo make kernel agnostic
|
||||
// const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
|
||||
// OpenCascadeShape Ss(s);
|
||||
//
|
||||
// int nv = count(&Ss, (int) TopAbs_VERTEX, true);
|
||||
// int ne = count(&Ss, (int) TopAbs_EDGE, true);
|
||||
// int nf = count(&Ss, (int) TopAbs_FACE, true);
|
||||
//
|
||||
// const int euler = nv - ne + nf;
|
||||
// const int genus = (2 - euler) / 2;
|
||||
//
|
||||
// return genus;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) {
|
||||
// if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
// return get_decomposing_entity_impl(inst->as<Ifc2x3::IfcProduct>(), include_openings);
|
||||
// } else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
// return get_decomposing_entity_impl(inst->as<Ifc4::IfcProduct>(), include_openings);
|
||||
// } else if (inst->declaration().name() == "IfcProject") {
|
||||
// return nullptr;
|
||||
// } else {
|
||||
// throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) {
|
||||
// // @todo make kernel agnostic
|
||||
// const TopoDS_Shape& a = ((OpenCascadeShape*) s_)->shape();
|
||||
//
|
||||
// if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) {
|
||||
// TopoDS_Iterator it(a);
|
||||
// for (; it.More(); it.Next()) {
|
||||
// OpenCascadeShape s(it.Value());
|
||||
// if (!is_manifold(&s)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// } else {
|
||||
// TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
// TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map);
|
||||
//
|
||||
// for (int i = 1; i <= map.Extent(); ++i) {
|
||||
// if (map.FindFromIndex(i).Extent() != 2) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef ITERATOR_KERNEL_H
|
||||
#define ITERATOR_KERNEL_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
#include "../ifcgeom/ConversionResult.h"
|
||||
#include "../ifcgeom/abstract_mapping.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
#include "../ifcgeom/AbstractKernel.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
class Converter {
|
||||
public:
|
||||
typedef boost::shared_ptr<IfcGeom::Representation::BRep> brep_ptr;
|
||||
private:
|
||||
std::string geometry_library_;
|
||||
abstract_mapping* mapping_;
|
||||
kernels::AbstractKernel* kernel_;
|
||||
IfcGeom::IteratorSettings settings_;
|
||||
std::map<ifcopenshell::geometry::taxonomy::item*, brep_ptr, ifcopenshell::geometry::taxonomy::less_functor> cache_;
|
||||
|
||||
public:
|
||||
kernels::AbstractKernel* kernel() { return kernel_; }
|
||||
|
||||
Converter(const std::string& geometry_library, IfcParse::IfcFile* file, IfcGeom::IteratorSettings& settings);
|
||||
|
||||
~Converter() {}
|
||||
|
||||
abstract_mapping* mapping() const { return mapping_; }
|
||||
|
||||
/*
|
||||
virtual NativeElement<double, double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
*/
|
||||
|
||||
double total_map_time = 0.;
|
||||
double total_geom_time = 0.;
|
||||
|
||||
IfcGeom::ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
std::clock_t map_start = std::clock();
|
||||
auto geom_item = mapping_->map(item);
|
||||
std::clock_t geom_start = std::clock();
|
||||
IfcGeom::ConversionResults results;
|
||||
kernel_->convert(geom_item, results);
|
||||
std::clock_t geom_end = std::clock();
|
||||
total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC;
|
||||
total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC;
|
||||
return results;
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product);
|
||||
// IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product, IfcGeom::BRepElement* brep);
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(taxonomy::item*, const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place);
|
||||
IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place, IfcGeom::BRepElement*);
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef GEOMETRYSERIALIZER_H
|
||||
#define GEOMETRYSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/Serializer.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomElement.h"
|
||||
#include "../ifcgeom/Serializer.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
class SerializerSettings : public IfcGeom::IteratorSettings
|
||||
{
|
||||
|
||||
@@ -27,56 +27,22 @@
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom_schema_agnostic/ifc_geom_api.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IteratorSettings.h"
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class Matrix {
|
||||
private:
|
||||
std::vector<double> _data;
|
||||
public:
|
||||
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
|
||||
// Convert the gp_Trsf into a 4x3 Matrix
|
||||
// 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 && settings.get(IteratorSettings::CONVERT_BACK_UNITS)
|
||||
? trsf_value / settings.unit_magnitude()
|
||||
: trsf_value;
|
||||
_data.push_back(static_cast<double>(matrix_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::vector<double>& data() const { return _data; }
|
||||
};
|
||||
|
||||
class Transformation {
|
||||
private:
|
||||
ElementSettings settings_;
|
||||
gp_Trsf trsf_;
|
||||
Matrix matrix_;
|
||||
ifcopenshell::geometry::taxonomy::matrix4 matrix_;
|
||||
public:
|
||||
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
|
||||
Transformation(const ElementSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& matrix)
|
||||
: settings_(settings)
|
||||
, trsf_(trsf)
|
||||
, matrix_(settings, trsf)
|
||||
, matrix_(matrix)
|
||||
{}
|
||||
const gp_Trsf& data() const { return trsf_; }
|
||||
const Matrix& matrix() const { return matrix_; }
|
||||
|
||||
Transformation inverted() const {
|
||||
return Transformation(settings_, trsf_.Inverted());
|
||||
}
|
||||
|
||||
Transformation multiplied(const Transformation& other) const {
|
||||
return Transformation(settings_, trsf_.Multiplied(other.data()));
|
||||
}
|
||||
const ifcopenshell::geometry::taxonomy::matrix4& data() const { return matrix_; }
|
||||
};
|
||||
|
||||
class Element {
|
||||
@@ -89,7 +55,7 @@ namespace IfcGeom {
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation _transformation;
|
||||
IfcUtil::IfcBaseEntity* product_;
|
||||
const IfcUtil::IfcBaseEntity* product_;
|
||||
std::vector<const IfcGeom::Element*> _parents;
|
||||
public:
|
||||
|
||||
@@ -123,12 +89,12 @@ namespace IfcGeom {
|
||||
const std::string& context() const { return _context; }
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation& transformation() const { return _transformation; }
|
||||
IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const std::vector<const IfcGeom::Element*> parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element*> newparents) { _parents = newparents; }
|
||||
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const gp_Trsf& trsf, IfcUtil::IfcBaseEntity* product)
|
||||
const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4& trsf, const IfcUtil::IfcBaseEntity* product)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
, product_(product)
|
||||
{
|
||||
@@ -164,17 +130,14 @@ namespace IfcGeom {
|
||||
const boost::shared_ptr<IfcGeom::Representation::BRep>& geometry_pointer() const { return _geometry; }
|
||||
const IfcGeom::Representation::BRep& geometry() const { return *_geometry; }
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<IfcGeom::Representation::BRep>& geometry,
|
||||
IfcUtil::IfcBaseEntity* product)
|
||||
const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4& trsf, const boost::shared_ptr<IfcGeom::Representation::BRep>& geometry,
|
||||
const IfcUtil::IfcBaseEntity* product)
|
||||
: Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
|
||||
bool calculate_projected_surface_area(double& along_x, double& along_y, double& along_z) const {
|
||||
const auto& trsf = this->transformation().data();
|
||||
const gp_Mat& mat = trsf.HVectorialPart();
|
||||
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
|
||||
return geometry().calculate_projected_surface_area(ax, along_x, along_y, along_z);
|
||||
return geometry().calculate_projected_surface_area(this->transformation().data(), along_x, along_y, along_z);
|
||||
}
|
||||
private:
|
||||
BRepElement(const BRepElement& other);
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
|
||||
#include "Kernel.h"
|
||||
#include "../ifcgeom/AbstractKernel.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/abstract_mapping.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function.hpp>
|
||||
@@ -70,7 +71,13 @@ namespace IfcGeom {
|
||||
bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const
|
||||
{
|
||||
IfcUtil::IfcBaseEntity* parent, *current = prod;
|
||||
while ((parent = IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings)) != nullptr) {
|
||||
// @todo examine if this can indeed be static. For now usage is only
|
||||
// in IfcConvert so invocation is bound to a single file with a single
|
||||
// schema.
|
||||
// @todo pass settings
|
||||
IfcGeom::IteratorSettings s;
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s);
|
||||
while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) {
|
||||
if (pred(parent)) {
|
||||
return true;
|
||||
}
|
||||
@@ -175,7 +182,10 @@ namespace IfcGeom {
|
||||
: wildcard_filter(include, traverse, patterns) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
layer_map_t layers = IfcGeom::Kernel::get_layers(prod);
|
||||
// @todo
|
||||
IfcGeom::IteratorSettings s;
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s);
|
||||
layer_map_t layers = mapping->get_layers(prod);
|
||||
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcGeom::Representation::Triangulation is a class that represents a *
|
||||
* triangulated IfcShapeRepresentation. *
|
||||
* Triangulation.verts is a 1 dimensional vector of float defining the *
|
||||
* cartesian coordinates of the vertices of the triangulated shape in the *
|
||||
* format of [x1,y1,z1,..,xn,yn,zn] *
|
||||
* Triangulation.faces is a 1 dimensional vector of int containing the *
|
||||
* indices of the triangles referencing positions in Triangulation.verts *
|
||||
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
|
||||
* the visibility of the edges that span the faces in Triangulation.faces *
|
||||
* *
|
||||
* IfcGeom::Element represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* returns a pointer to the current IfcGeom::Element *
|
||||
* *
|
||||
* IfcGeom::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* *
|
||||
* IfcGeom::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Iterator {
|
||||
private:
|
||||
Iterator(const Iterator&); // N/I
|
||||
Iterator& operator=(const Iterator&); // N/I
|
||||
|
||||
IfcParse::IfcFile* file_;
|
||||
IfcGeom::IteratorSettings settings_;
|
||||
std::vector<IfcGeom::filter_t> filters_;
|
||||
|
||||
IteratorImplementation* implementation_;
|
||||
|
||||
public:
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
{
|
||||
try {
|
||||
implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_, num_threads);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
implementation_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
, filters_(filters)
|
||||
{
|
||||
try {
|
||||
implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_, num_threads);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
implementation_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize() {
|
||||
if (implementation_) {
|
||||
return implementation_->initialize();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int progress() const { return implementation_->progress(); }
|
||||
|
||||
void compute_bounds(bool with_geometry) { implementation_->compute_bounds(with_geometry); }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return implementation_->bounds_min(); }
|
||||
const gp_XYZ& bounds_max() const { return implementation_->bounds_max(); }
|
||||
|
||||
const std::string& unit_name() const { return implementation_->getUnitName(); }
|
||||
|
||||
double unit_magnitude() const { return implementation_->getUnitMagnitude(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return implementation_->file(); }
|
||||
|
||||
IfcUtil::IfcBaseClass* next() const { return implementation_->next(); }
|
||||
|
||||
Element* get() { return implementation_->get(); }
|
||||
|
||||
BRepElement* get_native() { return implementation_->get_native(); }
|
||||
|
||||
const Element* get_object(int id) { return implementation_->get_object(id); }
|
||||
|
||||
IfcUtil::IfcBaseClass* create() { return implementation_->create(); }
|
||||
|
||||
void set_cache(GeometrySerializer* cache) { return implementation_->set_cache(cache); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcGeomIteratorSettings.h"
|
||||
#include "IteratorSettings.h"
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeomMaterial.h"
|
||||
|
||||
static double black[3] = {0.,0.,0.};
|
||||
static const std::string no_name = "";
|
||||
|
||||
IfcGeom::Material::Material() {}
|
||||
IfcGeom::Material::Material(const std::shared_ptr<const IfcGeom::SurfaceStyle>& style) : style(style) {}
|
||||
|
||||
bool IfcGeom::Material::hasDiffuse() const { return style && style->Diffuse() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecular() const { return style && style->Specular() ? true : false; }
|
||||
bool IfcGeom::Material::hasTransparency() const { return style && style->Transparency() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecularity() const { return style && style->Specularity() ? true : false; }
|
||||
const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
|
||||
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
|
||||
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
|
||||
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
|
||||
const std::string &IfcGeom::Material::name() const { return style ? style->Name() : no_name; }
|
||||
const std::string &IfcGeom::Material::original_name() const { return style ? style->original_name() : no_name; }
|
||||
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
|
||||
|
||||
const IfcGeom::SurfaceStyle& IfcGeom::Material::get_style() const {
|
||||
return *style;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMMATERIAL_H
|
||||
#define IFCGEOMMATERIAL_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Material {
|
||||
private:
|
||||
std::shared_ptr<const IfcGeom::SurfaceStyle> style;
|
||||
public:
|
||||
Material();
|
||||
explicit Material(const std::shared_ptr<const IfcGeom::SurfaceStyle>&);
|
||||
|
||||
bool hasDiffuse() const;
|
||||
bool hasSpecular() const;
|
||||
bool hasTransparency() const;
|
||||
bool hasSpecularity() const;
|
||||
const double* diffuse() const;
|
||||
const double* specular() const;
|
||||
double transparency() const;
|
||||
double specularity() const;
|
||||
const std::string &name() const;
|
||||
const std::string &original_name() const;
|
||||
bool operator==(const Material& other) const;
|
||||
|
||||
const IfcGeom::SurfaceStyle& get_style() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,8 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/ifc_geom_api.h"
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
@@ -30,79 +31,9 @@
|
||||
#include <memory>
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
double data[3];
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
}
|
||||
const double& R() const { return data[0]; }
|
||||
const double& G() const { return data[1]; }
|
||||
const double& B() const { return data[2]; }
|
||||
double& R() { return data[0]; }
|
||||
double& G() { return data[1]; }
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
std::string original_name_;
|
||||
boost::optional<int> id;
|
||||
boost::optional<ColorComponent> diffuse, specular;
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() : name("surface-style") {}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
std::string sanitized = name;
|
||||
boost::to_lower(sanitized);
|
||||
std::replace_if(sanitized.begin(), sanitized.end(), [](char c) {
|
||||
return c < 0x21 || c > 0x7e;
|
||||
}, '-');
|
||||
sstr << "surface-style-" << id << "-" << sanitized;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
|
||||
// Not used at this point. In fact, equality testing in the current
|
||||
// architecture can just as easily be accomplished by comparing the
|
||||
// pointer addresses of the styles, as they are always referenced
|
||||
// from out of a global map of some sort.
|
||||
bool operator==(const SurfaceStyle& other) {
|
||||
return name == other.name;
|
||||
}
|
||||
|
||||
/// ID name, e.g. "surface-style-66675-metal---aluminium"
|
||||
const std::string& Name() const { return name; }
|
||||
IFC_GEOM_API const ifcopenshell::geometry::taxonomy::style& get_default_style(const std::string& ifc_type);
|
||||
|
||||
/// Original name, if available, e.g. "Metal - Aluminium"
|
||||
const std::string& original_name() const { return original_name_; }
|
||||
|
||||
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
|
||||
const boost::optional<ColorComponent>& Specular() const { return specular; }
|
||||
const boost::optional<double>& Transparency() const { return transparency; }
|
||||
const boost::optional<double>& Specularity() const { return specularity; }
|
||||
const boost::optional<int>& Id() const { return id; }
|
||||
|
||||
boost::optional<ColorComponent>& Diffuse() { return diffuse; }
|
||||
boost::optional<ColorComponent>& Specular() { return specular; }
|
||||
boost::optional<double>& Transparency() { return transparency; }
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
boost::optional<int>& Id() { return id; }
|
||||
};
|
||||
|
||||
IFC_GEOM_API std::shared_ptr<const IfcGeom::SurfaceStyle> get_default_style(const std::string& ifc_type);
|
||||
|
||||
IFC_GEOM_API SurfaceStyle& update_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API ifcopenshell::geometry::taxonomy::style& update_default_style(const std::string& ifc_type);
|
||||
|
||||
IFC_GEOM_API void set_default_style_file(const std::string& json_file);
|
||||
}
|
||||
|
||||
@@ -26,40 +26,45 @@
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
|
||||
#include "../ifcgeom/kernels/opencascade/base_utils.h"
|
||||
|
||||
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
: Representation(brep.settings())
|
||||
, id_(brep.id())
|
||||
{
|
||||
TopoDS_Compound compound = brep.as_compound();
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
int sid = -1;
|
||||
|
||||
if (it->hasStyle() && it->Style().Diffuse()) {
|
||||
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
|
||||
surface_styles_.push_back(clr.R());
|
||||
surface_styles_.push_back(clr.G());
|
||||
surface_styles_.push_back(clr.B());
|
||||
ConversionResultShape* shape = brep.as_compound();
|
||||
TopoDS_Compound compound = TopoDS::Compound(((ifcopenshell::geometry::OpenCascadeShape*)shape)->shape());
|
||||
delete shape;
|
||||
|
||||
sid = it->Style().Id().get_value_or(-1);
|
||||
for (auto it = brep.begin(); it != brep.end(); ++it) {
|
||||
int sid = -1;
|
||||
|
||||
if (it->hasStyle()) {
|
||||
const auto& clr = it->Style().diffuse.ccomponents();
|
||||
surface_styles_.push_back(clr(0));
|
||||
surface_styles_.push_back(clr(1));
|
||||
surface_styles_.push_back(clr(2));
|
||||
|
||||
sid = it->Style().instance ? it->Style().instance->data().id() : -1;
|
||||
} else {
|
||||
surface_styles_.push_back(-1.);
|
||||
surface_styles_.push_back(-1.);
|
||||
surface_styles_.push_back(-1.);
|
||||
}
|
||||
|
||||
if (it->hasStyle() && it->Style().Transparency()) {
|
||||
surface_styles_.push_back(1. - *it->Style().Transparency());
|
||||
if (it->hasStyle() && it->Style().has_transparency()) {
|
||||
surface_styles_.push_back(1. - it->Style().transparency);
|
||||
} else {
|
||||
surface_styles_.push_back(1.);
|
||||
}
|
||||
|
||||
surface_style_ids_.push_back(sid);
|
||||
}
|
||||
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
brep_data_ = sstream.str();
|
||||
@@ -90,13 +95,26 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
|
||||
IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
|
||||
for (auto it = begin(); it != end(); ++it) {
|
||||
const TopoDS_Shape& s = *(ifcopenshell::geometry::OpenCascadeShape*)it->Shape();
|
||||
|
||||
// @todo, check
|
||||
gp_GTrsf trsf;
|
||||
if (it->Placement().components_) {
|
||||
gp_Trsf tr;
|
||||
const auto& m = it->Placement().ccomponents();
|
||||
tr.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
trsf = tr;
|
||||
}
|
||||
|
||||
if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
@@ -107,9 +125,11 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) co
|
||||
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
return compound;
|
||||
|
||||
return new ifcopenshell::geometry::OpenCascadeShape(compound);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
void accumulate(const gp_Ax3& ax, const gp_Dir& normal, double area, double& along_x, double& along_y, double& along_z) {
|
||||
along_x += area * fabs(ax.XDirection().Dot(normal));
|
||||
@@ -173,7 +193,7 @@ namespace {
|
||||
const gp_Vec v2 = pt3 - pt2;
|
||||
const gp_Vec v3 = pt1 - pt3;
|
||||
const gp_Vec normal_vector = v1 ^ v2;
|
||||
if (normal_vector.Magnitude() > ALMOST_ZERO) {
|
||||
if (normal_vector.Magnitude() > 1.e-7) {
|
||||
gp_Dir normal = gp_Dir();
|
||||
|
||||
double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() };
|
||||
@@ -197,9 +217,9 @@ bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const {
|
||||
try {
|
||||
area = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(it->Shape(), prop);
|
||||
BRepGProp::SurfaceProperties(*(ifcopenshell::geometry::OpenCascadeShape*)it->Shape(), prop);
|
||||
area += prop.Mass();
|
||||
}
|
||||
|
||||
@@ -214,10 +234,10 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
|
||||
try {
|
||||
volume = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
if (util::is_manifold(it->Shape())) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
if (util::is_manifold(*(ifcopenshell::geometry::OpenCascadeShape*)it->Shape())) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::VolumeProperties(it->Shape(), prop);
|
||||
BRepGProp::VolumeProperties(*(ifcopenshell::geometry::OpenCascadeShape*)it->Shape(), prop);
|
||||
volume += prop.Mass();
|
||||
} else {
|
||||
return false;
|
||||
@@ -231,15 +251,31 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const gp_Ax3 & ax, double & along_x, double & along_y, double & along_z) const {
|
||||
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& place, double & along_x, double & along_y, double & along_z) const {
|
||||
try {
|
||||
gp_GTrsf trsf;
|
||||
|
||||
if (place.components_) {
|
||||
gp_Trsf tr;
|
||||
const auto& m = place.ccomponents();
|
||||
tr.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
trsf = tr;
|
||||
}
|
||||
|
||||
gp_Mat mat = trsf.Trsf().HVectorialPart();
|
||||
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
|
||||
|
||||
along_x = along_y = along_z = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
double x, y, z;
|
||||
surface_area_along_direction(settings().deflection_tolerance(), it->Shape(), ax, x, y, z);
|
||||
surface_area_along_direction(settings().deflection_tolerance(), *(ifcopenshell::geometry::OpenCascadeShape*)it->Shape(), ax, x, y, z);
|
||||
|
||||
if (util::is_manifold(it->Shape())) {
|
||||
if (util::is_manifold(*(ifcopenshell::geometry::OpenCascadeShape*)it->Shape())) {
|
||||
x /= 2.;
|
||||
y /= 2.;
|
||||
z /= 2.;
|
||||
@@ -262,27 +298,25 @@ IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model)
|
||||
, id_(shape_model.id())
|
||||
, weld_offset_(0)
|
||||
{
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++iit) {
|
||||
|
||||
for (IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++iit) {
|
||||
|
||||
// Don't weld vertices that belong to different items to prevent non-manifold situations.
|
||||
weld_offset_ += welds.size();
|
||||
welds.clear();
|
||||
resetWelds();
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(iit->StylePtr());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
auto jt = std::find(_materials.begin(), _materials.end(), iit->Style());
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
_materials.push_back(iit->Style());
|
||||
} else {
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
const auto& material = IfcGeom::get_default_style(settings().element_type());
|
||||
auto mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
@@ -291,186 +325,7 @@ IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model)
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = iit->Shape();
|
||||
const gp_GTrsf& trsf = iit->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance(), false, settings().angular_tolerance());
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for (exp.Init(s, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (tri.IsNull()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation missing for face");
|
||||
} else {
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int, int>, int> edgecount;
|
||||
std::vector<std::pair<int, int> > edges_temp;
|
||||
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int, int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings().get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for (int i = 1; i <= tri->NbNodes(); ++i) {
|
||||
coords.push_back(tri->Node(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
dict[i] = addVertex(surface_style_id, *coords.rbegin());
|
||||
|
||||
if (calculate_normals) {
|
||||
const gp_Pnt2d& uv = tri->UVNode(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(), uv.Y(), p, normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > 1.e-9) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
|
||||
const bool is_top = uv.Y() > 0;
|
||||
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
|
||||
const double z = (is_top == is_forward) ? 1. : -1.;
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
|
||||
}
|
||||
}
|
||||
// TODO: Do the same for conical surfaces, but they are rare in IFC.
|
||||
}
|
||||
_normals.push_back(normal.X());
|
||||
_normals.push_back(normal.Y());
|
||||
_normals.push_back(normal.Z());
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
triangles(i).Get(n3, n2, n1);
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
_faces.push_back(dict[n1]);
|
||||
_faces.push_back(dict[n2]);
|
||||
_faces.push_back(dict[n3]);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for (std::vector<std::pair<int, int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
_edges.push_back(jt->first);
|
||||
_edges.push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
uvs_ = box_project_uvs(_verts, _normals);
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int previous = -1;
|
||||
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
int current = addVertex(surface_style_id, p);
|
||||
|
||||
std::vector<std::pair<int, int>> segments;
|
||||
if (i > 1) {
|
||||
segments.push_back(std::make_pair(previous, current));
|
||||
}
|
||||
|
||||
if (settings().get(IfcGeom::IteratorSettings::EDGE_ARROWS)) {
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
trsf.Transforms(p2);
|
||||
trsf.Transforms(p3);
|
||||
trsf.Transforms(p);
|
||||
|
||||
int left = addVertex(surface_style_id, p2);
|
||||
int right = addVertex(surface_style_id, p3);
|
||||
|
||||
segments.push_back(std::make_pair(left, current));
|
||||
segments.push_back(std::make_pair(right, current));
|
||||
}
|
||||
|
||||
for (auto& sgmt : segments) {
|
||||
_edges.push_back(sgmt.first);
|
||||
_edges.push_back(sgmt.second);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
}
|
||||
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(s);
|
||||
iit->Shape()->Triangulate(settings(), iit->Placement(), this, surface_style_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,11 +360,11 @@ std::vector<double> IfcGeom::Representation::Triangulation::box_project_uvs(cons
|
||||
return uvs;
|
||||
}
|
||||
|
||||
int IfcGeom::Representation::Triangulation::addVertex(int material_index, const gp_XYZ & p) {
|
||||
int IfcGeom::Representation::Triangulation::addVertex(int material_index, double pX, double pY, double pZ) {
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
const double X = convert ? (p.X() / settings().unit_magnitude()) : p.X();
|
||||
const double Y = convert ? (p.Y() / settings().unit_magnitude()) : p.Y();
|
||||
const double Z = convert ? (p.Z() / settings().unit_magnitude()) : p.Z();
|
||||
const double X = convert ? (pX / settings().unit_magnitude()) : pX;
|
||||
const double Y = convert ? (pY / settings().unit_magnitude()) : pY;
|
||||
const double Z = convert ? (pZ / settings().unit_magnitude()) : pZ;
|
||||
int i = (int)_verts.size() / 3;
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
|
||||
@@ -20,26 +20,8 @@
|
||||
#ifndef IFCGEOMREPRESENTATION_H
|
||||
#define IFCGEOMREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include "../ifcgeom/IteratorSettings.h"
|
||||
#include "../ifcgeom/ConversionResult.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -63,25 +45,25 @@ namespace IfcGeom {
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes_;
|
||||
const IfcGeom::ConversionResults shapes_;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes)
|
||||
: Representation(settings)
|
||||
, id_(id)
|
||||
, shapes_(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes_.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes_.end(); }
|
||||
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
|
||||
IfcGeom::ConversionResults::const_iterator begin() const { return shapes_.begin(); }
|
||||
IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); }
|
||||
const IfcGeom::ConversionResults& shapes() const { return shapes_; }
|
||||
const std::string& id() const { return id_; }
|
||||
TopoDS_Compound as_compound(bool force_meters = false) const;
|
||||
IfcGeom::ConversionResultShape* as_compound(bool force_meters = false) const;
|
||||
|
||||
bool calculate_volume(double&) const;
|
||||
bool calculate_surface_area(double&) const;
|
||||
bool calculate_projected_surface_area(const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) const;
|
||||
bool calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& ax, double& along_x, double& along_y, double& along_z) const;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
@@ -117,29 +99,25 @@ namespace IfcGeom {
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<double> _normals;
|
||||
std::vector<double> uvs_;
|
||||
std::vector<double> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style> _materials;
|
||||
size_t weld_offset_;
|
||||
VertexKeyMap welds;
|
||||
|
||||
// when read from serialization, the element needs to take ownership of the styles,
|
||||
// the material vector is constructor off of this.
|
||||
// @todo this can be improved
|
||||
std::vector<std::shared_ptr<IfcGeom::SurfaceStyle>> styles_;
|
||||
|
||||
public:
|
||||
const std::string& id() const { return id_; }
|
||||
const std::vector<double>& verts() const { return _verts; }
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
const std::vector<double>& normals() const { return _normals; }
|
||||
const std::vector<double>& uvs() const { return uvs_; }
|
||||
std::vector<double>& uvs() { return uvs_; }
|
||||
const std::vector<double>& uvs() const { return uvs_; }
|
||||
const std::vector<int>& material_ids() const { return _material_ids; }
|
||||
const std::vector<Material>& materials() const { return _materials; }
|
||||
const std::vector<ifcopenshell::geometry::taxonomy::style>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model);
|
||||
|
||||
|
||||
Triangulation(
|
||||
ElementSettings settings,
|
||||
const std::string& id,
|
||||
@@ -149,7 +127,8 @@ namespace IfcGeom {
|
||||
const std::vector<double>& normals,
|
||||
const std::vector<double>& uvs,
|
||||
const std::vector<int>& material_ids,
|
||||
const std::vector<std::shared_ptr<IfcGeom::SurfaceStyle>>& styles)
|
||||
const std::vector<ifcopenshell::geometry::taxonomy::style>& materials
|
||||
)
|
||||
: Representation(settings)
|
||||
, id_(id)
|
||||
, _verts(verts)
|
||||
@@ -158,12 +137,8 @@ namespace IfcGeom {
|
||||
, _normals(normals)
|
||||
, uvs_(uvs)
|
||||
, _material_ids(material_ids)
|
||||
, styles_(styles)
|
||||
{
|
||||
for (auto& s : styles_) {
|
||||
_materials.push_back(IfcGeom::Material(s));
|
||||
}
|
||||
}
|
||||
, _materials(materials)
|
||||
{}
|
||||
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
@@ -171,11 +146,45 @@ namespace IfcGeom {
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<double> box_project_uvs(const std::vector<double> &vertices, const std::vector<double> &normals);
|
||||
|
||||
private:
|
||||
/// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, const gp_XYZ& p);
|
||||
int addVertex(int material_index, double X, double Y, double Z);
|
||||
|
||||
void addNormal(double X, double Y, double Z) {
|
||||
_normals.push_back(X);
|
||||
_normals.push_back(Y);
|
||||
_normals.push_back(Z);
|
||||
}
|
||||
|
||||
void addFace(int style, int i0, int i1, int i2) {
|
||||
_faces.push_back(i0);
|
||||
_faces.push_back(i1);
|
||||
_faces.push_back(i2);
|
||||
|
||||
_material_ids.push_back(style);
|
||||
}
|
||||
|
||||
void addEdge(int style, int i0, int i1) {
|
||||
_edges.push_back(i0);
|
||||
_edges.push_back(i1);
|
||||
|
||||
_material_ids.push_back(style);
|
||||
}
|
||||
|
||||
void registerEdge(int i0, int i1) {
|
||||
_edges.push_back(i0);
|
||||
_edges.push_back(i1);
|
||||
}
|
||||
|
||||
void addEdge(int n1, int n2, std::map<std::pair<int, int>, int>& edgecount, std::vector<std::pair<int, int> >& edges_temp);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void resetWelds() {
|
||||
weld_offset_ += welds.size();
|
||||
welds.clear();
|
||||
}
|
||||
|
||||
Triangulation();
|
||||
Triangulation(const Triangulation&);
|
||||
Triangulation& operator=(const Triangulation&);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "IfcGeomIteratorImplementation.h"
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
#define MAKE_INIT_FN__(a, b) init_ ## a ## b
|
||||
#define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b)
|
||||
#define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema)
|
||||
|
||||
namespace {
|
||||
struct MAKE_TYPE_NAME(factory_t) {
|
||||
IfcGeom::IteratorImplementation* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
|
||||
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(settings, file, filters, num_threads);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation* mapping) {
|
||||
static const std::string schema_name = STRINGIFY(IfcSchema);
|
||||
MAKE_TYPE_NAME(factory_t) factory;
|
||||
mapping->bind(schema_name, factory);
|
||||
}
|
||||
+201
-672
File diff suppressed because it is too large
Load Diff
@@ -132,7 +132,7 @@ namespace IfcGeom
|
||||
double deflection_tolerance() const { return deflection_tolerance_; }
|
||||
double angular_tolerance() const { return angular_tolerance_; }
|
||||
double force_space_transparency() const { return force_space_transparency_; }
|
||||
std::set<int> context_ids() const { return context_ids_; }
|
||||
const std::set<int>& context_ids() const { return context_ids_; }
|
||||
|
||||
/// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
|
||||
/// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
|
||||
@@ -17,10 +17,8 @@
|
||||
return BOOST_PP_CAT(METHOD_NAME, elem)(shape, arg_2); \
|
||||
}
|
||||
|
||||
namespace IfcGeom {
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_1, , SCHEMA_SEQ);
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_2, , SCHEMA_SEQ);
|
||||
}
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_1, , SCHEMA_SEQ);
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_2, , SCHEMA_SEQ);
|
||||
|
||||
#define METHOD_NAME tesselate_Ifc
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/ifc_geom_api.h"
|
||||
#include "../../ifcgeom/ifc_geom_api.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
|
||||
@@ -15,8 +15,20 @@
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_BezierCurve.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "../../../ifcparse/macros.h"
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/x.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
#undef INCLUDE_PARENT_PARENT_DIR
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
|
||||
@@ -565,7 +577,7 @@ int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
|
||||
return faces->size();
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced) {
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise)(const TopoDS_Shape& shape, bool advanced) {
|
||||
|
||||
#ifndef SCHEMA_HAS_IfcAdvancedBrep
|
||||
advanced = false;
|
||||
@@ -677,7 +689,7 @@ IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& s
|
||||
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection) {
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate)(const TopoDS_Shape& shape, double deflection) {
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
@@ -8,55 +8,55 @@
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
static std::map<std::string, std::shared_ptr<IfcGeom::SurfaceStyle>> default_materials;
|
||||
static std::shared_ptr<IfcGeom::SurfaceStyle> default_material;
|
||||
static std::map<std::string, ifcopenshell::geometry::taxonomy::style> default_materials;
|
||||
static ifcopenshell::geometry::taxonomy::style default_material;
|
||||
static bool default_materials_initialized = false;
|
||||
|
||||
void InitDefaultMaterials() {
|
||||
default_materials.insert(std::make_pair("IfcSite", std::make_shared<IfcGeom::SurfaceStyle>("IfcSite")));
|
||||
default_materials["IfcSite"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
|
||||
default_materials.insert(std::make_pair("IfcSite", ifcopenshell::geometry::taxonomy::style("IfcSite")));
|
||||
default_materials["IfcSite"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.65);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSlab", std::make_shared<IfcGeom::SurfaceStyle>("IfcSlab")));
|
||||
default_materials["IfcSlab"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4, 0.4, 0.4));
|
||||
default_materials.insert(std::make_pair("IfcSlab", ifcopenshell::geometry::taxonomy::style("IfcSlab")));
|
||||
default_materials["IfcSlab"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.4, 0.4, 0.4);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", std::make_shared<IfcGeom::SurfaceStyle>("IfcWallStandardCase")));
|
||||
default_materials["IfcWallStandardCase"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", ifcopenshell::geometry::taxonomy::style("IfcWallStandardCase")));
|
||||
default_materials["IfcWallStandardCase"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWall", std::make_shared<IfcGeom::SurfaceStyle>("IfcWall")));
|
||||
default_materials["IfcWall"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
|
||||
default_materials.insert(std::make_pair("IfcWall", ifcopenshell::geometry::taxonomy::style("IfcWall")));
|
||||
default_materials["IfcWall"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWindow", std::make_shared<IfcGeom::SurfaceStyle>("IfcWindow")));
|
||||
default_materials["IfcWindow"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
|
||||
default_materials["IfcWindow"]->Transparency().reset(0.3);
|
||||
default_materials.insert(std::make_pair("IfcWindow", ifcopenshell::geometry::taxonomy::style("IfcWindow")));
|
||||
default_materials["IfcWindow"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.75);
|
||||
default_materials["IfcWindow"].transparency = 0.3;
|
||||
|
||||
default_materials.insert(std::make_pair("IfcDoor", std::make_shared<IfcGeom::SurfaceStyle>("IfcDoor")));
|
||||
default_materials["IfcDoor"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
|
||||
default_materials.insert(std::make_pair("IfcDoor", ifcopenshell::geometry::taxonomy::style("IfcDoor")));
|
||||
default_materials["IfcDoor"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.55, 0.3, 0.15);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcBeam", std::make_shared<IfcGeom::SurfaceStyle>("IfcBeam")));
|
||||
default_materials["IfcBeam"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7));
|
||||
default_materials.insert(std::make_pair("IfcBeam", ifcopenshell::geometry::taxonomy::style("IfcBeam")));
|
||||
default_materials["IfcBeam"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.75, 0.7, 0.7);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcRailing", std::make_shared<IfcGeom::SurfaceStyle>("IfcRailing")));
|
||||
default_materials["IfcRailing"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
|
||||
default_materials.insert(std::make_pair("IfcRailing", ifcopenshell::geometry::taxonomy::style("IfcRailing")));
|
||||
default_materials["IfcRailing"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcMember", std::make_shared<IfcGeom::SurfaceStyle>("IfcMember")));
|
||||
default_materials["IfcMember"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
|
||||
default_materials.insert(std::make_pair("IfcMember", ifcopenshell::geometry::taxonomy::style("IfcMember")));
|
||||
default_materials["IfcMember"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcPlate", std::make_shared<IfcGeom::SurfaceStyle>("IfcPlate")));
|
||||
default_materials["IfcPlate"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8, 0.8, 0.8));
|
||||
default_materials.insert(std::make_pair("IfcPlate", ifcopenshell::geometry::taxonomy::style("IfcPlate")));
|
||||
default_materials["IfcPlate"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.8, 0.8, 0.8);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSpace", std::make_shared<IfcGeom::SurfaceStyle>("IfcSpace")));
|
||||
default_materials["IfcWindow"]->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.75, 0.8));
|
||||
default_materials["IfcWindow"]->Transparency().reset(0.8);
|
||||
default_materials.insert(std::make_pair("IfcSpace", ifcopenshell::geometry::taxonomy::style("IfcSpace")));
|
||||
default_materials["IfcWindow"].diffuse = ifcopenshell::geometry::taxonomy::colour(0.65, 0.75, 0.8);
|
||||
default_materials["IfcWindow"].transparency = 0.8;
|
||||
|
||||
default_material = std::make_shared<IfcGeom::SurfaceStyle>("DefaultMaterial");
|
||||
default_material->Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
|
||||
default_material = ifcopenshell::geometry::taxonomy::style("DefaultMaterial");
|
||||
default_material.diffuse = ifcopenshell::geometry::taxonomy::colour(0.7, 0.7, 0.7);
|
||||
|
||||
default_materials_initialized = true;
|
||||
}
|
||||
|
||||
boost::optional<IfcGeom::SurfaceStyle::ColorComponent> read_colour_component(const boost::optional<pt::ptree&> list) {
|
||||
ifcopenshell::geometry::taxonomy::colour read_colour_component(const boost::optional<pt::ptree&> list) {
|
||||
if (!list) {
|
||||
return boost::none;
|
||||
return ifcopenshell::geometry::taxonomy::colour();
|
||||
}
|
||||
double rgb[3];
|
||||
int i = 0;
|
||||
@@ -70,7 +70,7 @@ boost::optional<IfcGeom::SurfaceStyle::ColorComponent> read_colour_component(con
|
||||
if (i != 3) {
|
||||
throw std::runtime_error("rgb array less than 3 elements large (was " + std::to_string(i) + ")");
|
||||
}
|
||||
return IfcGeom::SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]);
|
||||
return ifcopenshell::geometry::taxonomy::colour(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
@@ -83,20 +83,20 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
|
||||
for (pt::ptree::value_type &material_pair : root) {
|
||||
std::string name = material_pair.first;
|
||||
default_materials.insert(std::make_pair(name, std::make_shared<IfcGeom::SurfaceStyle>(name)));
|
||||
default_materials.insert(std::make_pair(name, ifcopenshell::geometry::taxonomy::style(name)));
|
||||
|
||||
pt::ptree material = material_pair.second;
|
||||
boost::optional<pt::ptree&> diffuse = material.get_child_optional("diffuse");
|
||||
default_materials[name]->Diffuse() = read_colour_component(diffuse);
|
||||
default_materials[name].diffuse = read_colour_component(diffuse);
|
||||
|
||||
boost::optional<pt::ptree&> specular = material.get_child_optional("specular");
|
||||
default_materials[name]->Specular() = read_colour_component(specular);
|
||||
default_materials[name].specular = read_colour_component(specular);
|
||||
|
||||
if (material.get_child_optional("specular-roughness")) {
|
||||
default_materials[name]->Specularity().reset(1.0 / material.get<double>("specular-roughness"));
|
||||
default_materials[name].specularity = 1.0 / material.get<double>("specular-roughness");
|
||||
}
|
||||
if (material.get_child_optional("transparency")) {
|
||||
default_materials[name]->Transparency() = material.get<double>("transparency");
|
||||
default_materials[name].transparency = material.get<double>("transparency");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const IfcGeom::SurfaceStyle> IfcGeom::get_default_style(const std::string& s) {
|
||||
const ifcopenshell::geometry::taxonomy::style& IfcGeom::get_default_style(const std::string& s) {
|
||||
static std::mutex m;
|
||||
std::lock_guard<std::mutex> lk(m);
|
||||
|
||||
@@ -121,11 +121,11 @@ std::shared_ptr<const IfcGeom::SurfaceStyle> IfcGeom::get_default_style(const st
|
||||
return it->second;
|
||||
}
|
||||
|
||||
IfcGeom::SurfaceStyle& IfcGeom::update_default_style(const std::string& s) {
|
||||
ifcopenshell::geometry::taxonomy::style& IfcGeom::update_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
auto it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
throw std::runtime_error("No style registered for " + s);
|
||||
}
|
||||
return *it->second;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -2,21 +2,30 @@
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
|
||||
ifcopenshell::geometry::impl::MappingFactoryImplementation& ifcopenshell::geometry::impl::mapping_implementations() {
|
||||
static MappingFactoryImplementation impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
extern void init_MappingImplementation_Ifc2x3(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
extern void init_MappingImplementation_Ifc4(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
extern void init_MappingImplementation_Ifc4x1(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
extern void init_MappingImplementation_Ifc4x2(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
// Declares the schema-based external kernel initialization routines:
|
||||
// - extern void init_MappingImplementation_Ifc2x3(IfcGeom::impl::MappingFactoryImplementation*);
|
||||
// - ...
|
||||
#define EXTERNAL_DEFS(r, data, elem) \
|
||||
extern void BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
|
||||
// Declares the schema-based external iterator initialization routines:
|
||||
// - init_MappingImplementation_Ifc2x3(this);
|
||||
// - ...
|
||||
#define CALL_DEFS(r, data, elem) \
|
||||
BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(this);
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
|
||||
|
||||
ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() {
|
||||
init_MappingImplementation_Ifc2x3(this);
|
||||
init_MappingImplementation_Ifc4(this);
|
||||
init_MappingImplementation_Ifc4x1(this);
|
||||
init_MappingImplementation_Ifc4x2(this);
|
||||
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
|
||||
@@ -24,12 +33,14 @@ void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std:
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, settings& s) {
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, IfcGeom::IteratorSettings& s) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
|
||||
std::map<std::string, ifcopenshell::geometry::impl::mapping_fn>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == end()) {
|
||||
throw IfcParse::IfcException("No geometry mapping registered for " + schema_name_lower);
|
||||
}
|
||||
return it->second(file, s);
|
||||
auto new_mapping = it->second(file, s);
|
||||
new_mapping->initialize_settings();
|
||||
return new_mapping;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
#define ABSTRACT_MAPPING_H
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcEntityList.h"
|
||||
#include "../ifcparse/aggregate_of_instance.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
#include "../ifcgeom/settings.h"
|
||||
#include "../ifcgeom/IteratorSettings.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
@@ -18,31 +20,42 @@ namespace geometry {
|
||||
struct geometry_conversion_task {
|
||||
int index;
|
||||
IfcUtil::IfcBaseEntity* representation;
|
||||
IfcEntityList::ptr products;
|
||||
aggregate_of_instance::ptr products;
|
||||
};
|
||||
|
||||
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
|
||||
|
||||
class abstract_mapping {
|
||||
protected:
|
||||
settings settings_;
|
||||
IfcGeom::IteratorSettings settings_;
|
||||
ConversionSettings conv_settings_;
|
||||
public:
|
||||
abstract_mapping(settings& s) : settings_(s) {}
|
||||
abstract_mapping(IfcGeom::IteratorSettings& s) : settings_(s) {}
|
||||
|
||||
virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0;
|
||||
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters, settings& s) = 0;
|
||||
virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0;
|
||||
virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseInterface*) = 0;
|
||||
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters) = 0;
|
||||
virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(const IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0;
|
||||
virtual std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual aggregate_of_instance::ptr find_openings(const IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual void initialize_settings() = 0;
|
||||
virtual bool get_layerset_information(const IfcUtil::IfcBaseInterface*, layerset_information&, int&) = 0;
|
||||
virtual bool get_wall_neighbours(const IfcUtil::IfcBaseInterface*, std::vector<endpoint_connection>&) = 0;
|
||||
virtual const IfcUtil::IfcBaseEntity* get_single_material_association(const IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual double get_length_unit() const = 0;
|
||||
virtual IfcUtil::IfcBaseEntity* representation_of(const IfcUtil::IfcBaseEntity* product) = 0;
|
||||
|
||||
const IfcGeom::IteratorSettings& settings() const { return settings_; }
|
||||
const ConversionSettings& conversion_settings() const { return conv_settings_; }
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function2<abstract_mapping*, IfcParse::IfcFile*, settings&> mapping_fn;
|
||||
typedef boost::function2<abstract_mapping*, IfcParse::IfcFile*, IfcGeom::IteratorSettings&> mapping_fn;
|
||||
|
||||
class MappingFactoryImplementation : public std::map<std::string, mapping_fn> {
|
||||
public:
|
||||
MappingFactoryImplementation();
|
||||
void bind(const std::string& schema_name, mapping_fn);
|
||||
abstract_mapping* construct(IfcParse::IfcFile*, settings&);
|
||||
abstract_mapping* construct(IfcParse::IfcFile*, IfcGeom::IteratorSettings&);
|
||||
};
|
||||
|
||||
MappingFactoryImplementation& mapping_implementations();
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "CgalConversionResult.h"
|
||||
#include "CgalKernel.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
|
||||
void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const {
|
||||
void ifcopenshell::geometry::CgalShape::Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const {
|
||||
// Copy is made because triangulate_faces() does not accept a const argument
|
||||
cgal_shape_t s = shape_;
|
||||
|
||||
if (!place.components->isIdentity()) {
|
||||
const auto& m = *place.components;
|
||||
if (!place.is_identity()) {
|
||||
const auto& m = place.ccomponents();
|
||||
|
||||
// @todo check
|
||||
const cgal_placement_t trsf(
|
||||
@@ -100,3 +101,29 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
|
||||
double ifcopenshell::geometry::CgalShape::bounding_box(void *& b) const {
|
||||
if (b == nullptr) {
|
||||
b = new CGAL::Bbox_3;
|
||||
}
|
||||
auto& bb = (*((CGAL::Bbox_3*)b));
|
||||
bb += CGAL::Polygon_mesh_processing::bbox(shape_);
|
||||
return (bb.xmax() - bb.xmin()) * (bb.ymax() - bb.ymin()) * (bb.zmax() - bb.zmin());
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::CgalShape::num_vertices() const {
|
||||
return shape_.size_of_vertices();
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::CgalShape::set_box(void * b) {
|
||||
auto& bb = (*((CGAL::Bbox_3*)b));
|
||||
Kernel_::Point_3 lower(bb.xmin(), bb.ymin(), bb.zmin());
|
||||
Kernel_::Point_3 upper(bb.xmax(), bb.ymax(), bb.zmax());
|
||||
shape_ = ifcopenshell::geometry::utils::create_cube(lower, upper);
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::CgalShape::surface_genus() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#ifndef CGALCONVERSIONRESULT_H
|
||||
#define CGALCONVERSIONRESULT_H
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/IfcGeomElement.h"
|
||||
|
||||
#undef Handle
|
||||
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
@@ -52,11 +54,11 @@ 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;
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
class CgalShape : public ConversionResultShape {
|
||||
class CgalShape : public IfcGeom::ConversionResultShape {
|
||||
public:
|
||||
CgalShape(const cgal_shape_t& shape)
|
||||
: shape_(shape)
|
||||
@@ -65,13 +67,13 @@ namespace ifcopenshell { namespace geometry {
|
||||
const cgal_shape_t& shape() const { return shape_; }
|
||||
operator const cgal_shape_t& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const;
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const;
|
||||
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual ConversionResultShape* clone() const {
|
||||
virtual IfcGeom::ConversionResultShape* clone() const {
|
||||
return new CgalShape(shape_);
|
||||
}
|
||||
|
||||
@@ -79,9 +81,14 @@ namespace ifcopenshell { namespace geometry {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual int surface_genus() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
virtual double bounding_box(void*&) const;
|
||||
|
||||
virtual int num_vertices() const;
|
||||
|
||||
virtual void set_box(void*);
|
||||
|
||||
virtual int surface_genus() const;
|
||||
|
||||
private:
|
||||
cgal_shape_t shape_;
|
||||
};
|
||||
|
||||
+1269
-126
File diff suppressed because it is too large
Load Diff
@@ -39,104 +39,76 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
|
||||
#include "../../../ifcparse/macros.h"
|
||||
|
||||
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
#include "../../../ifcgeom/AbstractKernel.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h"
|
||||
|
||||
struct PolyhedronBuilder : public CGAL::Modifier_base<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> {
|
||||
private:
|
||||
std::list<cgal_face_t> *face_list;
|
||||
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();
|
||||
}
|
||||
boost::optional<cgal_shape_t> from_soup;
|
||||
PolyhedronBuilder(std::list<cgal_face_t> *face_list);
|
||||
void operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds);
|
||||
};
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace utils {
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(double d);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
|
||||
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
|
||||
}
|
||||
|
||||
namespace kernels {
|
||||
|
||||
class IFC_GEOM_API CgalKernel : public AbstractKernel {
|
||||
private:
|
||||
double precision_;
|
||||
size_t circle_segments_;
|
||||
CGAL::Nef_polyhedron_3<Kernel_> precision_cube_;
|
||||
|
||||
bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, bool dilate);
|
||||
bool thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result);
|
||||
public:
|
||||
|
||||
CgalKernel()
|
||||
: AbstractKernel("cgal")
|
||||
// @todo
|
||||
, precision_(1.e-5)
|
||||
, circle_segments_(16)
|
||||
{
|
||||
auto cc = utils::create_cube(precision_);
|
||||
precision_cube_ = CGAL::Nef_polyhedron_3<Kernel_>(cc);
|
||||
namespace geometry {
|
||||
namespace utils {
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(double d);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list, bool stitch_borders = false);
|
||||
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
|
||||
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
|
||||
}
|
||||
|
||||
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
|
||||
namespace kernels {
|
||||
|
||||
bool convert(const taxonomy::extrusion*, cgal_shape_t&);
|
||||
bool convert(const taxonomy::face*, cgal_face_t&);
|
||||
bool convert(const taxonomy::loop*, cgal_wire_t&);
|
||||
// bool convert(const taxonomy::matrix4*, cgal_placement_t&);
|
||||
bool convert(const taxonomy::shell*, cgal_shape_t&);
|
||||
|
||||
// virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&);
|
||||
class IFC_GEOM_API CgalKernel : public AbstractKernel {
|
||||
private:
|
||||
size_t circle_segments_;
|
||||
// CGAL::Nef_polyhedron_3<Kernel_> precision_cube_;
|
||||
|
||||
const CGAL::Nef_polyhedron_3<Kernel_>& precision_cube() const { return precision_cube_; }
|
||||
};
|
||||
bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, bool dilate);
|
||||
bool thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result);
|
||||
|
||||
}
|
||||
}
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_precision_cube_() const {
|
||||
auto cc = utils::create_cube(conv_settings_.getValue(ConversionSettings::GV_PRECISION));
|
||||
return CGAL::Nef_polyhedron_3<Kernel_>(cc);
|
||||
}
|
||||
public:
|
||||
|
||||
CgalKernel(const ConversionSettings& settings)
|
||||
: AbstractKernel("cgal", settings)
|
||||
, circle_segments_(32)
|
||||
{}
|
||||
|
||||
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
|
||||
|
||||
bool convert(const taxonomy::extrusion*, cgal_shape_t&);
|
||||
bool convert(const taxonomy::face*, cgal_face_t&);
|
||||
bool convert(const taxonomy::loop*, cgal_wire_t&);
|
||||
// bool convert(const taxonomy::matrix4*, cgal_placement_t&);
|
||||
bool convert(const taxonomy::shell*, cgal_shape_t&);
|
||||
|
||||
bool process_extrusion(const cgal_face_t& bottom_face, const taxonomy::direction3& direction, double height, cgal_shape_t& shape);
|
||||
bool process_as_2d_polygon(const taxonomy::boolean_result* br, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1);
|
||||
bool process_as_2d_polygon(const std::list<std::list<std::pair<const IfcUtil::IfcBaseClass*, cgal_shape_t>>>& operands, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1);
|
||||
|
||||
virtual bool convert_impl(const taxonomy::shell*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::extrusion*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::boolean_result*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::solid*, IfcGeom::ConversionResults&);
|
||||
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::item*, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> precision_cube() const { return create_precision_cube_(); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -20,13 +20,12 @@
|
||||
#ifndef IFCGEOMTREE_H
|
||||
#define IFCGEOMTREE_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../../../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../../../ifcgeom/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/Iterator.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
#include "base_utils.h"
|
||||
|
||||
#include <NCollection_UBTree.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
@@ -39,13 +38,15 @@
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepExtrema_ExtPF.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
struct ray_intersection_result {
|
||||
double distance;
|
||||
int style_index;
|
||||
IfcUtil::IfcBaseEntity* instance;
|
||||
const IfcUtil::IfcBaseEntity* instance;
|
||||
std::array<double, 3> position;
|
||||
std::array<double, 3> normal;
|
||||
double ray_distance;
|
||||
@@ -267,8 +268,16 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
std::vector<T> select(const IfcGeom::BRepElement* elem, bool completely_within = false, double extend = -1.e-5) const {
|
||||
auto compound = elem->geometry().as_compound();
|
||||
compound.Move(elem->transformation().data());
|
||||
auto shp = elem->geometry().as_compound();
|
||||
auto compound = ((OpenCascadeShape*)shp)->shape();
|
||||
const auto& m = elem->transformation().data().ccomponents();
|
||||
gp_Trsf tr;
|
||||
tr.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
compound.Move(tr);
|
||||
return select(compound, completely_within, extend);
|
||||
}
|
||||
|
||||
@@ -354,7 +363,7 @@ namespace IfcGeom {
|
||||
};
|
||||
}
|
||||
|
||||
class tree : public impl::tree<IfcUtil::IfcBaseEntity*> {
|
||||
class tree : public impl::tree<const IfcUtil::IfcBaseEntity*> {
|
||||
public:
|
||||
|
||||
tree() {};
|
||||
@@ -377,7 +386,7 @@ namespace IfcGeom {
|
||||
settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
|
||||
IfcGeom::Iterator it(settings_, &f);
|
||||
IfcGeom::Iterator it(settings_, &f, {}, 1);
|
||||
|
||||
add_file(it);
|
||||
}
|
||||
@@ -394,27 +403,30 @@ namespace IfcGeom {
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
auto compound = elem->geometry().as_compound();
|
||||
compound.Move(elem->transformation().data());
|
||||
auto compound_generic = elem->geometry().as_compound();
|
||||
auto compound = ((ifcopenshell::geometry::OpenCascadeShape*)compound_generic)->shape();
|
||||
|
||||
const auto& m = elem->transformation().data().ccomponents();
|
||||
gp_Trsf tr;
|
||||
tr.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
|
||||
compound.Move(tr);
|
||||
add(elem->product(), compound);
|
||||
auto git = elem->geometry().begin();
|
||||
|
||||
if (enable_face_styles_) {
|
||||
TopoDS_Iterator it(compound);
|
||||
for (; it.More(); it.Next(), ++git) {
|
||||
std::unique_ptr<IfcGeom::Material> adaptor;
|
||||
if (git->hasStyle()) {
|
||||
adaptor.reset(new Material(git->StylePtr()));
|
||||
} else {
|
||||
adaptor.reset(new Material(IfcGeom::get_default_style(elem->type())));
|
||||
}
|
||||
|
||||
// Assumption is that the number of styles is small, so the linear lookup time is not significant.
|
||||
auto sit = std::find(styles_.begin(), styles_.end(), *adaptor);
|
||||
auto sit = std::find(styles_.begin(), styles_.end(), git->Style());
|
||||
size_t index;
|
||||
if (sit == styles_.end()) {
|
||||
index = styles_.size();
|
||||
styles_.push_back(*adaptor);
|
||||
styles_.push_back(git->Style());
|
||||
} else {
|
||||
index = std::distance(styles_.begin(), sit);
|
||||
}
|
||||
@@ -492,7 +504,7 @@ namespace IfcGeom {
|
||||
enable_face_styles_ = b;
|
||||
}
|
||||
|
||||
const std::vector<IfcGeom::Material>& styles() const {
|
||||
const std::vector<ifcopenshell::geometry::taxonomy::style>& styles() const {
|
||||
return styles_;
|
||||
}
|
||||
|
||||
@@ -500,7 +512,7 @@ namespace IfcGeom {
|
||||
typedef TopTools_DataMapOfShapeInteger face_style_map_t;
|
||||
|
||||
face_style_map_t face_styles_;
|
||||
std::vector<IfcGeom::Material> styles_;
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style> styles_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
// We bypass the conversion to gp_GTrsf, because it does not work
|
||||
void taxonomy_transform(const Eigen::Matrix4d* m, gp_XYZ& xyz) {
|
||||
if (m) {
|
||||
Eigen::Vector4d v(xyz.X(), xyz.Y(), xyz.Z(), 1.0);
|
||||
auto v2 = (*m * v).eval();
|
||||
xyz.ChangeData()[0] = v2(0);
|
||||
xyz.ChangeData()[1] = v2(1);
|
||||
xyz.ChangeData()[2] = v2(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const {
|
||||
|
||||
// @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf);
|
||||
// above can be static?
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
boost::optional<gp_Mat> rotation_matrix;
|
||||
|
||||
if (place.components_) {
|
||||
const auto& m = *place.components_;
|
||||
rotation_matrix.emplace(
|
||||
m(0, 0), m(0, 1), m(0, 2),
|
||||
m(1, 0), m(1, 1), m(1, 2),
|
||||
m(2, 0), m(2, 1), m(2, 2)
|
||||
);
|
||||
}
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(shape_, settings.deflection_tolerance(), false, settings.angular_tolerance());
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for (exp.Init(shape_, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (tri.IsNull()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation missing for face");
|
||||
} else {
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int, int>, int> edgecount;
|
||||
std::vector<std::pair<int, int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int, int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings.get(IfcGeom::IteratorSettings::WELD_VERTICES) &&
|
||||
!settings.get(IfcGeom::IteratorSettings::NO_NORMALS);
|
||||
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
taxonomy_transform(place.components_, *coords.rbegin());
|
||||
const gp_XYZ& last = *coords.rbegin();
|
||||
dict[i] = t->addVertex(surface_style_id, last.X(), last.Y(), last.Z());
|
||||
|
||||
if (calculate_normals) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(), uv.Y(), p, normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > 1.e-9) {
|
||||
if (rotation_matrix) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * *rotation_matrix);
|
||||
} else {
|
||||
normal = normal_direction;
|
||||
}
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
|
||||
const bool is_top = uv.Y() > 0;
|
||||
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
|
||||
const double z = (is_top == is_forward) ? 1. : -1.;
|
||||
if (rotation_matrix) {
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z) * *rotation_matrix);
|
||||
} else {
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Do the same for conical surfaces, but they are rare in IFC.
|
||||
}
|
||||
t->addNormal(normal.X(), normal.Y(), normal.Z());
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
triangles(i).Get(n3, n2, n1);
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
t->addFace(surface_style_id, dict[n1], dict[n2], dict[n3]);
|
||||
|
||||
t->addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
t->addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
t->addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for (std::vector<std::pair<int, int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
t->registerEdge(jt->first, jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!t->normals().empty() && settings.get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
t->uvs() = IfcGeom::Representation::Triangulation::box_project_uvs(t->verts(), t->normals());
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(shape_, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings.deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int previous = -1;
|
||||
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
taxonomy_transform(place.components_, p);
|
||||
|
||||
int current = t->addVertex(surface_style_id, p.X(), p.Y(), p.Z());
|
||||
|
||||
std::vector<std::pair<int, int>> segments;
|
||||
if (i > 1) {
|
||||
segments.push_back(std::make_pair(previous, current));
|
||||
}
|
||||
|
||||
if (settings.get(IfcGeom::IteratorSettings::EDGE_ARROWS)) {
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
|
||||
taxonomy_transform(place.components_, p2);
|
||||
taxonomy_transform(place.components_, p3);
|
||||
taxonomy_transform(place.components_, p);
|
||||
|
||||
int left = t->addVertex(surface_style_id, p2.X(), p2.Y(), p2.Z());
|
||||
int right = t->addVertex(surface_style_id, p3.X(), p3.Y(), p3.Z());
|
||||
|
||||
segments.push_back(std::make_pair(left, current));
|
||||
segments.push_back(std::make_pair(right, current));
|
||||
}
|
||||
|
||||
for (auto& sgmt : segments) {
|
||||
t->addEdge(surface_style_id, sgmt.first, sgmt.second);
|
||||
}
|
||||
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(shape_);
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::OpenCascadeShape::surface_genus() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::OpenCascadeShape::is_manifold() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
#define IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
|
||||
class OpenCascadeShape : public IfcGeom::ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape) {}
|
||||
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const;
|
||||
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual IfcGeom::ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
|
||||
virtual bool is_manifold() const;
|
||||
|
||||
virtual double bounding_box(void*&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual int num_vertices() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual void set_box(void*) {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual int surface_genus() const;
|
||||
private:
|
||||
TopoDS_Shape shape_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,61 +43,25 @@
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../../ifcgeom/AbstractKernel.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomShapeType.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../ifcgeom_schema_agnostic/ifc_geom_api.h"
|
||||
#include "../../../ifcgeom/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
|
||||
// Define this in case you want to conserve memory usage at all cost. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
// #define NO_CACHE
|
||||
#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#ifdef NO_CACHE
|
||||
#include "../../../ifcgeom/ifc_geom_api.h"
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
#include "../../../ifcgeom/taxonomy.h"
|
||||
#include "../../../ifcgeom/ConversionSettings.h"
|
||||
|
||||
#else
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->data().id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
|
||||
|
||||
#endif
|
||||
|
||||
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
|
||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||
#undef INCLUDE_PARENT_DIR
|
||||
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||
// @todo remove once merged to same ns.
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
|
||||
public:
|
||||
#include "mapping_cache.i"
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
namespace util {
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_pointer<T>::value, T&>::type conditional_address_of(T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_pointer<T>::value, T*>::type conditional_address_of(T& t) {
|
||||
return &t;
|
||||
}
|
||||
}
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
|
||||
class IFC_GEOM_API OpenCascadeKernel : public kernels::AbstractKernel {
|
||||
private:
|
||||
|
||||
/*
|
||||
@@ -108,20 +72,18 @@ private:
|
||||
threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c).
|
||||
*/
|
||||
|
||||
template <typename CP=const IfcSchema::IfcCartesianPoint*, typename LP=const IfcSchema::IfcPolyLoop*>
|
||||
class faceset_helper {
|
||||
private:
|
||||
MAKE_TYPE_NAME(Kernel)* kernel_;
|
||||
std::set<typename std::conditional<std::is_pointer<LP>::value, LP, const LP*>::type> duplicates_;
|
||||
std::map<const void*, int> vertex_mapping_;
|
||||
OpenCascadeKernel* kernel_;
|
||||
std::set<int> duplicates_;
|
||||
std::map<int, int> vertex_mapping_;
|
||||
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
||||
// not always in use
|
||||
const std::vector<std::vector<double>>* points_ = nullptr;
|
||||
double eps_;
|
||||
bool non_manifold_;
|
||||
|
||||
void loop_(const LP& lp, const std::function<void(int, int, bool)>& callback);
|
||||
void loop_(const taxonomy::loop* ps, const std::function<void(int, int, bool)>& callback);
|
||||
|
||||
/*
|
||||
bool construct(const IfcSchema::IfcCartesianPoint* cp, gp_Pnt* l);
|
||||
bool construct(const std::vector<double>& cp, gp_Pnt* l);
|
||||
|
||||
@@ -135,13 +97,9 @@ private:
|
||||
|
||||
std::vector<const void*> get_idxs(const IfcSchema::IfcPolyLoop* lp);
|
||||
std::vector<const void*> get_idxs(const std::vector<int>& it);
|
||||
*/
|
||||
public:
|
||||
faceset_helper(
|
||||
MAKE_TYPE_NAME(Kernel)* kernel,
|
||||
const std::vector<CP>& points,
|
||||
const std::vector<LP>& indices,
|
||||
bool should_by_closed);
|
||||
|
||||
faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell* l);
|
||||
~faceset_helper();
|
||||
|
||||
bool non_manifold() const { return non_manifold_; }
|
||||
@@ -150,280 +108,64 @@ private:
|
||||
|
||||
bool edge(int A, int B, TopoDS_Edge& e);
|
||||
|
||||
bool wire(const LP& loop, TopoDS_Wire& wire);
|
||||
bool wires(const LP& loop, TopTools_ListOfShape& wires);
|
||||
bool wire(const taxonomy::loop* loop, TopoDS_Wire& wire);
|
||||
bool wires(const taxonomy::loop* loop, TopTools_ListOfShape& wires);
|
||||
};
|
||||
|
||||
double deflection_tolerance;
|
||||
double max_faces_to_orient;
|
||||
double ifc_length_unit;
|
||||
double ifc_planeangle_unit;
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
double layerset_first;
|
||||
double no_wire_intersection_check;
|
||||
double no_wire_intersection_tolerance;
|
||||
double precision_factor;
|
||||
double boolean_debug_setting;
|
||||
double boolean_attempt_2d;
|
||||
|
||||
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
|
||||
const IfcParse::declaration* placement_rel_to_type_;
|
||||
const IfcUtil::IfcBaseEntity* placement_rel_to_instance_;
|
||||
|
||||
faceset_helper<>* faceset_helper_;
|
||||
double disable_boolean_result;
|
||||
faceset_helper* faceset_helper_;
|
||||
|
||||
// @todo these should be moved to the mapping
|
||||
/*
|
||||
gp_Vec offset = gp_Vec{0.0, 0.0, 0.0};
|
||||
gp_Quaternion rotation = gp_Quaternion{};
|
||||
gp_Trsf offset_and_rotation = gp_Trsf();
|
||||
*/
|
||||
|
||||
#ifndef NO_CACHE
|
||||
MAKE_TYPE_NAME(Cache) cache;
|
||||
#endif
|
||||
|
||||
std::map<int, std::shared_ptr<const SurfaceStyle>> style_cache;
|
||||
|
||||
std::shared_ptr<const SurfaceStyle> internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
|
||||
double precision_;
|
||||
|
||||
public:
|
||||
MAKE_TYPE_NAME(Kernel)()
|
||||
: IfcGeom::Kernel()
|
||||
, deflection_tolerance(0.001)
|
||||
, max_faces_to_orient(-1.0)
|
||||
, ifc_length_unit(1.0)
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
, layerset_first(-1.)
|
||||
|
||||
, no_wire_intersection_check(-1)
|
||||
, no_wire_intersection_tolerance(-1)
|
||||
, precision_factor(10.)
|
||||
, boolean_debug_setting(false)
|
||||
, boolean_attempt_2d(true)
|
||||
|
||||
, placement_rel_to_type_(nullptr)
|
||||
, placement_rel_to_instance_(nullptr)
|
||||
OpenCascadeKernel(const ConversionSettings& settings)
|
||||
: AbstractKernel("opencascade", settings)
|
||||
, faceset_helper_(nullptr)
|
||||
, disable_boolean_result(-1.)
|
||||
, precision_(settings.getValue(ConversionSettings::GV_PRECISION))
|
||||
{}
|
||||
|
||||
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other)
|
||||
: IfcGeom::Kernel()
|
||||
, deflection_tolerance(other.deflection_tolerance)
|
||||
, max_faces_to_orient(other.max_faces_to_orient)
|
||||
, ifc_length_unit(other.ifc_length_unit)
|
||||
, ifc_planeangle_unit(other.ifc_planeangle_unit)
|
||||
, modelling_precision(other.modelling_precision)
|
||||
, dimensionality(other.dimensionality)
|
||||
, layerset_first(other.layerset_first)
|
||||
, no_wire_intersection_check(other.no_wire_intersection_check)
|
||||
, no_wire_intersection_tolerance(other.no_wire_intersection_tolerance)
|
||||
, precision_factor(other.precision_factor)
|
||||
, boolean_debug_setting(other.boolean_debug_setting)
|
||||
, boolean_attempt_2d(other.boolean_attempt_2d)
|
||||
, placement_rel_to_type_(other.placement_rel_to_type_)
|
||||
, placement_rel_to_instance_(other.placement_rel_to_instance_)
|
||||
// @nb faceset_helper_ always initialized to 0
|
||||
, faceset_helper_(nullptr)
|
||||
, disable_boolean_result(other.disable_boolean_result)
|
||||
, offset(other.offset)
|
||||
, rotation(other.rotation)
|
||||
, offset_and_rotation(other.offset_and_rotation)
|
||||
{
|
||||
bool convert(const taxonomy::extrusion*, TopoDS_Shape&);
|
||||
bool convert(const taxonomy::face*, TopoDS_Shape&);
|
||||
bool convert(const taxonomy::loop*, TopoDS_Wire&);
|
||||
bool convert(const taxonomy::matrix4*, gp_GTrsf&);
|
||||
bool convert(const taxonomy::shell*, TopoDS_Shape&);
|
||||
bool convert(const taxonomy::solid*, TopoDS_Shape&);
|
||||
bool convert(const taxonomy::bspline_surface* bs, Handle(Geom_Surface) surf);
|
||||
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const taxonomy::matrix4& t);
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t);
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t);
|
||||
|
||||
virtual bool convert_impl(const taxonomy::face*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::solid*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::shell*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::extrusion*, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::boolean_result*, IfcGeom::ConversionResults&);
|
||||
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::item*, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
|
||||
|
||||
template <typename T, typename U>
|
||||
static T convert_xyz(const U& u) {
|
||||
const auto& vs = u.ccomponents();
|
||||
return T(vs(0), vs(1), vs(2));
|
||||
}
|
||||
|
||||
MAKE_TYPE_NAME(Kernel)& operator=(const MAKE_TYPE_NAME(Kernel)& other) {
|
||||
deflection_tolerance = other.deflection_tolerance;
|
||||
max_faces_to_orient = other.max_faces_to_orient;
|
||||
ifc_length_unit = other.ifc_length_unit;
|
||||
ifc_planeangle_unit = other.ifc_planeangle_unit;
|
||||
modelling_precision = other.modelling_precision;
|
||||
dimensionality = other.dimensionality;
|
||||
layerset_first = other.layerset_first;
|
||||
no_wire_intersection_check = other.no_wire_intersection_check;
|
||||
no_wire_intersection_tolerance = other.no_wire_intersection_tolerance;
|
||||
precision_factor = other.precision_factor;
|
||||
boolean_debug_setting = other.boolean_debug_setting;
|
||||
boolean_attempt_2d = other.boolean_attempt_2d;
|
||||
placement_rel_to_type_ = other.placement_rel_to_type_;
|
||||
placement_rel_to_instance_ = other.placement_rel_to_instance_;
|
||||
disable_boolean_result = other.disable_boolean_result;
|
||||
offset = other.offset;
|
||||
rotation = other.rotation;
|
||||
offset_and_rotation = other.offset_and_rotation;
|
||||
return *this;
|
||||
// @todo eliminate
|
||||
template <typename T, typename U>
|
||||
static T convert_xyz2(const U& vs) {
|
||||
return T(vs(0), vs(1), vs(2));
|
||||
}
|
||||
|
||||
void set_offset(const std::array<double, 3>& offset);
|
||||
void set_rotation(const std::array<double, 4>& rotation);
|
||||
double get_wire_intersection_tolerance(const TopoDS_Wire&) const;
|
||||
|
||||
bool convert_shapes(const IfcUtil::IfcBaseInterface* L, IfcRepresentationShapeItems& result);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseInterface* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseInterface* L, TopoDS_Shape& result);
|
||||
bool convert_wire(const IfcUtil::IfcBaseInterface* L, TopoDS_Wire& result);
|
||||
bool convert_curve(const IfcUtil::IfcBaseInterface* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseInterface* L, TopoDS_Shape& result);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<std::shared_ptr<const SurfaceStyle>>&, std::vector<double>&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
|
||||
|
||||
bool is_identity_transform(IfcUtil::IfcBaseInterface*);
|
||||
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
|
||||
|
||||
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement*);
|
||||
|
||||
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
|
||||
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
|
||||
std::shared_ptr<const SurfaceStyle> get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
std::shared_ptr<const SurfaceStyle> get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
std::vector<IfcSchema::IfcPresentationStyle*> prs_styles;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
|
||||
aggregate_of_instance::ptr style_assignments = si->Styles();
|
||||
for (aggregate_of_instance::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
|
||||
// Using IfcPresentationStyleAssignment is deprecated, use the direct assignment of a subtype of IfcPresentationStyle instead.
|
||||
auto style_k = (*kt)->as<IfcSchema::IfcPresentationStyle>();
|
||||
if (style_k) {
|
||||
prs_styles.push_back(style_k);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
|
||||
Logger::Warning("Deprecated usage of", style_assignment);
|
||||
|
||||
// Only in case of 2x3 or old style IfcPresentationStyleAssignment
|
||||
auto styles = style_assignment->Styles();
|
||||
|
||||
#elif defined SCHEMA_HAS_IfcPresentationStyleAssignment
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
|
||||
// Only in case of 2x3 or old style IfcPresentationStyleAssignment
|
||||
auto styles = style_assignment->Styles();
|
||||
#else
|
||||
auto styles = si->Styles();
|
||||
#endif
|
||||
|
||||
for (auto lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
auto style_l = (*lt)->as<IfcSchema::IfcPresentationStyle>();
|
||||
if (style_l) {
|
||||
prs_styles.push_back(style_l);
|
||||
}
|
||||
}
|
||||
#if defined(SCHEMA_HAS_IfcStyleAssignmentSelect) || defined(SCHEMA_HAS_IfcPresentationStyleAssignment)
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto& style : prs_styles) {
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
aggregate_of_instance::ptr styles_elements = surface_style->Styles();
|
||||
for (aggregate_of_instance::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->declaration().is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
|
||||
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
if (styled_items->size()) {
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
|
||||
return _get_surface_style<T>(*styled_items->begin());
|
||||
}
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
void purge_cache() {
|
||||
// Rather hack-ish, but a stopgap solution to keep memory under control
|
||||
// for large files. SurfaceStyles need to be kept at all costs, as they
|
||||
// are read later on when serializing Collada files.
|
||||
#ifndef NO_CACHE
|
||||
cache = MAKE_TYPE_NAME(Cache)();
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_conversion_placement_rel_to_type(const IfcParse::declaration* type);
|
||||
void set_conversion_placement_rel_to_instance(const IfcUtil::IfcBaseEntity* instance);
|
||||
|
||||
#include "mapping_kernel_header.i"
|
||||
|
||||
virtual void setValue(GeomValue var, double value);
|
||||
virtual double getValue(GeomValue var) const;
|
||||
|
||||
virtual IfcGeom::BRepElement* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return create_brep_for_representation_and_product(settings, representation->as<IfcSchema::IfcRepresentation>(), product->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
IfcRepresentationShapeItems items;
|
||||
bool success = convert_shapes(item, items);
|
||||
if (!success) {
|
||||
throw IfcParse::IfcException("Failed to process representation item");
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
try {
|
||||
return convert(item->as<IfcSchema::IfcObjectPlacement>(), trsf);
|
||||
} catch (std::exception& e) {
|
||||
Logger::Error(e, item);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed processing placement", item);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "base_utils.h"
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
#include "boolean_utils.h"
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
@@ -40,6 +42,8 @@
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
|
||||
// For axis placements detect equality early in order for the
|
||||
@@ -739,3 +743,66 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
|
||||
return valid_shell;
|
||||
}
|
||||
|
||||
bool IfcGeom::util::flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, double tol) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
result = TopoDS_Shape();
|
||||
|
||||
for (IfcGeom::ConversionResults::const_iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
TopoDS_Shape merged;
|
||||
const TopoDS_Shape& s = ((ifcopenshell::geometry::OpenCascadeShape*)it->Shape())->shape();
|
||||
if (fuse) {
|
||||
util::ensure_fit_for_subtraction(s, merged, tol);
|
||||
} else {
|
||||
merged = s;
|
||||
}
|
||||
|
||||
// @todo refactor, also should be GTrsf
|
||||
const auto& m = it->Placement().ccomponents();
|
||||
gp_Trsf trsf;
|
||||
trsf.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
|
||||
const TopoDS_Shape moved_shape = util::apply_transformation(merged, trsf);
|
||||
|
||||
if (shapes.size() == 1) {
|
||||
result = moved_shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fuse) {
|
||||
if (result.IsNull()) {
|
||||
result = moved_shape;
|
||||
} else {
|
||||
BRepAlgoAPI_Fuse brep_fuse(result, moved_shape);
|
||||
if (brep_fuse.IsDone()) {
|
||||
TopoDS_Shape fused = brep_fuse;
|
||||
|
||||
ShapeFix_Shape fix(result);
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if (is_valid) {
|
||||
result = fused;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fuse) {
|
||||
result = compound;
|
||||
}
|
||||
|
||||
const bool success = !result.IsNull();
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef BASE_UTILS_H
|
||||
#define BASE_UTILS_H
|
||||
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
@@ -65,6 +67,8 @@ namespace IfcGeom {
|
||||
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, double tol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include "boolean_utils.h"
|
||||
#include "base_utils.h"
|
||||
|
||||
using namespace IfcGeom;
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
|
||||
namespace {
|
||||
BOPAlgo_Operation op_to_occt(taxonomy::boolean_result::operation_t t) {
|
||||
switch (t) {
|
||||
case taxonomy::boolean_result::UNION: return BOPAlgo_FUSE;
|
||||
case taxonomy::boolean_result::INTERSECTION: return BOPAlgo_COMMON;
|
||||
case taxonomy::boolean_result::SUBTRACTION: return BOPAlgo_CUT;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_single_child(const TopoDS_Shape& s, TopoDS_Shape& child) {
|
||||
TopoDS_Iterator it(s);
|
||||
if (!it.More()) {
|
||||
return false;
|
||||
}
|
||||
child = it.Value();
|
||||
it.Next();
|
||||
return !it.More();
|
||||
}
|
||||
|
||||
bool is_unbounded_halfspace(const TopoDS_Shape& solid) {
|
||||
if (solid.ShapeType() != TopAbs_SOLID) {
|
||||
return false;
|
||||
}
|
||||
TopoDS_Shape shell;
|
||||
if (!get_single_child(solid, shell)) {
|
||||
return false;
|
||||
}
|
||||
TopoDS_Shape face;
|
||||
if (!get_single_child(shell, face)) {
|
||||
return false;
|
||||
}
|
||||
TopoDS_Iterator it(face);
|
||||
return !it.More();
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result* br, ConversionResults& results) {
|
||||
bool valid_result = false;
|
||||
bool first = true;
|
||||
const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
|
||||
|
||||
TopoDS_Shape a;
|
||||
TopTools_ListOfShape b;
|
||||
|
||||
taxonomy::style* first_item_style = nullptr;
|
||||
|
||||
for (auto& c : br->children) {
|
||||
IfcGeom::ConversionResults cr;
|
||||
AbstractKernel::convert(c, cr);
|
||||
if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) {
|
||||
// @todo A will be null on union/intersection, intended?
|
||||
IfcGeom::util::flatten_shape_list(cr, a, false, conv_settings_.getValue(ifcopenshell::geometry::ConversionSettings::GV_PRECISION));
|
||||
first_item_style = ((taxonomy::geom_item*)c)->surface_style;
|
||||
if (!first_item_style && c->kind() == taxonomy::COLLECTION) {
|
||||
// @todo recursively right?
|
||||
first_item_style = ((taxonomy::geom_item*) ((taxonomy::collection*)c)->children[0])->surface_style;
|
||||
}
|
||||
|
||||
if (conv_settings_.getValue(ConversionSettings::GV_DISABLE_BOOLEAN_RESULT) > 0.0) {
|
||||
results.emplace_back(IfcGeom::ConversionResult(
|
||||
(int)br->instance->data().id(),
|
||||
br->matrix,
|
||||
new OpenCascadeShape(a),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
const double first_operand_volume = util::shape_volume(a);
|
||||
if (first_operand_volume <= ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", c->instance);
|
||||
}
|
||||
} else {
|
||||
|
||||
for (auto& r : cr) {
|
||||
auto S = ((OpenCascadeShape*)r.Shape())->shape();
|
||||
gp_GTrsf trsf;
|
||||
convert(&r.Placement(), trsf);
|
||||
// @todo it really confuses me why I cannot use Moved() here instead
|
||||
S.Location(S.Location() * trsf.Trsf());
|
||||
|
||||
if (is_unbounded_halfspace(S)) {
|
||||
double d;
|
||||
TopoDS_Shape result;
|
||||
util::fit_halfspace(a, S, result, d, tol * 1e3);
|
||||
// #2665 we also set a precision-independent treshold, because in the boolean op routine
|
||||
// the working fuzziness might still be increased.
|
||||
if (d < tol * 20. || d < 0.00002) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", c->instance);
|
||||
continue;
|
||||
} else {
|
||||
S = result;
|
||||
}
|
||||
}
|
||||
|
||||
b.Append(S);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
util::boolean_settings bst;
|
||||
bst.attempt_2d = conv_settings_.getValue(ConversionSettings::GV_BOOLEAN_ATTEMPT_2D) > 0.;
|
||||
bst.debug = conv_settings_.getValue(ConversionSettings::GV_DEBUG_BOOLEAN) > 0.;
|
||||
bst.precision = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
|
||||
|
||||
TopoDS_Shape r;
|
||||
|
||||
if (a.ShapeType() == TopAbs_COMPOUND && TopoDS_Iterator(a).More() && util::is_nested_compound_of_solid(a)) {
|
||||
TopoDS_Compound C;
|
||||
BRep_Builder B;
|
||||
B.MakeCompound(C);
|
||||
TopoDS_Iterator it(a);
|
||||
valid_result = true;
|
||||
for (; it.More(); it.Next()) {
|
||||
TopoDS_Shape part;
|
||||
if (util::boolean_operation(bst, it.Value(), b, op_to_occt(br->operation), part)) {
|
||||
B.Add(C, part);
|
||||
} else {
|
||||
valid_result = false;
|
||||
}
|
||||
}
|
||||
r = C;
|
||||
} else {
|
||||
valid_result = util::boolean_operation(bst, a, b, op_to_occt(br->operation), r);
|
||||
}
|
||||
|
||||
results.emplace_back(IfcGeom::ConversionResult(
|
||||
(int) br->instance->data().id(),
|
||||
br->matrix,
|
||||
new OpenCascadeShape(r),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
));
|
||||
|
||||
return valid_result;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "boolean_utils.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomTree.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "IfcGeomTree.h"
|
||||
#include "base_utils.h"
|
||||
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
@@ -834,6 +834,25 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
fuzziness = settings.precision / 10.;
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
TopoDS_Compound C;
|
||||
BRep_Builder BB;
|
||||
BB.MakeCompound(C);
|
||||
|
||||
BB.Add(C, a_input);
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b_input);
|
||||
for (; it.More(); it.Next()) {
|
||||
BB.Add(C, it.Value());
|
||||
}
|
||||
|
||||
result = C;
|
||||
}
|
||||
|
||||
return true;
|
||||
*/
|
||||
|
||||
// @todo, it does seem a bit odd, we first triangulate non-planar faces
|
||||
// to later unify them again. Can we make this a bit more intelligent?
|
||||
TopoDS_Shape a;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::bspline_surface* bs, Handle(Geom_Surface) surf) {
|
||||
const bool is_rational = !!bs->weights;
|
||||
|
||||
TColgp_Array2OfPnt Poles(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
TColStd_Array2OfReal Weights(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)bs->knots[0].size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)bs->knots[1].size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)bs->multiplicities[0].size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)bs->multiplicities[1].size() - 1);
|
||||
Standard_Integer UDegree = bs->degree[0];
|
||||
Standard_Integer VDegree = bs->degree[1];
|
||||
|
||||
int i = 0, j;
|
||||
for (auto it = bs->control_points.begin(); it != bs->control_points.end(); ++it, ++i) {
|
||||
j = 0;
|
||||
for (auto jt = (*it).begin(); jt != (*it).end(); ++jt, ++j) {
|
||||
Poles(i, j) = convert_xyz<gp_Pnt>(*jt);
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = bs->knots[0].begin(); it != bs->knots[0].end(); ++it, ++i) {
|
||||
UKnots(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = bs->knots[1].begin(); it != bs->knots[1].end(); ++it, ++i) {
|
||||
VKnots(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = bs->multiplicities[0].begin(); it != bs->multiplicities[0].end(); ++it, ++i) {
|
||||
UMults(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = bs->multiplicities[1].begin(); it != bs->multiplicities[1].end(); ++it, ++i) {
|
||||
VMults(i) = *it;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
for (auto it = bs->weights->begin(); it != bs->weights->end(); ++it, ++i) {
|
||||
j = 0;
|
||||
for (auto jt = (*it).begin(); jt != (*it).end(); ++jt, ++j) {
|
||||
Weights(i, j) = *jt;
|
||||
}
|
||||
}
|
||||
surf = new Geom_BSplineSurface(Poles, Weights, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
} else {
|
||||
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Shape& shape) {
|
||||
const double& height = extrusion->depth;
|
||||
|
||||
if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) {
|
||||
Logger::Error("Non-positive extrusion height encountered for:", extrusion->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Shape face;
|
||||
if (!convert(&extrusion->basis, face)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// @todo we need to decide whether the matrix is kept on the taxonomy node or
|
||||
// move the TopoDS_Shape, but obviously not both.
|
||||
gp_GTrsf gtrsf;
|
||||
if (!convert(&extrusion->matrix, gtrsf)) {
|
||||
Logger::Error("Unable to move extrusion");
|
||||
}
|
||||
auto trsf = gtrsf.Trsf();
|
||||
*/
|
||||
|
||||
const auto& fs = extrusion->direction.ccomponents();
|
||||
gp_Dir dir(fs(0), fs(1), fs(2));
|
||||
|
||||
shape.Nullify();
|
||||
|
||||
if (face.ShapeType() == TopAbs_COMPOUND) {
|
||||
|
||||
// For compounds (most likely the result of a IfcCompositeProfileDef)
|
||||
// create a compound solid shape.
|
||||
|
||||
TopExp_Explorer exp(face, TopAbs_FACE);
|
||||
|
||||
TopoDS_CompSolid compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompSolid(compound);
|
||||
|
||||
int num_faces_extruded = 0;
|
||||
for (; exp.More(); exp.Next(), ++num_faces_extruded) {
|
||||
builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir));
|
||||
}
|
||||
|
||||
if (num_faces_extruded) {
|
||||
shape = compound;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shape.IsNull()) {
|
||||
shape = BRepPrimAPI_MakePrism(face, height*dir);
|
||||
}
|
||||
|
||||
/*
|
||||
if (!shape.IsNull()) {
|
||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||
// and therefore has a unit scale factor
|
||||
shape.Move(trsf);
|
||||
}
|
||||
*/
|
||||
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, IfcGeom::ConversionResults& results) {
|
||||
TopoDS_Shape shape;
|
||||
if (!convert(extrusion, shape)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
results.emplace_back(ConversionResult(
|
||||
extrusion->instance->data().id(),
|
||||
extrusion->matrix,
|
||||
new OpenCascadeShape(shape),
|
||||
extrusion->surface_style
|
||||
));
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <BRepLib_FindSurface.hxx>
|
||||
#include <ShapeExtend_MsgRegistrator.hxx>
|
||||
#include <Message_Msg.hxx>
|
||||
#include <ShapeFix_Edge.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
|
||||
#include "OpenCascadeKernel.h"
|
||||
#include "face_definition.h"
|
||||
#include "wire_utils.h"
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
using namespace IfcGeom::util;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result) {
|
||||
auto bounds = face->children_as<taxonomy::loop>();
|
||||
|
||||
face_definition fd;
|
||||
|
||||
const bool is_face_surface = false; /* todo */
|
||||
|
||||
/*
|
||||
if (is_face_surface) {
|
||||
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
|
||||
fs->FaceSurface();
|
||||
// FIXME: Surfaces are interpreted as a TopoDS_Shape
|
||||
TopoDS_Shape surface_shape;
|
||||
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
|
||||
|
||||
// FIXME: Assert this obtaines the only face
|
||||
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
|
||||
if (!exp.More()) return false;
|
||||
|
||||
TopoDS_Face surface = TopoDS::Face(exp.Current());
|
||||
fd.surface() = BRep_Tool::Surface(surface);
|
||||
}
|
||||
*/
|
||||
|
||||
const int num_bounds = bounds.size();
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (auto& bound : bounds) {
|
||||
if (bound->external.get_value_or(false)) {
|
||||
num_outer_bounds++;
|
||||
}
|
||||
}
|
||||
|
||||
// The number of outer bounds should be one according to the schema. Also Open Cascade
|
||||
// expects this, but it is not strictly checked. Regardless, if the number is greater,
|
||||
// the face will still be processed as long as there are no holes. A compound of faces
|
||||
// is returned in that case.
|
||||
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_outer_bounds > 1) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Multiple outer boundaries for:", face->instance);
|
||||
fd.all_outer() = true;
|
||||
}
|
||||
|
||||
TopTools_DataMapOfShapeInteger wire_senses;
|
||||
|
||||
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
|
||||
for (auto& bound : bounds) {
|
||||
bool same_sense = true; /* todo bound->Orientation(); */
|
||||
|
||||
const bool is_interior =
|
||||
!bound->external.get_value_or(false) &&
|
||||
(num_bounds > 1) &&
|
||||
(num_outer_bounds < num_bounds);
|
||||
|
||||
// The exterior face boundary is processed first
|
||||
if (is_interior == !process_interior) continue;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (faceset_helper_ && bound->is_polyhedron()) {
|
||||
if (!faceset_helper_->wire(bound, wire)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Face boundary loop not included", bound->instance);
|
||||
continue;
|
||||
}
|
||||
} else if (!convert(bound, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!same_sense) {
|
||||
wire.Reverse();
|
||||
}
|
||||
|
||||
wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED);
|
||||
|
||||
fd.wires().emplace_back(wire);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.wires().empty()) {
|
||||
Logger::Warning("Face with no boundaries", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// Use the first wire to find a plane manually for polygonal wires
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
if (is_polyhedron(wire)) {
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
int count = 0;
|
||||
TopoDS_Edge edges[2];
|
||||
for (; exp.More(); exp.Next(), count++) {
|
||||
if (count < 2) {
|
||||
edges[count] = TopoDS::Edge(exp.Current());
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 3) {
|
||||
// Help Open Cascade by finding the plane more efficiently
|
||||
double _, __;
|
||||
Handle(Geom_Line) c1 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[0], _, __));
|
||||
Handle(Geom_Line) c2 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[1], _, __));
|
||||
|
||||
const gp_Vec ab = c1->Position().Direction();
|
||||
const gp_Vec ac = c2->Position().Direction();
|
||||
const gp_Vec cross = ab.Crossed(ac);
|
||||
|
||||
if (cross.SquareMagnitude() > ALMOST_ZERO) {
|
||||
const gp_Dir n = cross;
|
||||
fd.surface() = new Geom_Plane(c1->Position().Location(), n);
|
||||
}
|
||||
} else {
|
||||
gp_Pln pln;
|
||||
if (approximate_plane_through_wire(wire, pln, precision_)) {
|
||||
fd.surface() = new Geom_Plane(pln);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// BRepLib_FindSurface is used in case no surface is found or provided
|
||||
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
|
||||
BRepLib_FindSurface fs(wire, precision_, true, true);
|
||||
if (fs.Found()) {
|
||||
fd.surface() = fs.Surface();
|
||||
ShapeFix_ShapeTolerance ftol;
|
||||
ftol.SetTolerance(wire, fs.ToleranceReached(), TopAbs_WIRE);
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// The set of wires is triangulated in case no surface can be found
|
||||
Logger::Message(Logger::LOG_WARNING, "Triangulating face boundaries for face", face->instance);
|
||||
|
||||
if (fd.all_outer()) {
|
||||
for (const auto& w : fd.wires()) {
|
||||
TopTools_ListOfShape fl;
|
||||
triangulate_wire({ w }, fl);
|
||||
face_list.Append(fl);
|
||||
}
|
||||
} else {
|
||||
triangulate_wire(fd.wires(), face_list);
|
||||
}
|
||||
} else if (!fd.all_outer()) {
|
||||
BRepBuilderAPI_MakeFace mf(fd.surface(), fd.outer_wire());
|
||||
|
||||
if (mf.IsDone()) {
|
||||
// Is this necessary
|
||||
TopoDS_Face f = mf.Face();
|
||||
mf.Init(f);
|
||||
|
||||
for (auto it = fd.inner_wires().first; it != fd.inner_wires().second; ++it) {
|
||||
mf.Add(*it);
|
||||
}
|
||||
|
||||
face_list.Append(mf.Face());
|
||||
}
|
||||
} else {
|
||||
for (const auto& w : fd.wires()) {
|
||||
BRepBuilderAPI_MakeFace mf(fd.surface(), w);
|
||||
if (mf.IsDone()) {
|
||||
face_list.Append(mf.Face());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fd.surface().IsNull()) {
|
||||
// Some fixes for orientation and p-curves. If we have no surface, it
|
||||
// means the face has been triangulated in which case none of these
|
||||
// fixes are necessary.
|
||||
|
||||
if (fd.surface()->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
|
||||
// In case of (non-planar) face surface, p-curves need to be computed.
|
||||
// For planar faces, Open Cascade generates p-curves on the fly.
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
// Small chance there are multiple faces
|
||||
const TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
for (TopExp_Explorer exp2(occ_face, TopAbs_EDGE); exp2.More(); exp2.Next()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(exp2.Current());
|
||||
ShapeFix_Edge fix_edge;
|
||||
fix_edge.FixAddPCurve(edge, occ_face, false, precision_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
const TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
|
||||
ShapeFix_Face sfs(TopoDS::Face(occ_face));
|
||||
TopTools_DataMapOfShapeListOfShape wire_map;
|
||||
sfs.FixOrientation(wire_map);
|
||||
|
||||
TopoDS_Iterator jt(occ_face, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
// tfk: @todo if wire_map contains w, I would assume wire_senses also contains w,
|
||||
// this is not the case in github issue #405.
|
||||
if (wire_map.IsBound(w) && wire_senses.IsBound(w)) {
|
||||
const TopTools_ListOfShape& shapes = wire_map.Find(w);
|
||||
TopTools_ListIteratorOfListOfShape kt(shapes);
|
||||
for (; kt.More(); kt.Next()) {
|
||||
// Apparently the wire got reversed, so register it with opposite orientation in the map
|
||||
wire_senses.Bind(kt.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it.Value() = sfs.Face();
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
|
||||
bool all_reversed = true;
|
||||
TopoDS_Iterator jt(occ_face, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) {
|
||||
all_reversed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_reversed) {
|
||||
occ_face.Reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (face_list.Extent() == 0) {
|
||||
return false;
|
||||
} else if (face_list.Extent() > 1) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
builder.Add(compound, occ_face);
|
||||
}
|
||||
result = compound;
|
||||
} else {
|
||||
result = face_list.First();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert_impl(const taxonomy::face* face, IfcGeom::ConversionResults& results) {
|
||||
throw std::runtime_error("Root-level face not expected");
|
||||
/*
|
||||
|
||||
// Root level faces are only encountered in case of half spaces
|
||||
// @todo this is not true, halfspace will be solid>face
|
||||
|
||||
if (face->basis == nullptr) {
|
||||
Logger::Error("Half space without underlying surface:", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (face->basis->kind() != taxonomy::PLANE) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", face->basis->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
// @todo boundary
|
||||
const auto& m = ((taxonomy::geom_item*)face->basis)->matrix.ccomponents();
|
||||
gp_Pln pln(convert_xyz2<gp_Pnt>(m.col(3)), convert_xyz2<gp_Dir>(m.col(2)));
|
||||
const gp_Pnt pnt = pln.Location().Translated(face->orientation.get_value_or(false) ? -pln.Axis().Direction() : pln.Axis().Direction());
|
||||
TopoDS_Shape shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln), pnt).Solid();
|
||||
results.emplace_back(ConversionResult(
|
||||
face->instance->data().id(),
|
||||
new OpenCascadeShape(shape),
|
||||
face->surface_style
|
||||
));
|
||||
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
+48
-90
@@ -1,9 +1,7 @@
|
||||
#include "IfcGeom.h"
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomTree.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "IfcGeomTree.h"
|
||||
#include "wire_utils.h"
|
||||
|
||||
namespace {
|
||||
void find_neighbours(IfcGeom::impl::tree<int>& tree, std::vector<std::unique_ptr<gp_Pnt>>& pnts, std::set<int>& visited, int p, double eps) {
|
||||
@@ -27,28 +25,28 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const std::vector<std::vector<double>>* store_cache(const std::vector<std::vector<double>>& p) {
|
||||
return &p;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<double>>* store_cache(const std::vector<const IfcSchema::IfcCartesianPoint*>& /*p*/) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
Kernel* kernel,
|
||||
const std::vector<CP>& points,
|
||||
const std::vector<LP>& indices,
|
||||
bool should_be_closed
|
||||
IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
||||
OpenCascadeKernel* kernel,
|
||||
const taxonomy::shell* shell
|
||||
)
|
||||
: kernel_(kernel)
|
||||
, non_manifold_(false)
|
||||
, points_(store_cache(points))
|
||||
{
|
||||
std::vector<std::unique_ptr<gp_Pnt>> pnts(std::distance(points.begin(), points.end()));
|
||||
// @todo use pointers?
|
||||
std::vector<taxonomy::point3> points;
|
||||
std::vector<taxonomy::loop*> loops;
|
||||
|
||||
for (auto& f : shell->children_as<taxonomy::face>()) {
|
||||
for (auto& l : f->children_as<taxonomy::loop>()) {
|
||||
loops.push_back(l);
|
||||
for (auto& e : l->children_as<taxonomy::edge>()) {
|
||||
// @todo make sure only cartesian points are provided here
|
||||
points.push_back(boost::get<taxonomy::point3>(e->start));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<gp_Pnt>> pnts(points.size());
|
||||
std::vector<TopoDS_Vertex> vertices(pnts.size());
|
||||
|
||||
IfcGeom::impl::tree<int> tree;
|
||||
@@ -57,15 +55,11 @@ IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
|
||||
Bnd_Box box;
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
gp_Pnt* p = new gp_Pnt;
|
||||
if (construct(points[i], p)) {
|
||||
pnts[i].reset(p);
|
||||
B.MakeVertex(vertices[i], *p, Precision::Confusion());
|
||||
tree.add((int)i, vertices[i]);
|
||||
box.Add(*p);
|
||||
} else {
|
||||
delete p;
|
||||
}
|
||||
gp_Pnt* p = new gp_Pnt(convert_xyz<gp_Pnt>(points[i]));
|
||||
pnts[i].reset(p);
|
||||
B.MakeVertex(vertices[i], *p, Precision::Confusion());
|
||||
tree.add(i, vertices[i]);
|
||||
box.Add(*p);
|
||||
}
|
||||
|
||||
// Use the bbox diagonal to influence local epsilon
|
||||
@@ -85,12 +79,12 @@ IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
double bdiff = std::numeric_limits<double>::infinity();
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
const double d = bmax[i] - bmin[i];
|
||||
if (d > kernel->getValue(GV_PRECISION) * 10. && d < bdiff) {
|
||||
if (d > kernel->settings().getValue(ConversionSettings::GV_PRECISION) * 10. && d < bdiff) {
|
||||
bdiff = d;
|
||||
}
|
||||
}
|
||||
|
||||
eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff);
|
||||
eps_ = kernel->settings().getValue(ConversionSettings::GV_PRECISION) * 10. * (std::min)(1.0, bdiff);
|
||||
|
||||
size_t loops_removed, non_manifold, duplicate_faces;
|
||||
|
||||
@@ -122,9 +116,11 @@ IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
find_neighbours(tree, pnts, vs, pnt_i, eps_);
|
||||
|
||||
for (int v : vs) {
|
||||
auto& pt = points[v];
|
||||
// NB: insert() ignores duplicate keys
|
||||
// v-1?
|
||||
vertex_mapping_.insert({ get_idx(points[v]), pnt_i });
|
||||
// @todo this reliable also in case of tesselations?
|
||||
vertex_mapping_.insert({ pt.instance->data().id(), pnt_i });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,18 +144,19 @@ IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
typedef std::set<edge_t> edge_set_t;
|
||||
std::set<edge_set_t> edge_sets;
|
||||
|
||||
for (auto ps = indices.begin(); ps != indices.end(); ++ps) {
|
||||
for (auto& loop : loops) {
|
||||
std::vector<std::pair<int, int> > segments;
|
||||
edge_set_t segment_set;
|
||||
|
||||
loop_(*ps, [&segments, &segment_set](int C, int D, bool) {
|
||||
loop_(loop, [&segments, &segment_set](int C, int D, bool) {
|
||||
segment_set.insert(edge_t{ C,D });
|
||||
segments.push_back(std::make_pair(C, D));
|
||||
});
|
||||
|
||||
if (edge_sets.find(segment_set) != edge_sets.end()) {
|
||||
duplicate_faces++;
|
||||
duplicates_.insert(util::conditional_address_of(*ps));
|
||||
// @todo does this work with tesselated face sets, will they have an associated instance? Guess not.
|
||||
duplicates_.insert(loop->instance->data().id());
|
||||
continue;
|
||||
}
|
||||
edge_sets.insert(segment_set);
|
||||
@@ -190,21 +187,20 @@ IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates_.size() || loops_removed || (non_manifold && should_be_closed)) {
|
||||
if (duplicates_.size() || loops_removed || (non_manifold && shell->closed.get_value_or(false))) {
|
||||
Logger::Warning(boost::lexical_cast<std::string>(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast<std::string>(loops_removed) + " degenerate loops eliminated and " + boost::lexical_cast<std::string>(non_manifold) + " non-manifold edges");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
void IfcGeom::Kernel::faceset_helper<CP, LP>::loop_(const LP& lp, const std::function<void(int, int, bool)>& callback) {
|
||||
auto ps = get_idxs(lp);
|
||||
|
||||
if (ps.size() < 3) {
|
||||
void IfcGeom::OpenCascadeKernel::faceset_helper::loop_(const taxonomy::loop* ps, const std::function<void(int, int, bool)>& callback) {
|
||||
if (ps->children.size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto A = ps.back();
|
||||
for (auto& B : ps) {
|
||||
auto a = boost::get<taxonomy::point3>(((taxonomy::edge*) ps->children.back())->start).instance;
|
||||
auto A = a->data().id();
|
||||
for (auto& b : ps->children) {
|
||||
auto B = boost::get<taxonomy::point3>(((taxonomy::edge*) b)->start).instance->data().id();
|
||||
auto C = vertex_mapping_[A], D = vertex_mapping_[B];
|
||||
bool fwd = C < D;
|
||||
if (!fwd) {
|
||||
@@ -217,23 +213,7 @@ void IfcGeom::Kernel::faceset_helper<CP, LP>::loop_(const LP& lp, const std::fun
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
std::vector<const void*> IfcGeom::Kernel::faceset_helper<CP, LP>::get_idxs(const IfcSchema::IfcPolyLoop* lp) {
|
||||
auto poly = lp->Polygon();
|
||||
std::vector<const void*> idxs;
|
||||
std::transform(poly->begin(), poly->end(), std::back_inserter(idxs), [this](const IfcSchema::IfcCartesianPoint* p) {return get_idx(p); });
|
||||
return idxs;
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
std::vector<const void*> IfcGeom::Kernel::faceset_helper<CP, LP>::get_idxs(const std::vector<int>& it) {
|
||||
std::vector<const void*> idxs;
|
||||
std::transform(it.begin(), it.end(), std::back_inserter(idxs), [this](int i) { return get_idx((*points_)[i - 1]); });
|
||||
return idxs;
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
bool IfcGeom::Kernel::faceset_helper<CP, LP>::edge(int A, int B, TopoDS_Edge& e) {
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::edge(int A, int B, TopoDS_Edge& e) {
|
||||
auto it = edges_.find({ A, B });
|
||||
if (it == edges_.end()) {
|
||||
return false;
|
||||
@@ -242,8 +222,7 @@ bool IfcGeom::Kernel::faceset_helper<CP, LP>::edge(int A, int B, TopoDS_Edge& e)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
bool IfcGeom::Kernel::faceset_helper<CP, LP>::wire(const LP& loop, TopoDS_Wire& w) {
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const taxonomy::loop* loop, TopoDS_Wire& w) {
|
||||
TopTools_ListOfShape ws;
|
||||
if (!wires(loop, ws)) {
|
||||
return false;
|
||||
@@ -252,9 +231,8 @@ bool IfcGeom::Kernel::faceset_helper<CP, LP>::wire(const LP& loop, TopoDS_Wire&
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
bool IfcGeom::Kernel::faceset_helper<CP, LP>::wires(const LP& loop, TopTools_ListOfShape& wires) {
|
||||
if (duplicates_.find(util::conditional_address_of(loop)) != duplicates_.end()) {
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const taxonomy::loop* loop, TopTools_ListOfShape& wires) {
|
||||
if (duplicates_.find(loop->instance->data().id()) != duplicates_.end()) {
|
||||
return false;
|
||||
}
|
||||
TopoDS_Wire wire;
|
||||
@@ -275,7 +253,7 @@ bool IfcGeom::Kernel::faceset_helper<CP, LP>::wires(const LP& loop, TopTools_Lis
|
||||
wire.Closed(true);
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
if (kernel_->getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(wire, results, {kernel_->getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., kernel_->getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., kernel_->getValue(GV_PRECISION)})) {
|
||||
if (kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(wire, results, {kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_CHECK) < 0., kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., kernel_->settings().getValue(ConversionSettings::GV_PRECISION)})) {
|
||||
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
non_manifold_ = true;
|
||||
wires = results;
|
||||
@@ -289,28 +267,8 @@ bool IfcGeom::Kernel::faceset_helper<CP, LP>::wires(const LP& loop, TopTools_Lis
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
IfcGeom::Kernel::faceset_helper<CP, LP>::~faceset_helper() {
|
||||
IfcGeom::OpenCascadeKernel::faceset_helper::~faceset_helper() {
|
||||
// @todo this is super ugly, but how else can we be notified that the unique_ptr goes out of scope?
|
||||
// Perhaps just supply a custom std::deleter?
|
||||
kernel_->faceset_helper_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename CP, typename LP>
|
||||
bool IfcGeom::Kernel::faceset_helper<CP, LP>::construct(const IfcSchema::IfcCartesianPoint* cp, gp_Pnt* l) {
|
||||
return kernel_->convert(cp, *l);
|
||||
}
|
||||
|
||||
template <typename CP, typename LP>
|
||||
bool IfcGeom::Kernel::faceset_helper<CP, LP>::construct(const std::vector<double>& cp, gp_Pnt* l) {
|
||||
if (cp.size() != 3) {
|
||||
return false;
|
||||
}
|
||||
auto LU = kernel_->getValue(GV_LENGTH_UNIT);
|
||||
l->SetCoord(cp[0] * LU, cp[1] * LU, cp[2] * LU);
|
||||
return true;
|
||||
}
|
||||
|
||||
template class IfcGeom::Kernel::faceset_helper<const IfcSchema::IfcCartesianPoint*, const IfcSchema::IfcPolyLoop*>;
|
||||
template class IfcGeom::Kernel::faceset_helper<std::vector<double>, std::vector<int>>;
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "layerset.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
#include "base_utils.h"
|
||||
#include "boolean_utils.h"
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
|
||||
@@ -30,6 +31,8 @@
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <NCollection_IncAllocator.hxx>
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
namespace {
|
||||
|
||||
void subshapes(const TopoDS_Shape& in, std::list<TopoDS_Shape>& out) {
|
||||
@@ -161,7 +164,7 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::apply_folded_layerset(const IfcRepresentationShapeItems& items, const std::vector< std::vector<Handle_Geom_Surface> >& surfaces, const std::vector<std::shared_ptr<const SurfaceStyle>>& styles, IfcRepresentationShapeItems& result, double tol) {
|
||||
bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const std::vector< std::vector<Handle_Geom_Surface> >& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style>& styles, ConversionResults& result, double tol) {
|
||||
Bnd_Box bb;
|
||||
TopoDS_Shape input;
|
||||
flatten_shape_list(items, input, false, tol);
|
||||
@@ -243,11 +246,11 @@ bool IfcGeom::util::apply_folded_layerset(const IfcRepresentationShapeItems& ite
|
||||
|
||||
} else if (shells.Extent() == 1) {
|
||||
|
||||
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
TopoDS_Shape a, b;
|
||||
if (split_solid_by_shell(it->Shape(), shells.First(), a, b, tol)) {
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, !!styles[0] ? styles[0] : it->StylePtr()));
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, !!styles[1] ? styles[1] : it->StylePtr()));
|
||||
if (split_solid_by_shell(((OpenCascadeShape*)it->Shape())->shape(), shells.First(), a, b, tol)) {
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(), new OpenCascadeShape(b), &(!!styles[0].diffuse ? styles[0] : it->Style())));
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(), new OpenCascadeShape(a), &(!!styles[1].diffuse ? styles[1] : it->Style())));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -257,16 +260,16 @@ bool IfcGeom::util::apply_folded_layerset(const IfcRepresentationShapeItems& ite
|
||||
|
||||
} else {
|
||||
|
||||
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const TopoDS_Shape& s = ((OpenCascadeShape*)it->Shape())->shape();
|
||||
TopoDS_Solid sld;
|
||||
ensure_fit_for_subtraction(s, sld, tol);
|
||||
|
||||
std::vector<TopoDS_Shape> slices;
|
||||
if (split(it->Shape(), shells, tol, slices) && slices.size() == styles.size()) {
|
||||
if (split(s, shells, tol, slices) && slices.size() == styles.size()) {
|
||||
for (size_t i = 0; i < slices.size(); ++i) {
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), slices[i], !!styles[i] ? styles[i] : it->StylePtr()));
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(), new OpenCascadeShape(slices[i]), &(!!styles[i].diffuse ? styles[i] : it->Style())));
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
@@ -279,18 +282,18 @@ bool IfcGeom::util::apply_folded_layerset(const IfcRepresentationShapeItems& ite
|
||||
|
||||
}
|
||||
|
||||
bool IfcGeom::util::apply_layerset(const IfcRepresentationShapeItems& items, const std::vector<Handle_Geom_Surface>& surfaces, const std::vector<std::shared_ptr<const SurfaceStyle>>& styles, IfcRepresentationShapeItems& result, double tol) {
|
||||
bool IfcGeom::util::apply_layerset(const ConversionResults& items, const std::vector<Handle_Geom_Surface>& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style>& styles, ConversionResults& result, double tol) {
|
||||
if (surfaces.size() < 3) {
|
||||
|
||||
return false;
|
||||
|
||||
} else if (surfaces.size() == 3) {
|
||||
|
||||
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
TopoDS_Shape a, b;
|
||||
if (split_solid_by_surface(it->Shape(), surfaces[1], a, b, tol)) {
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, !!styles[0] ? styles[0] : it->StylePtr()));
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, !!styles[1] ? styles[1] : it->StylePtr()));
|
||||
if (split_solid_by_surface(((OpenCascadeShape*)it->Shape())->shape(), surfaces[1], a, b, tol)) {
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(),new OpenCascadeShape(b), &(!!styles[0].diffuse ? styles[0] : it->Style())));
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(),new OpenCascadeShape(a), &(!!styles[1].diffuse ? styles[1] : it->Style())));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -304,7 +307,7 @@ bool IfcGeom::util::apply_layerset(const IfcRepresentationShapeItems& items, con
|
||||
// Determine whether sequence of surfaces is consistent with surface normal, so that
|
||||
// layer operations are applied in the correct order. This seems to be always the case.
|
||||
Bnd_Box bb;
|
||||
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
BRepBndLib::Add(it->Shape(), bb);
|
||||
}
|
||||
|
||||
@@ -329,9 +332,9 @@ bool IfcGeom::util::apply_layerset(const IfcRepresentationShapeItems& items, con
|
||||
mass.ChangeCoord() += n1.XYZ();
|
||||
*/
|
||||
|
||||
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const TopoDS_Shape& s = ((OpenCascadeShape*)it->Shape())->shape();
|
||||
TopoDS_Solid sld;
|
||||
ensure_fit_for_subtraction(s, sld, tol);
|
||||
|
||||
@@ -350,14 +353,14 @@ bool IfcGeom::util::apply_layerset(const IfcRepresentationShapeItems& items, con
|
||||
/*
|
||||
// enable this is you want to see how IfcOpenShell has placed the layer surfaces
|
||||
for (auto& x : operands) {
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), x, nullptr));
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(), x, nullptr));
|
||||
}
|
||||
*/
|
||||
|
||||
std::vector<TopoDS_Shape> slices;
|
||||
if (split(it->Shape(), operands, tol, slices) && slices.size() == styles.size()) {
|
||||
if (split(s, operands, tol, slices) && slices.size() == styles.size()) {
|
||||
for (size_t i = 0; i < slices.size(); ++i) {
|
||||
result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), slices[i], !!styles[i] ? styles[i] : it->StylePtr()));
|
||||
result.push_back(ConversionResult(it->ItemId(), it->Placement(), new OpenCascadeShape(slices[i]), &(!!styles[i].diffuse ? styles[i] : it->Style())));
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef LAYERSET_H
|
||||
#define LAYERSET_H
|
||||
|
||||
#include "IfcRepresentationShapeItem.h"
|
||||
#include "../../ConversionResult.h"
|
||||
|
||||
#include <Geom_Surface.hxx>
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace util {
|
||||
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<std::shared_ptr<const SurfaceStyle>>&, IfcRepresentationShapeItems&, double tol);
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<ifcopenshell::geometry::taxonomy::style>&, ConversionResults&, double tol);
|
||||
|
||||
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<std::shared_ptr<const SurfaceStyle>>&, IfcRepresentationShapeItems&, double tol);
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<ifcopenshell::geometry::taxonomy::style>&, ConversionResults&, double tol);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&, double tol);
|
||||
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
#include "wire_builder.h"
|
||||
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <BRepAdaptor_CompCurve.hxx>
|
||||
#include <BRepAdaptor_HCompCurve.hxx>
|
||||
#include <Approx_Curve3d.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
using namespace IfcGeom::util;
|
||||
|
||||
namespace {
|
||||
typedef boost::variant<Handle(Geom_Curve), TopoDS_Wire> curve_creation_visitor_result_type;
|
||||
curve_creation_visitor_result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve);
|
||||
|
||||
struct curve_creation_visitor {
|
||||
OpenCascadeKernel* kernel;
|
||||
curve_creation_visitor_result_type result;
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::bspline_curve& bc) {
|
||||
|
||||
const bool is_rational = !!bc.weights;
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, bc.control_points.size() - 1);
|
||||
TColStd_Array1OfReal Weights(0, bc.control_points.size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)bc.knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)bc.knots.size() - 1);
|
||||
Standard_Integer Degree = bc.degree;
|
||||
Standard_Boolean Periodic = false;
|
||||
// @tfk: it appears to be wrong to expect a period curve when the curve is closed, see #586
|
||||
// Standard_Boolean Periodic = l->ClosedCurve();
|
||||
|
||||
int i;
|
||||
|
||||
if (is_rational) {
|
||||
i = 0;
|
||||
for (auto it = bc.weights->begin(); it != bc.weights->end(); ++it, ++i) {
|
||||
Weights(i) = *it;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto it = bc.control_points.begin(); it != bc.control_points.end(); ++it, ++i) {
|
||||
Poles(i) = OpenCascadeKernel::convert_xyz<gp_Pnt>(*it);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto it = bc.multiplicities.begin(); it != bc.multiplicities.end(); ++it, ++i) {
|
||||
Mults(i) = *it;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto it = bc.knots.begin(); it != bc.knots.end(); ++it, ++i) {
|
||||
Knots(i) = *it;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
return result = Handle(Geom_Curve)(new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic));
|
||||
} else {
|
||||
return result = Handle(Geom_Curve)(new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic));
|
||||
}
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::line& l) {
|
||||
const auto& m = l.matrix.ccomponents();
|
||||
return result = Handle(Geom_Curve)(new Geom_Line(OpenCascadeKernel::convert_xyz2<gp_Pnt>(m.col(3)), OpenCascadeKernel::convert_xyz2<gp_Dir>(m.col(0))));
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::circle& c) {
|
||||
const auto& m = c.matrix.ccomponents();
|
||||
return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(OpenCascadeKernel::convert_xyz2<gp_Pnt>(m.col(3)), OpenCascadeKernel::convert_xyz2<gp_Dir>(m.col(2)), OpenCascadeKernel::convert_xyz2<gp_Dir>(m.col(0))), c.radius));
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::ellipse& e) {
|
||||
const auto& m = e.matrix.ccomponents();
|
||||
return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(OpenCascadeKernel::convert_xyz2<gp_Pnt>(m.col(3)), OpenCascadeKernel::convert_xyz2<gp_Dir>(m.col(2)), OpenCascadeKernel::convert_xyz2<gp_Dir>(m.col(0))), e.radius, e.radius2));
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::loop& l) {
|
||||
TopoDS_Wire wire;
|
||||
kernel->convert(&l, wire);
|
||||
return result = wire;
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::edge& e) {
|
||||
// @todo for polyloops/-lines we should probably construct edges based on correct oriented TopoDS_Vertex instead.
|
||||
|
||||
if (e.start.which() != e.end.which()) {
|
||||
throw std::runtime_error("Different trim types not supported");
|
||||
}
|
||||
|
||||
TopoDS_Edge E;
|
||||
if (e.basis) {
|
||||
auto crv_or_wire = convert_curve(kernel, e.basis);
|
||||
Handle(Geom_Curve) curve;
|
||||
if (crv_or_wire.which() == 0) {
|
||||
curve = boost::get<Handle(Geom_Curve)>(crv_or_wire);
|
||||
} else {
|
||||
// @todo
|
||||
const double precision_ = 1.e-5;
|
||||
Logger::Warning("Approximating BasisCurve due to possible discontinuities", e.instance);
|
||||
BRepAdaptor_CompCurve cc(boost::get<TopoDS_Wire>(crv_or_wire), true);
|
||||
Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc));
|
||||
// @todo, arbitrary numbers here, note they cannot be too high as contiguous memory is allocated based on them.
|
||||
Approx_Curve3d approx(hcc, precision_, GeomAbs_C0, 10, 10);
|
||||
curve = approx.Curve();
|
||||
}
|
||||
|
||||
const bool reversed = !((taxonomy::geom_item*)e.basis)->orientation.get_value_or(true);
|
||||
const bool is_conic = e.basis->kind() == taxonomy::ELLIPSE || e.basis->kind() == taxonomy::CIRCLE;
|
||||
|
||||
// @todo, copy over logic from previous IfcTrimmedCurve handling
|
||||
if (e.start.which() == 0) {
|
||||
auto p1 = OpenCascadeKernel::convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.start));
|
||||
auto p2 = OpenCascadeKernel::convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.end));
|
||||
|
||||
if (reversed) {
|
||||
std::swap(p1, p2);
|
||||
}
|
||||
|
||||
E = BRepBuilderAPI_MakeEdge(curve, p1, p2).Edge();
|
||||
} else {
|
||||
auto v1 = boost::get<double>(e.start);
|
||||
auto v2 = boost::get<double>(e.end);
|
||||
|
||||
if (reversed) {
|
||||
std::swap(v1, v2);
|
||||
}
|
||||
|
||||
if (is_conic && ALMOST_THE_SAME(fmod(v2 - v1, M_PI*2.), 0.)) {
|
||||
E = BRepBuilderAPI_MakeEdge(curve).Edge();
|
||||
} else {
|
||||
E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge();
|
||||
}
|
||||
}
|
||||
|
||||
if (reversed) {
|
||||
E.Reverse();
|
||||
}
|
||||
} else {
|
||||
if (e.start.which() != 0) {
|
||||
throw std::runtime_error("Non-cartesian trim on edge without curve");
|
||||
}
|
||||
auto p1 = OpenCascadeKernel::convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.start));
|
||||
auto p2 = OpenCascadeKernel::convert_xyz<gp_Pnt>(boost::get<taxonomy::point3>(e.end));
|
||||
|
||||
E = BRepBuilderAPI_MakeEdge(p1, p2).Edge();
|
||||
}
|
||||
BRep_Builder B;
|
||||
TopoDS_Wire W;
|
||||
B.MakeWire(W);
|
||||
B.Add(W, E);
|
||||
return result = W;
|
||||
}
|
||||
|
||||
curve_creation_visitor_result_type operator()(const taxonomy::offset_curve& l) {
|
||||
// @todo
|
||||
throw std::runtime_error("Offset curves not supported as part of loop");
|
||||
}
|
||||
};
|
||||
|
||||
curve_creation_visitor_result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve) {
|
||||
curve_creation_visitor v{ kernel };
|
||||
if (dispatch_curve_creation<curve_creation_visitor, 0>::dispatch(curve, v)) {
|
||||
return v.result;
|
||||
} else {
|
||||
throw std::runtime_error("No curve created");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) {
|
||||
auto segments = loop->children_as<taxonomy::edge>();
|
||||
|
||||
TopTools_ListOfShape converted_segments;
|
||||
|
||||
for (auto& segment : segments) {
|
||||
auto segment_wire = boost::get<TopoDS_Wire>(convert_curve(this, segment));
|
||||
|
||||
#ifdef IFOPSH_DEBUG
|
||||
std::ostringstream o;
|
||||
segment->print(o);
|
||||
TopoDS_Vertex v0, v1;
|
||||
TopExp::Vertices(segment_wire, v0, v1);
|
||||
gp_Pnt p0 = BRep_Tool::Pnt(v0);
|
||||
gp_Pnt p1 = BRep_Tool::Pnt(v1);
|
||||
o << "p0 " << p0.X() << " " << p0.Y() << " " << p0.Z() << std::endl;
|
||||
o << "p1 " << p1.X() << " " << p1.Y() << " " << p1.Z() << std::endl;
|
||||
auto o_str = o.str();
|
||||
std::wcout << o_str.c_str() << std::endl;
|
||||
#endif
|
||||
|
||||
if (!segment->orientation_2.get_value_or(true)) {
|
||||
segment_wire.Reverse();
|
||||
}
|
||||
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(segment_wire, precision_, TopAbs_WIRE);
|
||||
|
||||
converted_segments.Append(segment_wire);
|
||||
}
|
||||
|
||||
if (converted_segments.Extent() == 0) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No segment succesfully converted:", loop->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(converted_segments);
|
||||
|
||||
/*
|
||||
@todo
|
||||
IfcEntityList::ptr profile = l->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
|
||||
const bool force_close = profile && profile->size() > 0;
|
||||
*/
|
||||
const bool force_close = false;
|
||||
|
||||
wire_builder bld(precision_, loop->instance->as<IfcUtil::IfcBaseEntity>());
|
||||
shape_pair_enumerate(it, bld, force_close);
|
||||
wire = bld.wire();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
using namespace IfcGeom::util;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) {
|
||||
// @todo check
|
||||
const auto& m = matrix->ccomponents();
|
||||
gp_Mat mat(
|
||||
m(0, 0), m(0, 1), m(0, 2),
|
||||
m(1, 0), m(1, 1), m(1, 2),
|
||||
m(2, 0), m(2, 1), m(2, 2)
|
||||
);
|
||||
|
||||
if (matrix->instance && matrix->instance->declaration().name() == "IfcCartesianTransformationOperator3DnonUniform") {
|
||||
std::wcout << "non uniform" << std::endl;
|
||||
}
|
||||
|
||||
// @nb SetVectorialPart() sets gp_GTrsf.scale to 0.0, causing an non-invertable
|
||||
// matrix later on which cannot be in TopLoc_Location.
|
||||
|
||||
std::array<double, 3> ms{ {
|
||||
mat.Column(1).Modulus(),
|
||||
mat.Column(2).Modulus(),
|
||||
mat.Column(3).Modulus()
|
||||
} };
|
||||
std::sort(ms.begin(), ms.end());
|
||||
|
||||
if (std::fabs(ms.front() - ms.back()) < 1.e-7) {
|
||||
gp_Trsf tr;
|
||||
tr.SetValues(
|
||||
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
|
||||
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
|
||||
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
|
||||
);
|
||||
trsf = tr;
|
||||
} else {
|
||||
trsf.SetVectorialPart(mat);
|
||||
trsf.SetTranslationPart(gp_XYZ(m(0, 3), m(1, 3), m(2, 3)));
|
||||
trsf.SetForm();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include "base_utils.h"
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
using namespace IfcGeom::util;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::shell* l, TopoDS_Shape& shape) {
|
||||
std::unique_ptr<faceset_helper> helper_scope;
|
||||
helper_scope.reset(new faceset_helper(this, l));
|
||||
|
||||
faceset_helper_ = helper_scope.get();
|
||||
|
||||
auto faces = l->children_as<taxonomy::face>();
|
||||
double minimal_face_area = precision_ * precision_ * 0.5;
|
||||
|
||||
double min_face_area = faceset_helper_
|
||||
? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.)
|
||||
: minimal_face_area;
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
for (auto& face : faces) {
|
||||
bool success = false;
|
||||
TopoDS_Face occ_face;
|
||||
|
||||
try {
|
||||
success = convert(face, occ_face);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error creating face");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating face");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", face->instance);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (occ_face.ShapeType() == TopAbs_COMPOUND) {
|
||||
TopoDS_Iterator face_it(occ_face, false);
|
||||
for (; face_it.More(); face_it.Next()) {
|
||||
if (face_it.Value().ShapeType() == TopAbs_FACE) {
|
||||
// This should really be the case. This is not asserted.
|
||||
const TopoDS_Face& triangle = TopoDS::Face(face_it.Value());
|
||||
if (face_area(triangle) > min_face_area) {
|
||||
face_list.Append(triangle);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (face_area(occ_face) > min_face_area) {
|
||||
face_list.Append(occ_face);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (face_list.Extent() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @todo
|
||||
/* face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || */
|
||||
|
||||
if (!create_solid_from_faces(face_list, shape, conv_settings_.getValue(ifcopenshell::geometry::ConversionSettings::GV_PRECISION))) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
TopTools_ListIteratorOfListOfShape face_iterator;
|
||||
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
|
||||
builder.Add(compound, face_iterator.Value());
|
||||
}
|
||||
shape = compound;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, IfcGeom::ConversionResults& results) {
|
||||
TopoDS_Shape shape;
|
||||
if (!convert(shell, shape)) {
|
||||
return false;
|
||||
}
|
||||
results.emplace_back(ConversionResult(
|
||||
shell->instance->data().id(),
|
||||
shell->matrix,
|
||||
new OpenCascadeShape(shape),
|
||||
shell->surface_style
|
||||
));
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
using namespace ifcopenshell::geometry::kernels;
|
||||
using namespace IfcGeom;
|
||||
using namespace IfcGeom::util;
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::solid* solid, TopoDS_Shape& result) {
|
||||
BRep_Builder BB;
|
||||
TopoDS_Solid S;
|
||||
for (auto& s : solid->children) {
|
||||
if (s->kind() == taxonomy::FACE) {
|
||||
// halfspace
|
||||
if (solid->children.size() != 1) {
|
||||
throw std::runtime_error("Unexpected number of children on solid");
|
||||
}
|
||||
|
||||
auto face = (taxonomy::face*) s;
|
||||
|
||||
const auto& m = ((taxonomy::geom_item*)face->basis)->matrix.ccomponents();
|
||||
gp_Pln pln(convert_xyz2<gp_Pnt>(m.col(3)), convert_xyz2<gp_Dir>(m.col(2)));
|
||||
const gp_Pnt pnt = pln.Location().Translated(face->orientation.get_value_or(false) ? pln.Axis().Direction() : -pln.Axis().Direction());
|
||||
TopoDS_Shape halfspace = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln), pnt).Solid();
|
||||
|
||||
if (!face->children.empty()) {
|
||||
TopoDS_Wire wire;
|
||||
gp_GTrsf gtrsf;
|
||||
|
||||
if (convert((taxonomy::loop*)face->children[0], wire) && wire.Closed() && convert(&face->matrix, gtrsf)) {
|
||||
gp_Trsf trsf = gtrsf.Trsf();
|
||||
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire), gp_Vec(0, 0, 200));
|
||||
gp_Trsf down; down.SetTranslation(gp_Vec(0, 0, -100.0));
|
||||
|
||||
// `trsf` and `down` both have a unit scale factor
|
||||
prism.Move(trsf*down);
|
||||
|
||||
halfspace = BRepAlgoAPI_Common(halfspace, prism);
|
||||
}
|
||||
}
|
||||
|
||||
result = halfspace;
|
||||
return true;
|
||||
} else {
|
||||
if (s->kind() != taxonomy::SHELL) {
|
||||
throw std::runtime_error("Unexpected child in solid");
|
||||
}
|
||||
if (S.IsNull()) {
|
||||
BB.MakeSolid(S);
|
||||
}
|
||||
TopoDS_Shell shl;
|
||||
convert(((taxonomy::shell*)s), shl);
|
||||
BB.Add(S, shl);
|
||||
}
|
||||
}
|
||||
if (!S.IsNull()) {
|
||||
result = S;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert_impl(const taxonomy::solid* solid , IfcGeom::ConversionResults& results) {
|
||||
TopoDS_Shape shape;
|
||||
if (!convert(solid, shape)) {
|
||||
return false;
|
||||
}
|
||||
results.emplace_back(ConversionResult(
|
||||
solid->instance->data().id(),
|
||||
solid->matrix,
|
||||
new OpenCascadeShape(shape),
|
||||
solid->surface_style
|
||||
));
|
||||
return true;
|
||||
}
|
||||
@@ -21,9 +21,8 @@
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepOffsetAPI_MakePipeShell.hxx>
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "base_utils.h"
|
||||
|
||||
bool IfcGeom::util::wire_is_c1_continuous(const TopoDS_Wire & w, double tol) {
|
||||
// NB Note that c0 continuity is NOT checked!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "wire_builder.h"
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/ConversionSettings.h"
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef WIRE_BUILDER_H
|
||||
#define WIRE_BUILDER_H
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include <Geom_Curve.hxx>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "wire_utils.h"
|
||||
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../ifcgeom_schema_agnostic/boolean_utils.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomTree.h"
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/ConversionSettings.h"
|
||||
|
||||
#include "base_utils.h"
|
||||
#include "boolean_utils.h"
|
||||
#include "IfcGeomTree.h"
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
@@ -17,17 +17,18 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/*
|
||||
#include "IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomShapeType.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define Kernel POSTFIX_SCHEMA(Kernel)
|
||||
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseInterface* l, IfcRepresentationShapeItems& r) {
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseInterface* l, ConversionResults& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
@@ -35,7 +36,7 @@ bool IfcGeom::Kernel::convert_shapes(const IfcBaseInterface* l, IfcRepresentatio
|
||||
if (l->as<IfcSchema::IfcRepresentationItem>()) {
|
||||
style = get_style(l->as<IfcSchema::IfcRepresentationItem>());
|
||||
}
|
||||
r.push_back(IfcGeom::IfcRepresentationShapeItem(l->data().id(), shp, style));
|
||||
r.push_back(IfcGeom::ConversionResult(l->data().id(), shp, style));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -68,7 +69,7 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseInterface* l, TopoDS_Shape& r)
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPELIST) {
|
||||
processed = true;
|
||||
IfcRepresentationShapeItems items;
|
||||
ConversionResults items;
|
||||
success = convert_shapes(l, items) && util::flatten_shape_list(items, r, false, getValue(GV_PRECISION));
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "mapping_shape.i"
|
||||
@@ -131,3 +132,4 @@ bool IfcGeom::Kernel::convert_curve(const IfcBaseInterface* l, Handle(Geom_Curve
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
@@ -1,166 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file registers function prototypes for all supported IFC geometrical *
|
||||
* entities. For entities of type CLASS an std::map is also created to cache *
|
||||
* the output of the conversion functions *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
// IfcFacetedBrep included
|
||||
// IfcAdvancedBrep included
|
||||
// IfcFacetedBrepWithVoids included
|
||||
// IfcAdvancedBrepWithVoids included
|
||||
SHAPES(IfcManifoldSolidBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcCylindricalSurface
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedBrep
|
||||
SHAPE(IfcAdvancedBrep);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcToroidalSurface
|
||||
SHAPE(IfcToroidalSurface);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcSphericalSurface
|
||||
SHAPE(IfcSphericalSurface);
|
||||
#endif
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
|
||||
SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcTriangulatedFaceSet
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcPolygonalFaceSet
|
||||
SHAPE(IfcPolygonalFaceSet);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered
|
||||
SHAPE(IfcExtrudedAreaSolidTapered);
|
||||
#endif
|
||||
SHAPE(IfcPlane);
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanResult);
|
||||
SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcSurfaceOfLinearExtrusion);
|
||||
SHAPE(IfcSurfaceOfRevolution);
|
||||
SHAPE(IfcBlock);
|
||||
SHAPE(IfcBoundingBox);
|
||||
SHAPE(IfcRectangularPyramid);
|
||||
SHAPE(IfcRightCircularCylinder);
|
||||
SHAPE(IfcRightCircularCone);
|
||||
SHAPE(IfcSphere);
|
||||
SHAPE(IfcCsgSolid);
|
||||
SHAPE(IfcCurveBoundedPlane);
|
||||
SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
|
||||
FACE(IfcAnnotationFillArea);
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
FACE(IfcRoundedRectangleProfileDef);
|
||||
FACE(IfcRectangleHollowProfileDef);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
FACE(IfcTrapeziumProfileDef);
|
||||
FACE(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcLShapeProfileDef);
|
||||
FACE(IfcTShapeProfileDef);
|
||||
FACE(IfcUShapeProfileDef);
|
||||
FACE(IfcZShapeProfileDef);
|
||||
FACE(IfcCircleHollowProfileDef);
|
||||
FACE(IfcCircleProfileDef);
|
||||
FACE(IfcEllipseProfileDef);
|
||||
FACE(IfcCenterLineProfileDef);
|
||||
FACE(IfcCompositeProfileDef);
|
||||
FACE(IfcDerivedProfileDef);
|
||||
// IfcFaceSurface included
|
||||
// IfcAdvancedFace included in case of IFC4
|
||||
FACE(IfcFace);
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcCraneRailAShapeProfileDef
|
||||
FACE(IfcCraneRailAShapeProfileDef);
|
||||
#endif
|
||||
|
||||
WIRE(IfcEdgeCurve);
|
||||
WIRE(IfcSubedge);
|
||||
WIRE(IfcOrientedEdge);
|
||||
WIRE(IfcEdge);
|
||||
WIRE(IfcEdgeLoop);
|
||||
WIRE(IfcPolyline);
|
||||
WIRE(IfcPolyLoop);
|
||||
WIRE(IfcCompositeCurve);
|
||||
WIRE(IfcTrimmedCurve);
|
||||
WIRE(IfcArbitraryOpenProfileDef);
|
||||
#ifdef SCHEMA_HAS_IfcIndexedPolyCurve
|
||||
WIRE(IfcIndexedPolyCurve);
|
||||
#endif
|
||||
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
|
||||
// IfcRationalBSplineCurveWithKnots included
|
||||
CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
#ifdef SCHEMA_HAS_IfcSurfaceCurve
|
||||
CURVE(IfcSurfaceCurve);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
CLASS(IfcAxis2Placement2D,gp_Trsf2d);
|
||||
CLASS(IfcAxis2Placement3D,gp_Trsf);
|
||||
CLASS(IfcAxis1Placement,gp_Ax1);
|
||||
CLASS(IfcCartesianTransformationOperator2DnonUniform,gp_GTrsf2d);
|
||||
CLASS(IfcCartesianTransformationOperator3DnonUniform,gp_GTrsf);
|
||||
CLASS(IfcCartesianTransformationOperator2D,gp_Trsf2d);
|
||||
CLASS(IfcCartesianTransformationOperator3D,gp_Trsf);
|
||||
CLASS(IfcObjectPlacement,gp_Trsf);
|
||||
CLASS(IfcVector,gp_Vec);
|
||||
CLASS(IfcPlane,gp_Pln);
|
||||
@@ -1,30 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedBrep
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) {
|
||||
return convert(l->Outer(), shape);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,36 +21,32 @@
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAnnotationFillArea* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire outer_boundary;
|
||||
if (!convert_wire(l->OuterBoundary(), outer_boundary)) {
|
||||
return false;
|
||||
}
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
util::assert_closed_wire(outer_boundary, getValue(GV_PRECISION));
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcAnnotationFillArea* inst) {
|
||||
auto loop = map(inst->OuterBoundary());
|
||||
if (loop) {
|
||||
auto face = new taxonomy::face;
|
||||
((taxonomy::loop*)loop)->external = true;
|
||||
face->children = { loop };
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(outer_boundary);
|
||||
|
||||
if (l->InnerBoundaries()) {
|
||||
IfcSchema::IfcCurve::list::ptr inner_boundaries = *l->InnerBoundaries();
|
||||
|
||||
for(IfcSchema::IfcCurve::list::it it = inner_boundaries->begin(); it != inner_boundaries->end(); ++it) {
|
||||
TopoDS_Wire hole;
|
||||
if (convert_wire(*it, hole)) {
|
||||
util::assert_closed_wire(hole, getValue(GV_PRECISION));
|
||||
mf.Add(hole);
|
||||
if (inst->InnerBoundaries()) {
|
||||
IfcSchema::IfcCurve::list::ptr inner_boundaries = *inst->InnerBoundaries();
|
||||
for (auto& v : *inner_boundaries) {
|
||||
auto inner_loop = map(v);
|
||||
if (inner_loop) {
|
||||
((taxonomy::loop*)inner_loop)->external = false;
|
||||
face->children.push_back(inner_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return face;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = sfs.Shape();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,24 +17,33 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire wire;
|
||||
if (!convert_wire(l->OuterCurve(), wire)) {
|
||||
return false;
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* inst) {
|
||||
auto loop = map(inst->OuterCurve());
|
||||
if (loop) {
|
||||
auto face = new taxonomy::face;
|
||||
((taxonomy::loop*)loop)->external = true;
|
||||
face->children = { loop };
|
||||
|
||||
if (inst->as<IfcSchema::IfcArbitraryProfileDefWithVoids>()) {
|
||||
auto with_voids = inst->as<IfcSchema::IfcArbitraryProfileDefWithVoids>();
|
||||
auto voids = with_voids->InnerCurves();
|
||||
for (auto& v : *voids) {
|
||||
auto inner_loop = map(v);
|
||||
if (inner_loop) {
|
||||
((taxonomy::loop*)inner_loop)->external = false;
|
||||
face->children.push_back(inner_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return face;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
util::assert_closed_wire(wire, getValue(GV_PRECISION));
|
||||
|
||||
TopoDS_Compound f;
|
||||
bool success = util::convert_wire_to_faces(wire, f, {getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., getValue(GV_PRECISION)});
|
||||
if (success) {
|
||||
face = f;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "mapping.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
|
||||
return convert_wire(l->Curve(), result);
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryOpenProfileDef* inst) {
|
||||
return map(inst->Curve());
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire profile;
|
||||
if (!convert_wire(l->OuterCurve(), profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
util::assert_closed_wire(profile, getValue(GV_PRECISION));
|
||||
|
||||
// @todo this is a discrepancy with IfcArbitraryClosedProfileDef without voids.
|
||||
// wire intersection code is not triggered this way.
|
||||
BRepBuilderAPI_MakeFace mf(profile);
|
||||
|
||||
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
|
||||
|
||||
for(IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++it) {
|
||||
TopoDS_Wire hole;
|
||||
if (convert_wire(*it, hole)) {
|
||||
util::assert_closed_wire(hole, getValue(GV_PRECISION));
|
||||
mf.Add(hole);
|
||||
}
|
||||
}
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = sfs.Shape();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -19,23 +19,31 @@
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) {
|
||||
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
|
||||
|
||||
if (!l->Location()->declaration().is("IfcCartesianPoint")) {
|
||||
// only applicable to 4x3 rc2
|
||||
Logger::Error("Not implemented", l->Location());
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis1Placement* inst) {
|
||||
Eigen::Vector3d P, axis(0, 0, 1), ref;
|
||||
{
|
||||
taxonomy::point3 v = as<taxonomy::point3>(map(inst->Location()));
|
||||
P = *v.components_;
|
||||
}
|
||||
const bool hasAxis = inst->Axis();
|
||||
if (hasAxis) {
|
||||
taxonomy::direction3 v = as<taxonomy::direction3>(map(inst->Axis()));
|
||||
axis = *v.components_;
|
||||
}
|
||||
|
||||
// @todo not sure what to do with ref, we're probably never reading it,
|
||||
// because we just created an Axis1 again from it in the kernel, but
|
||||
// to this constructor we need to supply something valid.
|
||||
if (std::abs(axis.x()) > std::abs(axis.z())) {
|
||||
ref = Eigen::Vector3d(0, 0, 1).cross(axis).normalized();
|
||||
} else {
|
||||
ref = Eigen::Vector3d(1, 0, 0).cross(axis).normalized();
|
||||
}
|
||||
|
||||
IfcGeom::Kernel::convert((const IfcSchema::IfcCartesianPoint*) l->Location(),o);
|
||||
if ( l->Axis() ) IfcGeom::Kernel::convert(l->Axis(), axis);
|
||||
ax = gp_Ax1(o, axis);
|
||||
CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
return new taxonomy::matrix4(P, axis, ref);
|
||||
}
|
||||
|
||||
@@ -23,32 +23,22 @@
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
|
||||
gp_Pnt P; gp_Dir V (1,0,0);
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
if (!l->Location()->declaration().is("IfcCartesianPoint")) {
|
||||
// only applicable to 4x3 rc2
|
||||
Logger::Error("Not implemented", l->Location());
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement2D* inst) {
|
||||
Eigen::Vector3d P, axis(0, 0, 1), V(1, 0, 0);
|
||||
{
|
||||
taxonomy::point3 v = as<taxonomy::point3>(map(inst->Location()));
|
||||
P = *v.components_;
|
||||
}
|
||||
|
||||
IfcGeom::Kernel::convert((const IfcSchema::IfcCartesianPoint*) l->Location(),P);
|
||||
if (l->RefDirection()) {
|
||||
IfcGeom::Kernel::convert(l->RefDirection(), V);
|
||||
const bool hasRef = !!inst->RefDirection();
|
||||
if (hasRef) {
|
||||
taxonomy::direction3 v = as<taxonomy::direction3>(map(inst->RefDirection()));
|
||||
V = *v.components_;
|
||||
}
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
|
||||
|
||||
if (!util::axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(axis, gp_Ax2d());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement2D,l,trsf)
|
||||
return true;
|
||||
return new taxonomy::matrix4(P, axis, V);
|
||||
}
|
||||
|
||||
@@ -22,55 +22,42 @@
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement3D, l, gp_Trsf, trsf)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
gp_Pnt o;
|
||||
gp_Dir axis(0, 0, 1);
|
||||
gp_Dir refDirection;
|
||||
|
||||
if (!l->Location()->declaration().is("IfcCartesianPoint")) {
|
||||
// only applicable to 4x3 rc2
|
||||
Logger::Error("Not implemented", l->Location());
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) {
|
||||
Eigen::Vector3d o, axis(0, 0, 1), refDirection, X(1, 0, 0);
|
||||
{
|
||||
taxonomy::point3 v = as<taxonomy::point3>(map(inst->Location()));
|
||||
o = *v.components_;
|
||||
}
|
||||
|
||||
IfcGeom::Kernel::convert((const IfcSchema::IfcCartesianPoint*) l->Location(), o);
|
||||
const bool hasAxis = !!l->Axis();
|
||||
const bool hasRef = !!l->RefDirection();
|
||||
const bool hasAxis = !!inst->Axis();
|
||||
const bool hasRef = !!inst->RefDirection();
|
||||
|
||||
if (hasAxis != hasRef) {
|
||||
Logger::Warning("Axis and RefDirection should be specified together", l);
|
||||
Logger::Warning("Axis and RefDirection should be specified together", inst);
|
||||
}
|
||||
|
||||
if (hasAxis) {
|
||||
IfcGeom::Kernel::convert(l->Axis(), axis);
|
||||
taxonomy::direction3 v = as<taxonomy::direction3>(map(inst->Axis()));
|
||||
axis = *v.components_;
|
||||
}
|
||||
|
||||
if (hasRef) {
|
||||
IfcGeom::Kernel::convert(l->RefDirection(), refDirection);
|
||||
taxonomy::direction3 v = as<taxonomy::direction3>(map(inst->RefDirection()));
|
||||
refDirection = *v.components_;
|
||||
} else {
|
||||
if (!axis.IsParallel(gp::DX(), 1.e-5)) {
|
||||
refDirection = gp::DX();
|
||||
if (acos(axis.dot(X)) > 1.e-5) {
|
||||
refDirection = { 1., 0., 0. };
|
||||
} else {
|
||||
refDirection = gp::DZ();
|
||||
refDirection = { 0., 0., 1. };
|
||||
}
|
||||
gp_Vec Xvec = axis.Dot(refDirection) * axis;
|
||||
gp_Vec Xaxis = refDirection.XYZ() - Xvec.XYZ();
|
||||
auto Xvec = axis.dot(refDirection) * axis;
|
||||
auto Xaxis = refDirection - Xvec;
|
||||
refDirection = Xaxis;
|
||||
}
|
||||
|
||||
gp_Ax3 ax3(o, axis, refDirection);
|
||||
|
||||
if (!util::axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3, gp::XOY());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
return new taxonomy::matrix4(o, axis, refDirection);
|
||||
}
|
||||
|
||||
@@ -17,67 +17,29 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "mapping.h"
|
||||
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
|
||||
|
||||
const bool is_rational = l->declaration().is(IfcSchema::IfcRationalBSplineCurveWithKnots::Class());
|
||||
|
||||
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
|
||||
const std::vector<int> mults = l->KnotMultiplicities();
|
||||
const std::vector<double> knots = l->Knots();
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Weights(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
|
||||
Standard_Integer Degree = l->Degree();
|
||||
Standard_Boolean Periodic = false;
|
||||
// @tfk: it appears to be wrong to expect a period curve when the curve is closed, see #586
|
||||
// Standard_Boolean Periodic = l->ClosedCurve();
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcBSplineCurveWithKnots* inst) {
|
||||
auto bc = new taxonomy::bspline_curve;
|
||||
|
||||
int i;
|
||||
const IfcSchema::IfcCartesianPoint::list::ptr cps = inst->ControlPointsList();
|
||||
std::vector<taxonomy::point3> points;
|
||||
std::transform(cps->begin(), cps->end(), std::back_inserter(points), [this](IfcSchema::IfcCartesianPoint* cp) { return as<taxonomy::point3>(map(cp)); });
|
||||
bc->control_points = points;
|
||||
|
||||
bc->multiplicities = inst->KnotMultiplicities();
|
||||
bc->knots = inst->Knots();
|
||||
if (inst->as<IfcSchema::IfcRationalBSplineCurveWithKnots>()) {
|
||||
bc->weights = inst->as<IfcSchema::IfcRationalBSplineCurveWithKnots>()->WeightsData();
|
||||
}
|
||||
bc->degree = inst->Degree();
|
||||
|
||||
if (is_rational) {
|
||||
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
|
||||
std::vector<double> weights = rl->WeightsData();
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
|
||||
Weights(i) = *it;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
|
||||
gp_Pnt pnt;
|
||||
if (!convert(*it, pnt)) return false;
|
||||
Poles(i) = pnt;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
|
||||
Mults(i) = *it;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
|
||||
Knots(i) = *it;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
|
||||
} else {
|
||||
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
|
||||
}
|
||||
return true;
|
||||
return bc;
|
||||
}
|
||||
#endif
|
||||
@@ -17,69 +17,32 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
|
||||
boost::shared_ptr< aggregate_of_aggregate_of<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
std::vector<double> uknots = l->UKnots();
|
||||
std::vector<double> vknots = l->VKnots();
|
||||
std::vector<int> umults = l->UMultiplicities();
|
||||
std::vector<int> vmults = l->VMultiplicities();
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcBSplineSurfaceWithKnots* inst) {
|
||||
auto bs = new taxonomy::bspline_surface;
|
||||
|
||||
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
|
||||
Standard_Integer UDegree = l->UDegree();
|
||||
Standard_Integer VDegree = l->VDegree();
|
||||
auto cps = inst->ControlPointsList();
|
||||
std::transform(cps->begin(), cps->end(), std::back_inserter(bs->control_points), [this](const std::vector<IfcSchema::IfcCartesianPoint*>& inner) {
|
||||
std::vector<taxonomy::point3> ps;
|
||||
std::transform(inner.begin(), inner.end(), std::back_inserter(ps), [this](IfcSchema::IfcCartesianPoint* cp) { return as<taxonomy::point3>(map(cp)); });
|
||||
return ps;
|
||||
});
|
||||
|
||||
int i = 0, j;
|
||||
for (aggregate_of_aggregate_of<IfcSchema::IfcCartesianPoint>::outer_it it = cps->begin(); it != cps->end(); ++it, ++i) {
|
||||
j = 0;
|
||||
for (aggregate_of_aggregate_of<IfcSchema::IfcCartesianPoint>::inner_it jt = (*it).begin(); jt != (*it).end(); ++jt, ++j) {
|
||||
IfcSchema::IfcCartesianPoint* p = *jt;
|
||||
gp_Pnt pnt;
|
||||
if (!convert(p, pnt)) return false;
|
||||
Poles(i, j) = pnt;
|
||||
}
|
||||
bs->multiplicities = { inst->UMultiplicities(), inst->VMultiplicities() };
|
||||
bs->knots = { inst->UKnots(), inst->VKnots() };
|
||||
if (inst->as<IfcSchema::IfcRationalBSplineSurfaceWithKnots>()) {
|
||||
bs->weights = inst->as<IfcSchema::IfcRationalBSplineSurfaceWithKnots>()->WeightsData();
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = uknots.begin(); it != uknots.end(); ++it, ++i) {
|
||||
UKnots(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = vknots.begin(); it != vknots.end(); ++it, ++i) {
|
||||
VKnots(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = umults.begin(); it != umults.end(); ++it, ++i) {
|
||||
UMults(i) = *it;
|
||||
}
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
|
||||
VMults(i) = *it;
|
||||
}
|
||||
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
bs->degree = { inst->UDegree(), inst->VDegree() };
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return bs;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,21 +19,18 @@
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) {
|
||||
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT);
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcBlock* inst) {
|
||||
const double dx = inst->XLength() * length_unit_;
|
||||
const double dy = inst->YLength() * length_unit_;
|
||||
const double dz = inst->ZLength() * length_unit_;
|
||||
|
||||
BRepPrimAPI_MakeBox builder(dx, dy, dz);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
auto solid = create_box(dx, dy, dz);
|
||||
solid->matrix = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
|
||||
// IfcCsgPrimitive3D.Position has unit scale factor
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
|
||||
return true;
|
||||
return solid;
|
||||
}
|
||||
|
||||
@@ -19,38 +19,37 @@
|
||||
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "../ifcgeom_schema_agnostic/boolean_utils.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
TopoDS_Shape s1;
|
||||
IfcRepresentationShapeItems items1;
|
||||
TopoDS_Wire boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
|
||||
namespace {
|
||||
taxonomy::boolean_result::operation_t boolean_op_type(IfcSchema::IfcBooleanOperator::Value op) {
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
return taxonomy::boolean_result::SUBTRACTION;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
|
||||
return taxonomy::boolean_result::INTERSECTION;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
|
||||
return taxonomy::boolean_result::UNION;
|
||||
} else {
|
||||
throw taxonomy::topology_error("Unknown boolean operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcBooleanResult* inst) {
|
||||
IfcSchema::IfcBooleanOperand* operand1 = inst->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = inst->SecondOperand();
|
||||
bool has_halfspace_operand = false;
|
||||
|
||||
BOPAlgo_Operation occ_op;
|
||||
std::vector<IfcSchema::IfcBooleanOperand*> operands;
|
||||
operands.push_back(operand2);
|
||||
|
||||
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
occ_op = BOPAlgo_CUT;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
|
||||
occ_op = BOPAlgo_COMMON;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
|
||||
occ_op = BOPAlgo_FUSE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
auto op = boolean_op_type(inst->Operator());
|
||||
|
||||
std::vector<IfcSchema::IfcBooleanOperand*> second_operands;
|
||||
second_operands.push_back(operand2);
|
||||
|
||||
if (occ_op == BOPAlgo_CUT) {
|
||||
if (op == taxonomy::boolean_result::SUBTRACTION) {
|
||||
int n_half_space_operands = 0;
|
||||
bool process_as_list = true;
|
||||
while (true) {
|
||||
@@ -59,13 +58,15 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
// There is something peculiar about many half space subtraction operands that OCCT does not like.
|
||||
// Often these are used to create a semi-curved arch, as is the case in 693. Supplying all these
|
||||
// operands at once apparently leads to too many edge-edge interference checks.
|
||||
|
||||
// @todo this should probably be moved to the opencascade kernel and not the mapping.
|
||||
process_as_list = false;
|
||||
break;
|
||||
}
|
||||
if (res1) {
|
||||
if (res1->Operator() == op) {
|
||||
if (boolean_op_type(res1->Operator()) == op) {
|
||||
operand1 = res1->FirstOperand();
|
||||
second_operands.push_back(res1->SecondOperand());
|
||||
operands.push_back(res1->SecondOperand());
|
||||
} else {
|
||||
process_as_list = false;
|
||||
break;
|
||||
@@ -76,163 +77,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
}
|
||||
|
||||
if (!process_as_list) {
|
||||
operand1 = l->FirstOperand();
|
||||
second_operands = { operand2 };
|
||||
operand1 = inst->FirstOperand();
|
||||
operands = { operand2 };
|
||||
}
|
||||
}
|
||||
|
||||
if ( shape_type(operand1) == ST_SHAPELIST ) {
|
||||
if (!(convert_shapes(operand1, items1) && util::flatten_shape_list(items1, s1, true, getValue(GV_PRECISION)))) {
|
||||
return false;
|
||||
}
|
||||
} else if ( shape_type(operand1) == ST_SHAPE ) {
|
||||
if ( ! convert_shape(operand1, s1) ) {
|
||||
return false;
|
||||
}
|
||||
{ TopoDS_Solid temp_solid;
|
||||
s1 = util::ensure_fit_for_subtraction(s1, temp_solid, getValue(GV_PRECISION)); }
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
|
||||
return false;
|
||||
operands.insert(operands.begin(), operand1);
|
||||
|
||||
auto br = map_to_collection<taxonomy::boolean_result>(this, &operands);
|
||||
if (br) {
|
||||
br->operation = op;
|
||||
}
|
||||
|
||||
if (getValue(GV_DISABLE_BOOLEAN_RESULT) > 0.0) {
|
||||
shape = s1;
|
||||
return true;
|
||||
}
|
||||
|
||||
const double first_operand_volume = util::shape_volume(s1);
|
||||
if (first_operand_volume <= ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
|
||||
}
|
||||
|
||||
TopTools_ListOfShape second_operand_shapes;
|
||||
|
||||
for (auto& op2 : second_operands) {
|
||||
TopoDS_Shape s2;
|
||||
|
||||
bool shape2_processed = false;
|
||||
|
||||
bool is_halfspace = op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class());
|
||||
bool is_unbounded_halfspace = is_halfspace && !op2->declaration().is(IfcSchema::IfcPolygonalBoundedHalfSpace::Class());
|
||||
has_halfspace_operand |= is_halfspace;
|
||||
|
||||
{
|
||||
if (shape_type(op2) == ST_SHAPELIST) {
|
||||
IfcRepresentationShapeItems items2;
|
||||
shape2_processed = convert_shapes(op2, items2) && util::flatten_shape_list(items2, s2, true, getValue(GV_PRECISION));
|
||||
} else if (shape_type(op2) == ST_SHAPE) {
|
||||
shape2_processed = convert_shape(op2, s2);
|
||||
if (shape2_processed) {
|
||||
TopoDS_Solid temp_solid;
|
||||
s2 = util::ensure_fit_for_subtraction(s2, temp_solid, getValue(GV_PRECISION));
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", op2);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_unbounded_halfspace) {
|
||||
TopoDS_Shape temp;
|
||||
double d;
|
||||
if (util::fit_halfspace(s1, s2, temp, d, getValue(GV_PRECISION))) {
|
||||
if (d < getValue(GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", l);
|
||||
continue;
|
||||
} else {
|
||||
s2 = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shape2_processed) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand:", op2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class())) {
|
||||
const double second_operand_volume = util::shape_volume(s2);
|
||||
if (second_operand_volume <= ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", op2);
|
||||
}
|
||||
}
|
||||
|
||||
second_operand_shapes.Append(s2);
|
||||
}
|
||||
|
||||
/*
|
||||
// TK: A little debugging trick to output both operands for visual inspection
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
builder.Add(compound, s1);
|
||||
for (const auto& s2 : second_operand_shapes) {
|
||||
builder.Add(compound, s2);
|
||||
}
|
||||
shape = compound;
|
||||
return true;
|
||||
*/
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
// @todo: this currently does not compile anymore, do we still need this?
|
||||
bool valid_result = boolean_operation(s1, s2, occ_op, shape);
|
||||
#else
|
||||
|
||||
bool valid_result;
|
||||
|
||||
util::boolean_settings bst;
|
||||
bst.attempt_2d = getValue(GV_BOOLEAN_ATTEMPT_2D) > 0.;
|
||||
bst.debug = getValue(GV_DEBUG_BOOLEAN) > 0.;
|
||||
bst.precision = getValue(GV_PRECISION);
|
||||
|
||||
if (s1.ShapeType() == TopAbs_COMPOUND && TopoDS_Iterator(s1).More() && util::is_nested_compound_of_solid(s1)) {
|
||||
TopoDS_Compound C;
|
||||
BRep_Builder B;
|
||||
B.MakeCompound(C);
|
||||
TopoDS_Iterator it(s1);
|
||||
valid_result = true;
|
||||
for (; it.More(); it.Next()) {
|
||||
TopoDS_Shape part;
|
||||
if (util::boolean_operation(bst, it.Value(), second_operand_shapes, occ_op, part)) {
|
||||
B.Add(C, part);
|
||||
} else {
|
||||
valid_result = false;
|
||||
}
|
||||
}
|
||||
shape = C;
|
||||
} else {
|
||||
valid_result = util::boolean_operation(bst, s1, second_operand_shapes, occ_op, shape);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
// In case of a subtraction, a check on volume is performed.
|
||||
if (valid_result) {
|
||||
const double volume_after_subtraction = util::shape_volume(shape);
|
||||
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
|
||||
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l);
|
||||
shape = s1;
|
||||
}
|
||||
// NB: After issuing error the first operand is returned!
|
||||
return true;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION && !valid_result) {
|
||||
BRep_Builder B;
|
||||
TopoDS_Compound C;
|
||||
B.MakeCompound(C);
|
||||
B.Add(C, s1);
|
||||
TopTools_ListIteratorOfListOfShape it(second_operand_shapes);
|
||||
for (; it.More(); it.Next()) {
|
||||
B.Add(C, it.Value());
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process union, creating compound:", l);
|
||||
shape = C;
|
||||
return true;
|
||||
} else {
|
||||
return valid_result;
|
||||
}
|
||||
return false;
|
||||
return br;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBoundingBox* l, TopoDS_Shape& shape) {
|
||||
const double dx = l->XDim() * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->YDim() * getValue(GV_LENGTH_UNIT);
|
||||
const double dz = l->ZDim() * getValue(GV_LENGTH_UNIT);
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcBoundingBox* inst) {
|
||||
const double dx = inst->XDim() * length_unit_;
|
||||
const double dy = inst->YDim() * length_unit_;
|
||||
const double dz = inst->ZDim() * length_unit_;
|
||||
|
||||
gp_Pnt corner;
|
||||
IfcGeom::Kernel::convert(l->Corner(), corner);
|
||||
BRepPrimAPI_MakeBox builder(corner, dx, dy, dz);
|
||||
taxonomy::point3 corner = as<taxonomy::point3>(map(inst->Corner()));
|
||||
auto solid = create_box(corner.ccomponents().x(), corner.ccomponents().y(), corner.ccomponents().z(), dx, dy, dz);
|
||||
|
||||
shape = builder.Solid();
|
||||
|
||||
return true;
|
||||
return solid;
|
||||
}
|
||||
|
||||
@@ -17,41 +17,58 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/profile_helper.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "../profile_helper.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
|
||||
bool doFillet = !!l->InternalFilletRadius();
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCShapeProfileDef* inst) {
|
||||
const double y = inst->Depth() / 2.0f * length_unit_;
|
||||
const double x = inst->Width() / 2.0f * length_unit_;
|
||||
const double d1 = inst->WallThickness() * length_unit_;
|
||||
const double d2 = inst->Girth() * length_unit_;
|
||||
bool doFillet = !!inst->InternalFilletRadius();
|
||||
double f1 = 0;
|
||||
double f2 = 0;
|
||||
if ( doFillet ) {
|
||||
f1 = *l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
f1 = *inst->InternalFilletRadius() * length_unit_;
|
||||
f2 = f1 + d1;
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
|
||||
|
||||
if ( x < tol || y < tol || d1 < tol || d2 < tol) {
|
||||
Logger::Message(Logger::LOG_NOTICE," Skipping zero sized profile:", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
Eigen::Matrix4d m4;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
has_position = !!inst->Position();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
m4 = m.ccomponents();
|
||||
}
|
||||
|
||||
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
|
||||
int fillets[8] = {0,1,4,5,6,7,10,11};
|
||||
double radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
|
||||
return util::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
|
||||
return profile_helper(m4, {
|
||||
{{-x,-y},{f2}},
|
||||
{{x,-y},{f2}},
|
||||
{{x,-y + d2}},
|
||||
{{x - d1,-y + d2}},
|
||||
{{x - d1,-y + d1},{f1}},
|
||||
{{-x + d1,-y + d1},{f1}},
|
||||
{{-x + d1,y - d1},{f1}},
|
||||
{{x - d1,y - d1},{f1}},
|
||||
{{x - d1,y - d2}},
|
||||
{{x,y - d2}},
|
||||
{{x,y},{f2}},
|
||||
{{-x,y},{f2}}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,19 +17,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
|
||||
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
point = gp_Pnt(
|
||||
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
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianPoint* inst) {
|
||||
std::vector<double> xyz = inst->Coordinates();
|
||||
return new taxonomy::point3(
|
||||
xyz.size() >= 1 ? xyz[0] * length_unit_ : 0.,
|
||||
xyz.size() >= 2 ? xyz[1] * length_unit_ : 0.,
|
||||
xyz.size() >= 3 ? xyz[2] * length_unit_ : 0.
|
||||
);
|
||||
CACHE(IfcCartesianPoint,l,point)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,54 +17,45 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2D* inst) {
|
||||
auto m = new taxonomy::matrix4;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf)
|
||||
Eigen::Vector4d origin, axis1(1.0, 0.0, 0.0, 0.0), axis2(0.0, 1.0, 0.0, 0.0), axis3(0.0, 0.0, 1.0, 0.0);
|
||||
|
||||
gp_Pnt origin;
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
taxonomy::point3 O = as<taxonomy::point3>(map(inst->LocalOrigin()));
|
||||
origin << *O.components_, 1.0;
|
||||
|
||||
// A better match to represent the IfcCartesianTransformationOperator2D would
|
||||
// be the gp_Ax22d, but to my knowledge no easy way exists to convert it into
|
||||
// a gp_Trsf2d. Easiest would probably be to simply update the underlying
|
||||
// gp_Mat2d directly.
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
if (inst->Axis1()) {
|
||||
taxonomy::direction3 ax1 = as<taxonomy::direction3>(map(inst->Axis1()));
|
||||
axis1 << *ax1.components_, 0.0;
|
||||
}
|
||||
if (inst->Axis2()) {
|
||||
taxonomy::direction3 ax2 = as<taxonomy::direction3>(map(inst->Axis1()));
|
||||
axis2 << *ax2.components_, 0.0;
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
if (l->Scale() && !ALMOST_THE_SAME(*l->Scale(), 1.)) {
|
||||
trsf.SetScaleFactor(*l->Scale());
|
||||
double scale1, scale2;
|
||||
scale1 = scale2 = 1.0;
|
||||
|
||||
if (inst->Scale()) {
|
||||
scale1 = *inst->Scale();
|
||||
}
|
||||
if (inst->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) {
|
||||
auto nu = inst->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>();
|
||||
scale2 = nu->Scale2() ? *nu->Scale2() : scale1;
|
||||
}
|
||||
|
||||
if (util::is_identity(trsf, getValue(GV_PRECISION))) {
|
||||
trsf = gp_Trsf2d();
|
||||
}
|
||||
m->components() <<
|
||||
axis1 * scale1,
|
||||
axis2 * scale2,
|
||||
axis3,
|
||||
origin;
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
m->components().transposeInPlace();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf)
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
gp_Pnt origin;
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
|
||||
const double scale1 = l->Scale().get_value_or(1.);
|
||||
const double scale2 = l->Scale2().get_value_or(scale1);
|
||||
gtrsf = gp_GTrsf2d();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.Multiply(trsf);
|
||||
|
||||
if (util::is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
@@ -21,33 +21,72 @@
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt origin;
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
if ( l->Axis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
|
||||
if (!util::axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3D* inst) {
|
||||
|
||||
Eigen::Vector4d origin;
|
||||
Eigen::Vector4d axis1(1., 0., 0., 0.);
|
||||
Eigen::Vector4d axis2(0., 1., 0., 0.);
|
||||
Eigen::Vector4d axis3(0., 0., 1., 0.);
|
||||
|
||||
taxonomy::point3 O = as<taxonomy::point3>(map(inst->LocalOrigin()));
|
||||
origin << *O.components_, 1.0;
|
||||
|
||||
if (inst->Axis1()) {
|
||||
taxonomy::direction3 ax1 = as<taxonomy::direction3>(map(inst->Axis1()));
|
||||
axis1 << *ax1.components_, 0.0;
|
||||
}
|
||||
|
||||
if (l->Scale() && !ALMOST_THE_SAME(*l->Scale(), 1.)) {
|
||||
trsf.SetScaleFactor(*l->Scale());
|
||||
if (inst->Axis2()) {
|
||||
taxonomy::direction3 ax2 = as<taxonomy::direction3>(map(inst->Axis2()));
|
||||
axis2 << *ax2.components_, 0.0;
|
||||
}
|
||||
if (inst->Axis3()) {
|
||||
taxonomy::direction3 ax3 = as<taxonomy::direction3>(map(inst->Axis3()));
|
||||
axis3 << *ax3.components_, 0.0;
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
auto m4 = new taxonomy::matrix4(origin.head<3>(), axis3.head<3>(), axis1.head<3>());
|
||||
if (m4->ccomponents().col(1).dot(axis2) < 0.) {
|
||||
m4->components().col(1) *= -1.;
|
||||
}
|
||||
|
||||
double scale1, scale2, scale3;
|
||||
scale1 = scale2 = scale3 = 1.;
|
||||
|
||||
if (inst->Scale()) {
|
||||
scale1 = *inst->Scale();
|
||||
}
|
||||
if (inst->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) {
|
||||
auto nu = inst->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>();
|
||||
scale2 = nu->Scale2() ? *nu->Scale2() : scale1;
|
||||
scale3 = nu->Scale3() ? *nu->Scale3() : scale1;
|
||||
}
|
||||
|
||||
if (scale1 != 1.) {
|
||||
m4->components().col(0) *= scale1;
|
||||
}
|
||||
if (scale2 != 1.) {
|
||||
m4->components().col(1) *= scale2;
|
||||
}
|
||||
if (scale3 != 1.) {
|
||||
m4->components().col(2) *= scale3;
|
||||
}
|
||||
|
||||
return m4;
|
||||
|
||||
/*
|
||||
auto m = new taxonomy::matrix4;
|
||||
|
||||
// @todo is this necessary?
|
||||
m->components() = m->components().inverse();
|
||||
m->components().transposeInPlace();
|
||||
|
||||
// @todo tag identity?
|
||||
|
||||
return m;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
|
||||
gp_Trsf trsf;
|
||||
gp_Pnt origin;
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
if ( l->Axis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
const double scale1 = l->Scale().get_value_or(1.);
|
||||
const double scale2 = l->Scale2().get_value_or(scale1);
|
||||
const double scale3 = l->Scale3().get_value_or(scale1);
|
||||
gtrsf = gp_GTrsf();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.SetValue(3,3,scale3);
|
||||
gtrsf.PreMultiply(trsf);
|
||||
|
||||
if (util::is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
@@ -17,28 +17,24 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <Geom_OffsetCurve.hxx>
|
||||
#include <BRepOffsetAPI_MakeOffset.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCenterLineProfileDef* inst) {
|
||||
const double d = inst->Thickness() * length_unit_ / 2.;
|
||||
auto f = new taxonomy::face;
|
||||
auto ofc = new taxonomy::offset_curve;
|
||||
ofc->basis = map(inst->Curve());
|
||||
ofc->offset = d;
|
||||
f->children.push_back(ofc);
|
||||
return f;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) {
|
||||
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.;
|
||||
// @todo we still need to handle this in the l
|
||||
|
||||
/*
|
||||
TopoDS_Wire wire;
|
||||
if (!convert_wire(l->Curve(), wire)) return false;
|
||||
if (!convert_wire(inst->Curve(), wire)) return false;
|
||||
|
||||
// BRepOffsetAPI_MakeOffset insists on creating circular arc
|
||||
// segments for joining the curves that constitute the center
|
||||
@@ -81,4 +77,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoD
|
||||
face = BRepBuilderAPI_MakeFace(TopoDS::Wire(offset));
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -17,29 +17,22 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define ALMOST_ZERO 1.e-7;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircle* inst) {
|
||||
const double r = inst->Radius() * length_unit_;
|
||||
if (r < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst);
|
||||
return nullptr;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
|
||||
IfcGeom::Kernel::convert(placement->as<IfcSchema::IfcAxis2Placement3D>(),trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(placement->as<IfcSchema::IfcAxis2Placement2D>(),trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
curve = new Geom_Circle(ax, r);
|
||||
return true;
|
||||
|
||||
IfcSchema::IfcAxis2Placement* placement = inst->Position();
|
||||
auto c = new taxonomy::circle;
|
||||
c->radius = r;
|
||||
c->matrix = as<taxonomy::matrix4>(map(placement));
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( r == 0.0f || t == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
}
|
||||
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
|
||||
|
||||
BRepBuilderAPI_MakeWire outer;
|
||||
Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r);
|
||||
outer.Add(BRepBuilderAPI_MakeEdge(outerCircle));
|
||||
BRepBuilderAPI_MakeFace mf(outer.Wire(), false);
|
||||
|
||||
BRepBuilderAPI_MakeWire inner;
|
||||
Handle(Geom_Circle) innerCirlce = new Geom_Circle(ax, r-t);
|
||||
inner.Add(BRepBuilderAPI_MakeEdge(innerCirlce));
|
||||
mf.Add(inner);
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = TopoDS::Face(sfs.Shape());
|
||||
return true;
|
||||
}
|
||||
@@ -17,43 +17,51 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircleProfileDef* inst) {
|
||||
std::vector<double> radii = { inst->Radius() * length_unit_ };
|
||||
|
||||
if (inst->as<IfcSchema::IfcCircleHollowProfileDef>()) {
|
||||
double t = inst->as<IfcSchema::IfcCircleHollowProfileDef>()->WallThickness() * length_unit_;
|
||||
radii.push_back(radii.front() - t);
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
bool has_position = true;
|
||||
|
||||
auto f = new taxonomy::face;
|
||||
|
||||
for (auto it = radii.begin(); it != radii.end(); ++it) {
|
||||
const double r = *it;
|
||||
const bool exterior = it == radii.begin();
|
||||
|
||||
auto c = new taxonomy::circle;
|
||||
c->radius = r;
|
||||
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
has_position = !!inst->Position();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
if (has_position) {
|
||||
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
if (m.components_) {
|
||||
c->matrix = *m.components_;
|
||||
}
|
||||
}
|
||||
|
||||
auto e = new taxonomy::edge;
|
||||
e->basis = c;
|
||||
e->start = 0.;
|
||||
e->end = 2 * boost::math::constants::pi<double>();
|
||||
|
||||
auto l = new taxonomy::loop;
|
||||
l->children = { e };
|
||||
l->external = exterior;
|
||||
|
||||
f->children.push_back(l);
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
|
||||
|
||||
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = util::convert_wire_to_face(w, f, {false, false, 0., 0.});
|
||||
if (success) face = f;
|
||||
return success;
|
||||
return f;
|
||||
}
|
||||
|
||||
@@ -17,101 +17,84 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
|
||||
auto loop = new taxonomy::loop;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcSegment
|
||||
// 4x3
|
||||
IfcSchema::IfcSegment::list::ptr segments = inst->Segments();
|
||||
#else
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = inst->Segments();
|
||||
#endif
|
||||
|
||||
for (auto& segment : *segments) {
|
||||
if (!(segment)->declaration().is(IfcSchema::IfcCompositeCurveSegment::Class())) {
|
||||
Logger::Error("Not implemented", segment);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IfcSchema::IfcCurve* curve = ((IfcSchema::IfcCompositeCurveSegment*)(segment))->ParentCurve();
|
||||
|
||||
if (curve->as<IfcSchema::IfcLine>()) {
|
||||
Logger::Notice("Infinite IfcLine used as ParentCurve of segment, treating as a segment", segment);
|
||||
double u0 = 0.0;
|
||||
double u1 = curve->as<IfcSchema::IfcLine>()->Dir()->Magnitude() * length_unit_;
|
||||
if (u1 < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) {
|
||||
Logger::Warning("Segment length below tolerance", segment);
|
||||
}
|
||||
|
||||
auto e = new taxonomy::edge;
|
||||
e->basis = map(curve);
|
||||
e->start = u0;
|
||||
e->end = u1;
|
||||
e->orientation_2.reset(segment->SameSense());
|
||||
|
||||
loop->children.push_back(e);
|
||||
} else {
|
||||
auto crv = map(segment->ParentCurve());
|
||||
if (crv) {
|
||||
if (crv->kind() == taxonomy::EDGE) {
|
||||
((taxonomy::edge*)crv)->orientation_2.reset(segment->SameSense());
|
||||
loop->children.push_back(crv);
|
||||
} else if (crv->kind() == taxonomy::LOOP) {
|
||||
if (!segment->SameSense()) {
|
||||
crv->reverse();
|
||||
}
|
||||
auto curve_segments = ((taxonomy::loop*)crv)->children_as<taxonomy::edge>();
|
||||
for (auto& s : curve_segments) {
|
||||
loop->children.push_back(s);
|
||||
}
|
||||
// @todo delete crv without children
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
|
||||
const bool force_close = profile && profile->size() > 0;
|
||||
loop->closed = force_close;
|
||||
return loop;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "mapping.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_builder.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l);
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
bool use_radians = false;
|
||||
bool use_degrees = false;
|
||||
|
||||
// First try radians
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Notice(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Notice(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Notice("Unknown error using radians");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Notice("Unknown error using radians");
|
||||
}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Notice(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Notice(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Notice("Unknown error using degrees");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Notice("Unknown error using degrees");
|
||||
}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
} else if ( succes_radians && ! succes_degrees ) {
|
||||
use_radians = true;
|
||||
} else if ( succes_radians && succes_degrees ) {
|
||||
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
|
||||
use_degrees = true;
|
||||
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
|
||||
use_radians = true;
|
||||
} else {
|
||||
// No heuristic left to prefer the one over the other,
|
||||
// apparently both variants are equally successful.
|
||||
// The curve might be composed of only straight segments.
|
||||
// Let's go with the wire created using radians as that
|
||||
// at least is a SI unit.
|
||||
use_radians = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( use_radians ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
|
||||
wire = wire_radians;
|
||||
} else if ( use_degrees ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
|
||||
wire = wire_degrees;
|
||||
}
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcSegment
|
||||
// 4x3
|
||||
IfcSchema::IfcSegment::list::ptr segments = l->Segments();
|
||||
#else
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
#endif
|
||||
|
||||
TopTools_ListOfShape converted_segments;
|
||||
|
||||
@@ -135,7 +118,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
Handle_Geom_Curve handle;
|
||||
convert_curve(curve, handle);
|
||||
double u0 = 0.0;
|
||||
double u1 = curve->as<IfcSchema::IfcLine>()->Dir()->Magnitude() * getValue(GV_LENGTH_UNIT);
|
||||
double u1 = curve->as<IfcSchema::IfcLine>()->Dir()->Magnitude() * length_unit_;
|
||||
if (u1 < getValue(GV_PRECISION)) {
|
||||
Logger::Warning("Segment length below tolerance", *it);
|
||||
}
|
||||
@@ -172,7 +155,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(converted_segments);
|
||||
|
||||
aggregate_of_instance::ptr profile = l->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
|
||||
aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
|
||||
const bool force_close = profile && profile->size() > 0;
|
||||
|
||||
util::wire_builder bld(getValue(GV_PRECISION), l);
|
||||
@@ -181,3 +164,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -17,37 +17,12 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) {
|
||||
// BRepBuilderAPI_MakeFace mf;
|
||||
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
|
||||
//bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
TopoDS_Face f;
|
||||
if (convert_face(*it, f)) {
|
||||
builder.Add(compound, f);
|
||||
/* TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Wire& wire = TopoDS::Wire(exp.Current());
|
||||
if (first) {
|
||||
mf.Init(BRepBuilderAPI_MakeFace(wire));
|
||||
} else {
|
||||
mf.Add(wire);
|
||||
}
|
||||
first = false;
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
face = compound;
|
||||
return !face.IsNull();
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeProfileDef* inst) {
|
||||
// @todo double check that this is actually supported
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles = inst->Profiles();
|
||||
return map_to_collection<>(this, profiles);
|
||||
}
|
||||
|
||||
@@ -17,101 +17,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/base_utils.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <memory>
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
|
||||
std::unique_ptr<faceset_helper<>> helper_scope;
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = IfcParse::traverse((IfcUtil::IfcBaseClass*) l)->as<IfcSchema::IfcCartesianPoint>();
|
||||
std::vector<const IfcSchema::IfcCartesianPoint*> points_(points->begin(), points->end());
|
||||
|
||||
IfcSchema::IfcPolyLoop::list::ptr loops = IfcParse::traverse((IfcUtil::IfcBaseClass*)l)->as<IfcSchema::IfcPolyLoop>();
|
||||
std::vector<const IfcSchema::IfcPolyLoop*> loops_(loops->begin(), loops->end());
|
||||
|
||||
helper_scope.reset(new faceset_helper<>(
|
||||
this,
|
||||
points_,
|
||||
loops_,
|
||||
l->declaration().is(IfcSchema::IfcClosedShell::Class())
|
||||
));
|
||||
|
||||
faceset_helper_ = helper_scope.get();
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
|
||||
|
||||
double min_face_area = faceset_helper_
|
||||
? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.)
|
||||
: getValue(GV_MINIMAL_FACE_AREA);
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
|
||||
bool success = false;
|
||||
TopoDS_Face face;
|
||||
|
||||
try {
|
||||
success = convert_face(*it, face);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error creating face");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating face");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (face.ShapeType() == TopAbs_COMPOUND) {
|
||||
TopoDS_Iterator face_it(face, false);
|
||||
for (; face_it.More(); face_it.Next()) {
|
||||
if (face_it.Value().ShapeType() == TopAbs_FACE) {
|
||||
// This should really be the case. This is not asserted.
|
||||
const TopoDS_Face& triangle = TopoDS::Face(face_it.Value());
|
||||
if (util::face_area(triangle) > min_face_area) {
|
||||
face_list.Append(triangle);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (util::face_area(face) > min_face_area) {
|
||||
face_list.Append(face);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it));
|
||||
}
|
||||
}
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) {
|
||||
auto shell = map_to_collection<taxonomy::shell>(this, inst->CfsFaces());
|
||||
if (shell == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (face_list.Extent() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !util::create_solid_from_faces(face_list, shape, getValue(GV_PRECISION))) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
TopTools_ListIteratorOfListOfShape face_iterator;
|
||||
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
|
||||
builder.Add(compound, face_iterator.Value());
|
||||
}
|
||||
shape = compound;
|
||||
}
|
||||
|
||||
return true;
|
||||
shell->closed = inst->declaration().is(IfcSchema::IfcClosedShell::Class());
|
||||
return shell;
|
||||
}
|
||||
|
||||
@@ -17,50 +17,51 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/profile_helper.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "../profile_helper.h"
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcCraneRailAShapeProfileDef
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCraneRailAShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
double oh = l->OverallHeight() * getValue(GV_LENGTH_UNIT);
|
||||
double bw2 = l->BaseWidth2() * getValue(GV_LENGTH_UNIT);
|
||||
double hw = l->HeadWidth() * getValue(GV_LENGTH_UNIT);
|
||||
double hd2 = l->HeadDepth2() * getValue(GV_LENGTH_UNIT);
|
||||
double hd3 = l->HeadDepth3() * getValue(GV_LENGTH_UNIT);
|
||||
double wt = l->WebThickness() * getValue(GV_LENGTH_UNIT);
|
||||
double bw4 = l->BaseWidth4() * getValue(GV_LENGTH_UNIT);
|
||||
double bd1 = l->BaseDepth1() * getValue(GV_LENGTH_UNIT);
|
||||
double bd2 = l->BaseDepth2() * getValue(GV_LENGTH_UNIT);
|
||||
double bd3 = l->BaseDepth3() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCraneRailAShapeProfileDef* inst) {
|
||||
double oh = inst->OverallHeight() * length_unit_;
|
||||
double bw2 = inst->BaseWidth2() * length_unit_;
|
||||
double hw = inst->HeadWidth() * length_unit_;
|
||||
double hd2 = inst->HeadDepth2() * length_unit_;
|
||||
double hd3 = inst->HeadDepth3() * length_unit_;
|
||||
double wt = inst->WebThickness() * length_unit_;
|
||||
double bw4 = inst->BaseWidth4() * length_unit_;
|
||||
double bd1 = inst->BaseDepth1() * length_unit_;
|
||||
double bd2 = inst->BaseDepth2() * length_unit_;
|
||||
double bd3 = inst->BaseDepth3() * length_unit_;
|
||||
|
||||
Eigen::Matrix4d m4;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
has_position = !!inst->Position();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
m4 = m.ccomponents();
|
||||
}
|
||||
|
||||
double coords[28] = {
|
||||
-hw / 2., +oh / 2.,
|
||||
-hw / 2., +oh / 2. - hd3,
|
||||
-wt / 2., +oh / 2. - hd2,
|
||||
-wt / 2., -oh / 2. + bd2,
|
||||
-bw4 / 2., -oh / 2. + bd3,
|
||||
-bw2 / 2., -oh / 2. + bd1,
|
||||
-bw2 / 2., -oh / 2.,
|
||||
+bw2 / 2., -oh / 2.,
|
||||
+bw2 / 2., -oh / 2. + bd1,
|
||||
+bw4 / 2., -oh / 2. + bd3,
|
||||
+wt / 2., -oh / 2. + bd2,
|
||||
+wt / 2., +oh / 2. - hd2,
|
||||
+hw / 2., +oh / 2. - hd3,
|
||||
+hw / 2., +oh / 2.
|
||||
};
|
||||
|
||||
return util::profile_helper(14, coords, 0, 0, 0, trsf2d, face);
|
||||
return profile_helper(m4, {
|
||||
{{-hw / 2., +oh / 2.}},
|
||||
{{-hw / 2., +oh / 2. - hd3}},
|
||||
{{-wt / 2., +oh / 2. - hd2}},
|
||||
{{-wt / 2., -oh / 2. + bd2}},
|
||||
{{-bw4 / 2., -oh / 2. + bd3}},
|
||||
{{-bw2 / 2., -oh / 2. + bd1}},
|
||||
{{-bw2 / 2., -oh / 2.}},
|
||||
{{+bw2 / 2., -oh / 2.}},
|
||||
{{+bw2 / 2., -oh / 2. + bd1}},
|
||||
{{+bw4 / 2., -oh / 2. + bd3}},
|
||||
{{+wt / 2., -oh / 2. + bd2}},
|
||||
{{+wt / 2., +oh / 2. - hd2}},
|
||||
{{+hw / 2., +oh / 2. - hd3}},
|
||||
{{+hw / 2., +oh / 2.}}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
|
||||
return convert_shape(l->TreeRootExpression(), shape);
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCsgSolid* inst) {
|
||||
return map(inst->TreeRootExpression());
|
||||
}
|
||||
|
||||
@@ -17,53 +17,21 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
|
||||
gp_Pln pln;
|
||||
if (!IfcGeom::Kernel::convert(l->BasisSurface(), pln)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf trsf;
|
||||
trsf.SetTransformation(pln.Position(), gp::XOY());
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCurveBoundedPlane* inst) {
|
||||
taxonomy::plane pl = as<taxonomy::plane>(map(inst->BasisSurface()));
|
||||
auto f = new taxonomy::face;
|
||||
f->children.push_back(map(inst->OuterBoundary()));
|
||||
|
||||
TopoDS_Wire outer;
|
||||
if (!convert_wire(l->OuterBoundary(), outer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(outer);
|
||||
|
||||
if (!mf.IsDone() || mf.Shape().IsNull()) {
|
||||
Logger::Error("Invalid outer boundary:", l->OuterBoundary());
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
|
||||
IfcSchema::IfcCurve::list::ptr boundaries = inst->InnerBoundaries();
|
||||
|
||||
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
|
||||
TopoDS_Wire inner;
|
||||
if (convert_wire(*it, inner)) {
|
||||
mf.Add(inner);
|
||||
}
|
||||
f->children.push_back(map(*it));
|
||||
}
|
||||
f->matrix = pl.matrix;
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
|
||||
// `trsf` consitutes the placement of the plane and therefore has unit scale factor
|
||||
face = TopoDS::Face(sfs.Shape()).Moved(trsf);
|
||||
|
||||
return true;
|
||||
return f;
|
||||
}
|
||||
|
||||
@@ -17,23 +17,17 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcCylindricalSurface
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
// IfcElementarySurface.Position has unit scale factor
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT)), getValue(GV_PRECISION)).Face().Moved(trsf);
|
||||
return true;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcCylindricalSurface* inst) {
|
||||
auto c = new taxonomy::cylinder;
|
||||
c->radius = inst->Radius() * length_unit_;
|
||||
c->matrix = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,22 +17,13 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Face f;
|
||||
gp_Trsf2d trsf2d;
|
||||
if (convert_face(l->ParentProfile(), f) && IfcGeom::Kernel::convert(l->Operator(), trsf2d)) {
|
||||
gp_Trsf trsf = trsf2d;
|
||||
face = BRepBuilderAPI_Transform(f, trsf).Shape();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcDerivedProfileDef* inst) {
|
||||
auto it = map(inst->ParentProfile());
|
||||
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Operator()));
|
||||
((taxonomy::geom_item*)it)->matrix.components() *= m.ccomponents();
|
||||
return it;
|
||||
}
|
||||
|
||||
@@ -17,19 +17,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Dir.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
|
||||
IN_CACHE(IfcDirection,l,gp_Dir,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = gp_Dir(
|
||||
xyz.size() ? xyz[0] : 0.0f,
|
||||
xyz.size() > 1 ? xyz[1] : 0.0f,
|
||||
xyz.size() > 2 ? xyz[2] : 0.0f
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcDirection* inst) {
|
||||
auto coords = inst->DirectionRatios();
|
||||
return new taxonomy::direction3(
|
||||
coords.size() >= 1 ? coords[0] : 0.,
|
||||
coords.size() >= 2 ? coords[1] : 0.,
|
||||
coords.size() >= 3 ? coords[2] : 0.
|
||||
);
|
||||
CACHE(IfcDirection,l,dir)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -17,38 +17,32 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
|
||||
if (!l->EdgeStart()->declaration().is(IfcSchema::IfcVertexPoint::Class()) || !l->EdgeEnd()->declaration().is(IfcSchema::IfcVertexPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcEdge* inst) {
|
||||
if (!inst->EdgeStart()->declaration().is(IfcSchema::IfcVertexPoint::Class()) || !inst->EdgeEnd()->declaration().is(IfcSchema::IfcVertexPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) inst->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) inst->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
auto e = new taxonomy::edge;
|
||||
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
e->start = as<taxonomy::point3>(map(pnt1));
|
||||
e->end = as<taxonomy::point3>(map(pnt2));
|
||||
|
||||
if (inst->as<IfcSchema::IfcEdgeCurve>()) {
|
||||
e->basis = map(inst->as<IfcSchema::IfcEdgeCurve>()->EdgeGeometry());
|
||||
e->orientation = inst->as<IfcSchema::IfcEdgeCurve>()->SameSense();
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/wire_builder.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
Handle_Geom_Curve crv;
|
||||
|
||||
// The lack of a clear separation between topological and geometrical entities
|
||||
// is starting to get problematic. If the underlying curve is bounded it is
|
||||
// assumed that a topological wire can be crafted from it. After which an
|
||||
// attempt is made to reconstruct it from the individual curves and the vertices
|
||||
// of the IfcEdgeCurve.
|
||||
const bool is_bounded = l->EdgeGeometry()->declaration().is(IfcSchema::IfcBoundedCurve::Class());
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
TopoDS_Edge e;
|
||||
if (util::create_edge_over_curve_with_log_messages(crv, getValue(GV_PRECISION), p1, p2, e)) {
|
||||
mw.Add(e);
|
||||
result = mw;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
|
||||
if (!l->SameSense()) {
|
||||
result.Reverse();
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
|
||||
while (exp.More()) {
|
||||
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
|
||||
exp.Next();
|
||||
const bool last = !exp.More();
|
||||
|
||||
gp_Pnt a, b;
|
||||
|
||||
if (first && last) {
|
||||
a = p1;
|
||||
b = p2;
|
||||
} else if (first) {
|
||||
a = p1;
|
||||
ecrv->D0(u2, b);
|
||||
} else if (last) {
|
||||
ecrv->D0(u1, a);
|
||||
b = p2;
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge me(ecrv, u1, u2);
|
||||
if (!me.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
mw.Add(me.Edge());
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
TopoDS_Edge e;
|
||||
if (util::create_edge_over_curve_with_log_messages(ecrv, getValue(GV_PRECISION), a, b, e)) {
|
||||
mw.Add(e);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -17,26 +17,10 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(*it, w)) {
|
||||
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
|
||||
}
|
||||
}
|
||||
if (!mw.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcEdgeLoop* inst) {
|
||||
return map_to_collection<taxonomy::loop>(this, inst->EdgeList());
|
||||
}
|
||||
|
||||
@@ -17,42 +17,37 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) {
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcEllipse* inst) {
|
||||
double x = inst->SemiAxis1() * length_unit_;
|
||||
double y = inst->SemiAxis2() * length_unit_;
|
||||
const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
|
||||
if (x < tol || y < tol) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto el = new taxonomy::ellipse;
|
||||
el->matrix = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
// is greater than the major radius. Hence, in this case, the
|
||||
// ellipse is rotated. Note that special care needs to be taken
|
||||
// ellipse is rotated. Note that special care is taken
|
||||
// when creating a trimmed curve off of an ellipse like this.
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
|
||||
IfcGeom::Kernel::convert(placement->as<IfcSchema::IfcAxis2Placement3D>(), trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(placement->as<IfcSchema::IfcAxis2Placement2D>(), trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
if (y > x) {
|
||||
el->matrix.components() <<
|
||||
-el->matrix.ccomponents().col(1),
|
||||
el->matrix.ccomponents().col(0),
|
||||
el->matrix.ccomponents().col(2),
|
||||
el->matrix.ccomponents().col(3);
|
||||
std::swap(x, y);
|
||||
}
|
||||
ax.Transform(trsf);
|
||||
curve = new Geom_Ellipse(ax, x, y);
|
||||
return true;
|
||||
|
||||
el->radius = x;
|
||||
el->radius2 = y;
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
@@ -17,51 +17,49 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/wire_utils.h"
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) {
|
||||
double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcEllipseProfileDef* inst) {
|
||||
double rx = inst->SemiAxis1() * length_unit_;
|
||||
double ry = inst->SemiAxis2() * length_unit_;
|
||||
const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
|
||||
if (rx < tol || ry < tol) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool rotated = ry > rx;
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
Eigen::Matrix4d m4;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
has_position = !!inst->Position();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf2d);
|
||||
taxonomy::matrix4 m = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
m4 = m.ccomponents();
|
||||
}
|
||||
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
if (ry > rx) {
|
||||
auto m4_copy = m4;
|
||||
m4 <<
|
||||
-m4_copy.col(1),
|
||||
m4_copy.col(0),
|
||||
m4_copy.col(2),
|
||||
m4_copy.col(3);
|
||||
std::swap(rx, ry);
|
||||
}
|
||||
ax.Transform(trsf2d);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(ellipse);
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = util::convert_wire_to_face(w, f, {false, false, 0., 0.});
|
||||
if (success) face = f;
|
||||
return success;
|
||||
auto fc = new taxonomy::face;
|
||||
auto lp = new taxonomy::loop;
|
||||
auto ed = new taxonomy::edge;
|
||||
auto el = new taxonomy::ellipse;
|
||||
el->radius = rx;
|
||||
el->radius2 = ry;
|
||||
ed->basis = el;
|
||||
lp->children.push_back(ed);
|
||||
fc->children.push_back(lp);
|
||||
return fc;
|
||||
}
|
||||
|
||||
@@ -17,91 +17,42 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
// uncomment if you'd like negative or close to zero extrusion depths to succeed
|
||||
// #define PERMISSIVE_EXTRUSION
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& 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);
|
||||
taxonomy::item* mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) {
|
||||
const double height = inst->Depth() * length_unit_;
|
||||
if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", inst);
|
||||
#ifndef PERMISSIVE_EXTRUSION
|
||||
return false;
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
TopoDS_Shape face;
|
||||
if ( !convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
gp_Trsf trsf;
|
||||
taxonomy::matrix4 matrix;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL
|
||||
has_position = l->Position() != nullptr;
|
||||
has_position = inst->Position() != nullptr;
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf);
|
||||
matrix = as<taxonomy::matrix4>(map(inst->Position()));
|
||||
}
|
||||
|
||||
#ifdef PERMISSIVE_EXTRUSION
|
||||
if (abs(height) < getValue(GV_PRECISION)) {
|
||||
shape = face;
|
||||
|
||||
if (has_position && !shape.IsNull()) {
|
||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||
// and therefore has a unit scale factor
|
||||
shape.Move(trsf);
|
||||
}
|
||||
|
||||
return true;
|
||||
face->matrix = matrix;
|
||||
return face;
|
||||
}
|
||||
#endif
|
||||
|
||||
gp_Dir dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
|
||||
shape.Nullify();
|
||||
|
||||
/*
|
||||
// @nb This logic was probably flawed always as this does not by itself result in a valid compsolid...
|
||||
if (face.ShapeType() == TopAbs_COMPOUND) {
|
||||
|
||||
// For compounds (most likely the result of a IfcCompositeProfileDef)
|
||||
// create a compound solid shape.
|
||||
|
||||
TopExp_Explorer exp(face, TopAbs_FACE);
|
||||
|
||||
TopoDS_CompSolid compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompSolid(compound);
|
||||
|
||||
int num_faces_extruded = 0;
|
||||
for (; exp.More(); exp.Next(), ++num_faces_extruded) {
|
||||
builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir));
|
||||
}
|
||||
|
||||
if (num_faces_extruded) {
|
||||
shape = compound;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
if (shape.IsNull()) {
|
||||
shape = BRepPrimAPI_MakePrism(face, height*dir);
|
||||
}
|
||||
|
||||
if (has_position && !shape.IsNull()) {
|
||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||
// and therefore has a unit scale factor
|
||||
shape.Move(trsf);
|
||||
}
|
||||
|
||||
return !shape.IsNull();
|
||||
return new taxonomy::extrusion(
|
||||
matrix,
|
||||
as<taxonomy::face>(map(inst->SweptArea())),
|
||||
as<taxonomy::direction3>(map(inst->ExtrudedDirection())),
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user