Proceed with merge

This commit is contained in:
Thomas Krijnen
2023-03-21 20:15:01 +01:00
parent cfb0eda067
commit c78b2893de
194 changed files with 105325 additions and 7785 deletions
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+29 -17
View File
@@ -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();
+8 -8
View File
@@ -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);
}
+19 -19
View File
@@ -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),
+12 -12
View File
@@ -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));
+18 -15
View File
@@ -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>
+63
View File
@@ -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;
}
+122
View File
@@ -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
+63 -24
View File
@@ -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
+9
View File
@@ -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];
}
+69 -140
View File
@@ -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
+457
View File
@@ -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;
// }
//}
+67
View File
@@ -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
+2 -2
View File
@@ -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
{
+13 -50
View File
@@ -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);
+13 -3
View File
@@ -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();
}
-145
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
#include "IfcGeomIteratorSettings.h"
#include "IteratorSettings.h"
#include "../ifcparse/IfcLogger.h"
-42
View File
@@ -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;
}
-54
View File
@@ -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
+4 -73
View File
@@ -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);
}
+77 -222
View 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)));
+55 -46
View File
@@ -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&);
-20
View File
@@ -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
View File
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
+2 -4
View File
@@ -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
+2 -2
View File
@@ -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);
+40 -40
View File
@@ -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;
}
+21 -10
View File
@@ -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;
}
+23 -10
View File
@@ -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_;
};
File diff suppressed because it is too large Load Diff
+57 -85
View File
@@ -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
+36 -24
View File
@@ -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
+68 -1
View File
@@ -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;
}
+335
View File
@@ -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;
*/
}
@@ -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>>;
+24 -21
View File
@@ -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;
+3 -3
View File
@@ -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);
+236
View File
@@ -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;
}
+103
View File
@@ -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;
}
+96
View File
@@ -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>
+6 -4
View File
@@ -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;
}
*/
-166
View File
@@ -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);
-30
View File
@@ -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 -25
View File
@@ -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;
}
+23 -15
View File
@@ -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);
}
+13 -23
View File
@@ -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);
}
+21 -34
View File
@@ -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
+10 -13
View File
@@ -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;
}
+36 -182
View File
@@ -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;
}
+10 -12
View File
@@ -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;
}
+38 -21
View File
@@ -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}}
});
}
+9 -13
View File
@@ -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;
}
+15 -18
View File
@@ -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;
*/
}
+15 -22
View File
@@ -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;
}
+40 -32
View File
@@ -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;
}
+72 -87
View File
@@ -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;
}
*/
+7 -32
View File
@@ -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);
}
+9 -95
View File
@@ -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
+5 -5
View File
@@ -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());
}
+11 -43
View File
@@ -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;
}
+8 -14
View File
@@ -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
+8 -17
View File
@@ -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;
}
+10 -14
View File
@@ -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;
}
}
+21 -27
View File
@@ -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;
}
-118
View File
@@ -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;
}
}
+5 -21
View File
@@ -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());
}
+26 -31
View File
@@ -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;
}
+31 -33
View File
@@ -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;
}
+19 -68
View File
@@ -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