mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 16:43:00 +00:00
More work
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#include "abstract_mapping.h"
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
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*);
|
||||
|
||||
ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() {
|
||||
init_MappingImplementation_Ifc2x3(this);
|
||||
init_MappingImplementation_Ifc4(this);
|
||||
init_MappingImplementation_Ifc4x1(this);
|
||||
init_MappingImplementation_Ifc4x2(this);
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file) {
|
||||
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);
|
||||
}
|
||||
@@ -1,15 +1,56 @@
|
||||
#ifndef ABSTRACT_MAPPING_H
|
||||
#define ABSTRACT_MAPPING_H
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcEntityList.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
#include "../ifcgeom/settings.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
namespace geometry {
|
||||
|
||||
class Element;
|
||||
class NativeElement;
|
||||
|
||||
struct geometry_conversion_task {
|
||||
int index;
|
||||
IfcUtil::IfcBaseEntity* representation;
|
||||
IfcEntityList::ptr products;
|
||||
std::vector<ifcopenshell::geometry::NativeElement*> breps;
|
||||
std::vector<ifcopenshell::geometry::Element*> elements;
|
||||
};
|
||||
|
||||
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
|
||||
|
||||
class abstract_mapping {
|
||||
public:
|
||||
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 std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1<abstract_mapping*, IfcParse::IfcFile*> 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*);
|
||||
};
|
||||
|
||||
MappingFactoryImplementation& mapping_implementations();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,551 +2,101 @@
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
|
||||
#define AbstractKernel MAKE_TYPE_NAME(AbstractKernel)
|
||||
|
||||
void IfcGeom::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
|
||||
placement_rel_to = type;
|
||||
}
|
||||
|
||||
void IfcGeom::AbstractKernel::setValue(GeomValue var, double value) {
|
||||
switch (var) {
|
||||
case GV_DEFLECTION_TOLERANCE:
|
||||
deflection_tolerance = value;
|
||||
break;
|
||||
case GV_POINT_EQUALITY_TOLERANCE:
|
||||
point_equality_tolerance = value;
|
||||
break;
|
||||
case GV_LENGTH_UNIT:
|
||||
ifc_length_unit = value;
|
||||
break;
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
ifc_planeangle_unit = value;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
modelling_precision = value;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
dimensionality = value;
|
||||
break;
|
||||
default:
|
||||
assert(!"never reach here");
|
||||
}
|
||||
}
|
||||
|
||||
double IfcGeom::AbstractKernel::getValue(GeomValue var) const {
|
||||
switch (var) {
|
||||
case GV_DEFLECTION_TOLERANCE:
|
||||
return deflection_tolerance;
|
||||
case GV_MINIMAL_FACE_AREA:
|
||||
// Considering a right-angled triangle, this about the smallest
|
||||
// area you can obtain without the vertices being confused.
|
||||
return modelling_precision * modelling_precision / 2.;
|
||||
case GV_POINT_EQUALITY_TOLERANCE:
|
||||
return point_equality_tolerance;
|
||||
case GV_LENGTH_UNIT:
|
||||
return ifc_length_unit;
|
||||
break;
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
return ifc_planeangle_unit;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
return modelling_precision;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
return dimensionality;
|
||||
break;
|
||||
}
|
||||
assert(!"never reach here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const IfcSchema::IfcMaterial* IfcGeom::AbstractKernel::get_single_material_association(const IfcSchema::IfcProduct* product) {
|
||||
IfcSchema::IfcMaterial* single_material = 0;
|
||||
IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (associated_materials->size() == 1) {
|
||||
IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
|
||||
single_material = associated_material->as<IfcSchema::IfcMaterial>();
|
||||
|
||||
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
|
||||
// in accordance with other viewers.
|
||||
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
|
||||
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
|
||||
if (layerset->MaterialLayers()->size() == 1) {
|
||||
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
|
||||
if (layer->hasMaterial()) {
|
||||
single_material = layer->Material();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return single_material;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* IfcGeom::AbstractKernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items();
|
||||
if (items->size() == 1) {
|
||||
IfcSchema::IfcRepresentationItem* item = *items->begin();
|
||||
if (item->declaration().is(IfcSchema::IfcMappedItem::Class())) {
|
||||
if (item->StyledByItem()->size() == 0) {
|
||||
IfcSchema::IfcMappedItem* mapped_item = item->as<IfcSchema::IfcMappedItem>();
|
||||
if (is_identity_transform(mapped_item->MappingTarget())) {
|
||||
IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource();
|
||||
if (is_identity_transform(map->MappingOrigin())) {
|
||||
representation_mapped_to = map->MappedRepresentation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return representation_mapped_to;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr IfcGeom::AbstractKernel::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||
|
||||
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
if (maps->size() == 1) {
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (is_identity_transform(map->MappingOrigin())) {
|
||||
IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage();
|
||||
for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
|
||||
IfcSchema::IfcMappedItem* item = *it;
|
||||
if (item->StyledByItem()->size() != 0) continue;
|
||||
|
||||
if (!is_identity_transform(item->MappingTarget())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = item->data().getInverse((&IfcSchema::IfcRepresentation::Class()), -1)->as<IfcSchema::IfcRepresentation>();
|
||||
for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation* rep = *jt;
|
||||
if (rep->Items()->size() != 1) continue;
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps_mapped = rep->OfProductRepresentation();
|
||||
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps_mapped->begin(); kt != prodreps_mapped->end(); ++kt) {
|
||||
IfcSchema::IfcProduct::list::ptr ps = (*kt)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>();
|
||||
products->push(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
|
||||
while (item->declaration().is(IfcSchema::IfcBooleanClippingResult::Class())) {
|
||||
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
|
||||
// IfcGeometricRepresentationItem
|
||||
item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand();
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
/* 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, ifcopenshell::geometry::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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
|
||||
// But neither are these very prevalent, nor does the current IfcOpenShell style
|
||||
// mechanism enable to conveniently style subshapes, which would be necessary for
|
||||
// distinctly styled union operands.
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::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);
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
template <>
|
||||
struct dispatch_conversion<ifcopenshell::geometry::taxonomy::type_by_kind::max> {
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item*, ifcopenshell::geometry::ConversionResults&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
|
||||
bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) {
|
||||
return dispatch_conversion<0>::dispatch(this, item, results);
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
|
||||
if (ss.second) {
|
||||
return internalize_surface_style(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
|
||||
return &(style_cache[material->data().id()] = material_style);
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int, SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
|
||||
if (it != style_cache.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
|
||||
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
|
||||
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
|
||||
|
||||
if (style->hasName()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, style->Name());
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
double rgb[3];
|
||||
if (process_colour(shading->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1, 1, 1));
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasDiffuseTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasReflectionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasTransparency()) {
|
||||
const double d = rendering_style->Transparency();
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(style_cache[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) {
|
||||
std::stringstream representation_id_builder;
|
||||
|
||||
representation_id_builder << representation->data().id();
|
||||
|
||||
IfcGeom::Representation::BRep* shape;
|
||||
IfcGeom::ConversionResults shapes;
|
||||
|
||||
if (!convert_shapes(representation, shapes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
|
||||
if (apply_layerset(product, shapes)) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool material_style_applied = false;
|
||||
|
||||
const IfcSchema::IfcMaterial* single_material = get_single_material_association(product);
|
||||
if (single_material) {
|
||||
const IfcGeom::SurfaceStyle* s = get_style(single_material);
|
||||
for (IfcGeom::ConversionResults::iterator 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 (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
if (!it->hasStyle()) {
|
||||
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();
|
||||
}
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->hasName() ? product->Name() : "";
|
||||
const std::string guid = product->GlobalId();
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as<IfcSchema::IfcRelVoidsElement>();
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
|
||||
|
||||
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
|
||||
representation_id_builder << "-openings";
|
||||
for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) {
|
||||
representation_id_builder << "-" << (*it)->data().id();
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResults opened_shapes;
|
||||
bool caught_error = false;
|
||||
try {
|
||||
convert_openings(product, openings, shapes, trsf, 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(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
representation_id_builder << "-world-coords";
|
||||
}
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes);
|
||||
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
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 = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
|
||||
auto elem = new NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
boost::shared_ptr<IfcGeom::Representation::BRep>(shape),
|
||||
product
|
||||
);
|
||||
|
||||
if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
|
||||
validate_quantities(product, elem->geometry());
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_processed_representation(
|
||||
const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product,
|
||||
IfcGeom::NativeElement<P, PP>* brep) {
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->hasName() ? product->Name() : "";
|
||||
const std::string guid = product->GlobalId();
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
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 NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
brep->geometry_pointer(),
|
||||
product
|
||||
);
|
||||
}
|
||||
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, float>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<double, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, float>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, float>* brep);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, double>* brep);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<double, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<double, double>* brep);
|
||||
//void ifcopenshell::geometry::kernels::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
|
||||
// placement_rel_to = type;
|
||||
//}
|
||||
//
|
||||
//void ifcopenshell::geometry::kernels::AbstractKernel::setValue(GeomValue var, double value) {
|
||||
// switch (var) {
|
||||
// case GV_DEFLECTION_TOLERANCE:
|
||||
// deflection_tolerance = value;
|
||||
// break;
|
||||
// case GV_POINT_EQUALITY_TOLERANCE:
|
||||
// point_equality_tolerance = value;
|
||||
// break;
|
||||
// case GV_LENGTH_UNIT:
|
||||
// ifc_length_unit = value;
|
||||
// break;
|
||||
// case GV_PLANEANGLE_UNIT:
|
||||
// ifc_planeangle_unit = value;
|
||||
// break;
|
||||
// case GV_PRECISION:
|
||||
// modelling_precision = value;
|
||||
// break;
|
||||
// case GV_DIMENSIONALITY:
|
||||
// dimensionality = value;
|
||||
// break;
|
||||
// default:
|
||||
// assert(!"never reach here");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//double ifcopenshell::geometry::kernels::AbstractKernel::getValue(GeomValue var) const {
|
||||
// switch (var) {
|
||||
// case GV_DEFLECTION_TOLERANCE:
|
||||
// return deflection_tolerance;
|
||||
// case GV_MINIMAL_FACE_AREA:
|
||||
// // Considering a right-angled triangle, this about the smallest
|
||||
// // area you can obtain without the vertices being confused.
|
||||
// return modelling_precision * modelling_precision / 2.;
|
||||
// case GV_POINT_EQUALITY_TOLERANCE:
|
||||
// return point_equality_tolerance;
|
||||
// case GV_LENGTH_UNIT:
|
||||
// return ifc_length_unit;
|
||||
// break;
|
||||
// case GV_PLANEANGLE_UNIT:
|
||||
// return ifc_planeangle_unit;
|
||||
// break;
|
||||
// case GV_PRECISION:
|
||||
// return modelling_precision;
|
||||
// break;
|
||||
// case GV_DIMENSIONALITY:
|
||||
// return dimensionality;
|
||||
// break;
|
||||
// }
|
||||
// assert(!"never reach here");
|
||||
// return 0;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, float>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<float, float>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<float, double>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<double, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<double, double>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
//
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, float>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<float, float>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<float, float>* brep);
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<float, double>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<float, double>* brep);
|
||||
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<double, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<double, double>(
|
||||
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<double, double>* brep);
|
||||
@@ -3,19 +3,12 @@
|
||||
|
||||
#include "../../ifcparse/macros.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
#include "../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../ifcgeom/taxonomy.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
namespace ifcopenshell { namespace geometry { namespace kernels {
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(AbstractKernel) : public IfcGeom::Kernel {
|
||||
class IFC_GEOM_API AbstractKernel {
|
||||
protected:
|
||||
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
|
||||
const IfcParse::declaration* placement_rel_to;
|
||||
@@ -29,11 +22,11 @@ namespace IfcGeom {
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
|
||||
std::map<int, SurfaceStyle> style_cache;
|
||||
std::string geometry_library;
|
||||
|
||||
public:
|
||||
MAKE_TYPE_NAME(AbstractKernel)(const std::string& geometry_library)
|
||||
: IfcGeom::Kernel(geometry_library, nullptr)
|
||||
AbstractKernel(const std::string& geometry_library)
|
||||
: geometry_library(geometry_library)
|
||||
, deflection_tolerance(0.001)
|
||||
, wire_creation_tolerance(0.0001)
|
||||
, point_equality_tolerance(0.00001)
|
||||
@@ -42,36 +35,39 @@ namespace IfcGeom {
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
, placement_rel_to(0)
|
||||
{}
|
||||
, placement_rel_to(0) {}
|
||||
|
||||
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
|
||||
virtual void setValue(GeomValue var, double value);
|
||||
virtual double getValue(GeomValue var) const;
|
||||
bool convert(const taxonomy::item*, ifcopenshell::geometry::ConversionResults&);
|
||||
|
||||
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*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*) = 0;
|
||||
virtual bool convert_shapes(const IfcUtil::IfcBaseClass*, IfcGeom::ConversionResults&) = 0;
|
||||
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) = 0;
|
||||
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) = 0;
|
||||
virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) = 0;
|
||||
|
||||
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement<P, PP>*);
|
||||
virtual bool convert_impl(const taxonomy::matrix4*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::point3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::direction3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::line*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::circle*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::ellipse*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::bspline*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::edge*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::loop*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1 < AbstractKernel*, const std::string&> kernel_fn;
|
||||
|
||||
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
|
||||
public:
|
||||
KernelFactoryImplementation();
|
||||
void bind(const std::string& geometry_library, kernel_fn);
|
||||
AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*);
|
||||
};
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "IfcGeomIteratorImplementation.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, float>;
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, double>;
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<double, double>;
|
||||
}
|
||||
|
||||
#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 {
|
||||
template <typename P, typename PP>
|
||||
struct MAKE_TYPE_NAME(factory_t) {
|
||||
IfcGeom::IteratorImplementation<P, PP>* operator()(const std::string& geometry_engine, 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_)<P, PP>(geometry_engine, settings, file, filters, num_threads);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation<P, PP>* mapping) {
|
||||
static const std::string schema_name = STRINGIFY(IfcSchema);
|
||||
MAKE_TYPE_NAME(factory_t)<P, PP> factory;
|
||||
mapping->bind(schema_name, factory);
|
||||
}
|
||||
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<float, float>(IteratorFactoryImplementation<float, float>*);
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<float, double>(IteratorFactoryImplementation<float, double>*);
|
||||
template void MAKE_INIT_FN(IteratorImplementation_)<double, double>(IteratorFactoryImplementation<double, double>*);
|
||||
@@ -1,950 +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 <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#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/macros.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
#include <atomic>
|
||||
|
||||
// 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 {
|
||||
template <typename P, typename PP=P>
|
||||
struct geometry_conversion_task {
|
||||
int index;
|
||||
IfcSchema::IfcRepresentation *representation;
|
||||
IfcSchema::IfcProduct::list::ptr products;
|
||||
std::vector<IfcGeom::NativeElement<P, PP>*> breps;
|
||||
std::vector<IfcGeom::Element<P, PP>*> elements;
|
||||
};
|
||||
|
||||
template <typename P, typename PP=P>
|
||||
IfcGeom::Element<P, PP>* process_based_on_settings(
|
||||
const IfcGeom::IteratorSettings& settings,
|
||||
IfcGeom::NativeElement<P, PP>* elem,
|
||||
IfcGeom::TriangulationElement<P, PP>* previous=nullptr)
|
||||
{
|
||||
if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
|
||||
try {
|
||||
return new IfcGeom::SerializedElement<P, PP>(*elem);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
return nullptr;
|
||||
}
|
||||
} else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
try {
|
||||
if (!previous) {
|
||||
return new IfcGeom::TriangulationElement<P, PP>(*elem);
|
||||
} else {
|
||||
return new IfcGeom::TriangulationElement<P, PP>(*elem, previous->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P, typename PP = P>
|
||||
void create_element(
|
||||
IfcGeom::MAKE_TYPE_NAME(AbstractKernel)* kernel,
|
||||
const IfcGeom::IteratorSettings& settings,
|
||||
geometry_conversion_task<P, PP>* rep)
|
||||
{
|
||||
IfcSchema::IfcRepresentation *representation = rep->representation;
|
||||
IfcSchema::IfcProduct *product = *rep->products->begin();
|
||||
auto brep = kernel->create_brep_for_representation_and_product<P, PP>(settings, representation, product);
|
||||
if (!brep) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto elem = process_based_on_settings(settings, brep);
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
rep->breps = { brep };
|
||||
rep->elements = { elem };
|
||||
|
||||
for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) {
|
||||
auto brep2 = kernel->create_brep_for_processed_representation<P, PP>(settings, representation, *it, brep);
|
||||
if (brep2) {
|
||||
auto elem2 = process_based_on_settings(settings, brep, dynamic_cast<IfcGeom::TriangulationElement<P, PP>*>(elem));
|
||||
if (elem2) {
|
||||
rep->breps.push_back(brep2);
|
||||
rep->elements.push_back(elem2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class MAKE_TYPE_NAME(IteratorImplementation_) : public IteratorImplementation<P, PP> {
|
||||
private:
|
||||
|
||||
int num_threads_;
|
||||
std::atomic<int> progress_;
|
||||
std::vector<geometry_conversion_task<P, PP>> tasks_;
|
||||
std::vector<IfcGeom::Element<P, PP>*> all_processed_elements_;
|
||||
std::vector<IfcGeom::NativeElement<P, PP>*> all_processed_native_elements_;
|
||||
typename std::vector<IfcGeom::Element<P, PP>*>::const_iterator task_result_iterator_;
|
||||
typename std::vector<IfcGeom::NativeElement<P, PP>*>::const_iterator native_task_result_iterator_;
|
||||
|
||||
std::string geometry_library_;
|
||||
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)& operator=(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
|
||||
MAKE_TYPE_NAME(AbstractKernel)* kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
|
||||
// A container and iterator for IfcRepresentations
|
||||
IfcSchema::IfcRepresentation::list::ptr representations;
|
||||
IfcSchema::IfcRepresentation::list::it representation_iterator;
|
||||
|
||||
// The object is fetched beforehand to be sure that get() returns a valid element
|
||||
TriangulationElement<P, PP>* current_triangulation;
|
||||
NativeElement<P, PP>* current_shape_model;
|
||||
SerializedElement<P, PP>* current_serialization;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||
IfcSchema::IfcProduct::list::ptr ifcproducts;
|
||||
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
||||
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
std::string unit_name;
|
||||
double unit_magnitude;
|
||||
|
||||
gp_XYZ bounds_min_;
|
||||
gp_XYZ bounds_max_;
|
||||
|
||||
std::vector<filter_t> filters_;
|
||||
|
||||
struct filter_match
|
||||
{
|
||||
filter_match(IfcSchema::IfcProduct *prod) : product(prod) {}
|
||||
bool operator()(const filter_t& filter) const { return filter(product); }
|
||||
|
||||
IfcSchema::IfcProduct* product;
|
||||
};
|
||||
|
||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
||||
public:
|
||||
typedef P Precision;
|
||||
typedef PP PlacementPrecision;
|
||||
|
||||
bool initialize() {
|
||||
|
||||
std::set<std::string> allowed_context_types;
|
||||
allowed_context_types.insert("model");
|
||||
allowed_context_types.insert("plan");
|
||||
allowed_context_types.insert("notdefined");
|
||||
|
||||
std::set<std::string> context_types;
|
||||
if (!settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// Some earlier (?) versions DDS-CAD output their own ContextTypes
|
||||
context_types.insert("model view");
|
||||
context_types.insert("detail view");
|
||||
}
|
||||
if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
ifc_file->instances_by_type<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type = context->ContextType();
|
||||
boost::to_lower(context_type);
|
||||
|
||||
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
|
||||
Logger::Warning(std::string("ContextType '") + context->ContextType() + "' not allowed:", context);
|
||||
}
|
||||
if (context_types.find(context_type) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// In case no contexts are identified based on their ContextType, all contexts are
|
||||
// considered. Note that sub contexts are excluded as they are considered later on.
|
||||
if (filtered_contexts->size() == 0) {
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
}
|
||||
// There is no need for full recursion as the following is governed by the schema:
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered in relevant contexts, using all");
|
||||
representations = ifc_file->instances_by_type<IfcSchema::IfcRepresentation>();
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
representation_iterator = representations->begin();
|
||||
ifcproducts.reset();
|
||||
|
||||
done = 0;
|
||||
total = representations->size();
|
||||
|
||||
if (num_threads_ != 1) {
|
||||
collect();
|
||||
process_concurrently();
|
||||
} else {
|
||||
if (!create()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void collect() {
|
||||
int i = 0;
|
||||
IfcSchema::IfcProduct::list* previous = nullptr;
|
||||
while (auto rp = get_next_task()) {
|
||||
// Note that get_next_task() mutates the state of the iterator
|
||||
// we use that capture all products that can be processed as
|
||||
// part of this representation and then keep iterating until
|
||||
// the underlying list of products changes.
|
||||
if (ifcproducts.get() != previous) {
|
||||
previous = ifcproducts.get();
|
||||
geometry_conversion_task<P, PP> t;
|
||||
t.index = i++;
|
||||
t.representation = *representation_iterator;
|
||||
t.products = ifcproducts;
|
||||
tasks_.emplace_back(t);
|
||||
}
|
||||
|
||||
_nextShape();
|
||||
}
|
||||
}
|
||||
|
||||
void process_concurrently() {
|
||||
size_t conc_threads = num_threads_;
|
||||
if (conc_threads > tasks_.size()) {
|
||||
conc_threads = tasks_.size();
|
||||
}
|
||||
|
||||
std::vector<MAKE_TYPE_NAME(AbstractKernel)*> kernel_pool;
|
||||
kernel_pool.reserve(conc_threads);
|
||||
for (unsigned i = 0; i < conc_threads; ++i) {
|
||||
kernel_pool.push_back((MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(ifc_file->schema()->name(), geometry_library_, ifc_file));
|
||||
}
|
||||
|
||||
std::vector<std::future<void>> threadpool;
|
||||
|
||||
int old_progress = -1;
|
||||
int processed = 0;
|
||||
|
||||
Logger::ProgressBar(0);
|
||||
|
||||
for (auto& rep : tasks_) {
|
||||
MAKE_TYPE_NAME(AbstractKernel)* K = nullptr;
|
||||
if (threadpool.size() < kernel_pool.size()) {
|
||||
K = kernel_pool[threadpool.size()];
|
||||
}
|
||||
|
||||
while (threadpool.size() == conc_threads) {
|
||||
for (int i = 0; i < (int)threadpool.size(); i++) {
|
||||
std::future<void> &fu = threadpool[i];
|
||||
std::future_status status;
|
||||
status = fu.wait_for(std::chrono::seconds(0));
|
||||
if (status == std::future_status::ready) {
|
||||
fu.get();
|
||||
|
||||
processed += 1;
|
||||
progress_ = processed * 50 / tasks_.size();
|
||||
if (progress_ != old_progress) {
|
||||
Logger::ProgressBar(progress_);
|
||||
old_progress = progress_;
|
||||
}
|
||||
|
||||
std::swap(threadpool[i], threadpool.back());
|
||||
threadpool.pop_back();
|
||||
std::swap(kernel_pool[i], kernel_pool.back());
|
||||
K = kernel_pool.back();
|
||||
break;
|
||||
} // if
|
||||
} // for
|
||||
} // while
|
||||
|
||||
std::future<void> fu = std::async(std::launch::async, create_element<P, PP>, K, std::ref(settings), &rep);
|
||||
threadpool.emplace_back(std::move(fu));
|
||||
}
|
||||
|
||||
for (std::future<void> &fu : threadpool) {
|
||||
fu.get();
|
||||
|
||||
processed += 1;
|
||||
progress_ = processed * 50 / tasks_.size();
|
||||
if (progress_ != old_progress) {
|
||||
Logger::ProgressBar(progress_);
|
||||
old_progress = progress_;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& rep : tasks_) {
|
||||
all_processed_elements_.insert(all_processed_elements_.end(), rep.elements.begin(), rep.elements.end());
|
||||
all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep.breps.begin(), rep.breps.end());
|
||||
}
|
||||
|
||||
task_result_iterator_ = all_processed_elements_.begin();
|
||||
native_task_result_iterator_ = all_processed_native_elements_.begin();
|
||||
|
||||
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
|
||||
" objects) ");
|
||||
}
|
||||
|
||||
/// Computes model's bounding box (bounds_min and bounds_max).
|
||||
/// @note Can take several minutes for large files.
|
||||
void compute_bounds()
|
||||
{
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
|
||||
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type<IfcSchema::IfcProduct>();
|
||||
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
|
||||
IfcSchema::IfcProduct* product = *iter;
|
||||
if (product->hasObjectPlacement()) {
|
||||
// Use a fresh trsf every time in order to prevent the result to be concatenated
|
||||
ConversionResultPlacement* trsf;
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
success = kernel->convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double X, Y, Z;
|
||||
trsf->TranslationPart(X, Y, Z);
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), X));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), Y));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), Z));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), X));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), Y));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), Z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int progress() const {
|
||||
if (num_threads_ == 1) {
|
||||
return 100 * done / total;
|
||||
} else {
|
||||
return progress_;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& getUnitName() const { return unit_name; }
|
||||
|
||||
/// @note Double always as per IFC specification.
|
||||
double getUnitMagnitude() const { return unit_magnitude; }
|
||||
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return ifc_file; }
|
||||
|
||||
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
|
||||
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
||||
const gp_XYZ& bounds_max() const { return bounds_max_; }
|
||||
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
ifcproducts.reset();
|
||||
++ representation_iterator;
|
||||
++ done;
|
||||
}
|
||||
|
||||
bool geometry_reuse_ok_for_current_representation_;
|
||||
|
||||
bool reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) {
|
||||
// With world coords enabled, object transformations are directly applied to
|
||||
// the BRep. There is no way to re-use the geometry for multiple products.
|
||||
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<const IfcSchema::IfcMaterial*> associated_single_materials;
|
||||
|
||||
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) {
|
||||
IfcSchema::IfcProduct* product = *it;
|
||||
|
||||
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel->find_openings(product)->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (assoc) {
|
||||
if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) {
|
||||
// TODO: Check whether single layer?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
|
||||
associated_single_materials.insert(kernel->get_single_material_association(product));
|
||||
if (associated_single_materials.size() > 1) return false;
|
||||
}
|
||||
|
||||
return associated_single_materials.size() == 1;
|
||||
}
|
||||
|
||||
boost::optional<std::pair<IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*>> get_next_task() {
|
||||
for (;;) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
if (representation_iterator == representations->end()) {
|
||||
representations.reset();
|
||||
return boost::none; // reached the end of our list of representations
|
||||
}
|
||||
representation = *representation_iterator;
|
||||
|
||||
if (!ifcproducts) {
|
||||
// Init. the list of filtered IfcProducts for this representation
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel->products_represented_by(representation);
|
||||
// Include only the desired products for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
if (ifcproducts->size() == 0) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts);
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
|
||||
if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) {
|
||||
// unfiltered_products contains products represented by this representation by means of mapped items.
|
||||
// For example because of openings applied to products, reuse might not be acceptable and then the
|
||||
// products will be processed by means of their immediate representation and not the mapped representation.
|
||||
|
||||
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map
|
||||
// is indeed used by IfcMappedItems.
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (map->MapUsage()->size() > 0) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this represenation has (or will be) processed as part its mapped representation
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel->representation_mapped_to(representation);
|
||||
if (representation_mapped_to) {
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
|
||||
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel->products_represented_by(representation_mapped_to)));
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
ok_mapped_representations->push(representation_mapped_to);
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
ifcproduct_iterator = ifcproducts->begin();
|
||||
}
|
||||
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if (ifcproduct_iterator == ifcproducts->end()) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
|
||||
|
||||
|
||||
return std::make_pair(representation, product);
|
||||
}
|
||||
}
|
||||
|
||||
NativeElement<P, PP>* create_shape_model_for_next_entity() {
|
||||
for (;;) {
|
||||
auto rp = get_next_task();
|
||||
if (!rp) {
|
||||
return nullptr;
|
||||
}
|
||||
auto representation = rp->first;
|
||||
auto product = rp->second;
|
||||
|
||||
Logger::SetProduct(product);
|
||||
|
||||
NativeElement<P, PP>* element;
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
||||
element = kernel->create_brep_for_representation_and_product<P, PP>(settings, representation, product);
|
||||
} else {
|
||||
element = kernel->create_brep_for_processed_representation(settings, representation, product, current_shape_model);
|
||||
}
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
|
||||
if (!element) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
void free_shapes() {
|
||||
// Free all possible representations of the current geometrical entity
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
delete current_serialization;
|
||||
current_serialization = 0;
|
||||
delete current_shape_model;
|
||||
current_shape_model = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Returns what would be the product for the next shape representation
|
||||
/// @todo Double-check and test the impl.
|
||||
//IfcSchema::IfcProduct* peek_next() const
|
||||
//{
|
||||
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
|
||||
// return *(ifcproduct_iterator + 1);
|
||||
// } else {
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
/// @todo Would this be as simple as the following code?
|
||||
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
IfcUtil::IfcBaseClass* next() {
|
||||
if (num_threads_ != 1) {
|
||||
task_result_iterator_++;
|
||||
native_task_result_iterator_++;
|
||||
if (task_result_iterator_ == all_processed_elements_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return (*task_result_iterator_)->product();
|
||||
}
|
||||
} else {
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
if (ifcproducts) {
|
||||
++ifcproduct_iterator;
|
||||
}
|
||||
|
||||
return create();
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the representation of the current geometrical entity.
|
||||
Element<P, PP>* get()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
Element<P, PP>* ret = 0;
|
||||
|
||||
if (num_threads_ != 1) {
|
||||
ret = *task_result_iterator_;
|
||||
} else {
|
||||
if (current_triangulation) {
|
||||
ret = current_triangulation;
|
||||
} else if (current_serialization) {
|
||||
ret = current_serialization;
|
||||
} else if (current_shape_model) {
|
||||
ret = current_shape_model;
|
||||
}
|
||||
}
|
||||
|
||||
// If we want to organize the element considering their hierarchy
|
||||
if (settings.get(IteratorSettings::SEARCH_FLOOR))
|
||||
{
|
||||
// We are going to build a vector with the element parents.
|
||||
// First, create the parent vector
|
||||
std::vector<const IfcGeom::Element<P, PP>*> parents;
|
||||
|
||||
// if the element has a parent
|
||||
if (ret->parent_id() != -1)
|
||||
{
|
||||
const IfcGeom::Element<P, PP>* parent_object = NULL;
|
||||
bool hasParent = true;
|
||||
|
||||
// get the parent
|
||||
try {
|
||||
parent_object = get_object(ret->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
// We need to find all the parents
|
||||
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1)
|
||||
{
|
||||
// Find the next parent
|
||||
try {
|
||||
parent_object = get_object(parent_object->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
hasParent = hasParent && parent_object->parent_id() != -1;
|
||||
}
|
||||
|
||||
// when done push the parent list in the Element object
|
||||
ret->SetParents(parents);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
NativeElement<P, PP>* get_native()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
if (num_threads_ != 1) {
|
||||
return *native_task_result_iterator_;
|
||||
} else {
|
||||
return current_shape_model;
|
||||
}
|
||||
}
|
||||
|
||||
const Element<P, PP>* get_object(int id) {
|
||||
ConversionResultPlacement* trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcSchema::IfcProduct* ifc_product = 0;
|
||||
|
||||
try {
|
||||
IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id);
|
||||
instance_type = ifc_entity->declaration().name();
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) {
|
||||
IfcSchema::IfcRoot* ifc_root = ifc_entity->as<IfcSchema::IfcRoot>();
|
||||
product_guid = ifc_root->GlobalId();
|
||||
product_name = ifc_root->hasName() ? ifc_root->Name() : "";
|
||||
}
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) {
|
||||
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to find decomposing entity");
|
||||
}
|
||||
|
||||
try {
|
||||
kernel->convert_placement(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
}
|
||||
} 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 returning product");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error returning product");
|
||||
}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
|
||||
Element<P, PP>* ifc_object = new Element<P, PP>(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product);
|
||||
return ifc_object;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* create() {
|
||||
IfcGeom::NativeElement<P, PP>* next_shape_model = 0;
|
||||
IfcGeom::SerializedElement<P, PP>* next_serialization = 0;
|
||||
IfcGeom::TriangulationElement<P, PP>* next_triangulation = 0;
|
||||
|
||||
try {
|
||||
next_shape_model = create_shape_model_for_next_entity();
|
||||
} 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 geometry");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating geometry");
|
||||
}
|
||||
|
||||
if (next_shape_model) {
|
||||
if (settings.get(IteratorSettings::USE_BREP_DATA)) {
|
||||
try {
|
||||
next_serialization = new SerializedElement<P, PP>(*next_shape_model);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
}
|
||||
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
try {
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
||||
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model);
|
||||
} else {
|
||||
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model, current_triangulation->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
|
||||
current_shape_model = next_shape_model;
|
||||
current_serialization = next_serialization;
|
||||
current_triangulation = next_triangulation;
|
||||
|
||||
return next_shape_model ? next_shape_model->product() : 0;
|
||||
}
|
||||
private:
|
||||
void _initialize() {
|
||||
current_triangulation = 0;
|
||||
current_shape_model = 0;
|
||||
current_serialization = 0;
|
||||
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel->setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel->setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
|
||||
? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
|
||||
if (settings.get(IteratorSettings::BUILDING_LOCAL_PLACEMENT)) {
|
||||
if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
|
||||
}
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
|
||||
} else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
|
||||
}
|
||||
}
|
||||
|
||||
bool owns_ifc_file;
|
||||
public:
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
, filters_(filters)
|
||||
, owns_ifc_file(false)
|
||||
, num_threads_(num_threads)
|
||||
, geometry_library_(geometry_library)
|
||||
{
|
||||
kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file);
|
||||
// kernel = new Kernel(geometry_library, file);
|
||||
_initialize();
|
||||
}
|
||||
|
||||
~MAKE_TYPE_NAME(IteratorImplementation_)() {
|
||||
if (owns_ifc_file) {
|
||||
delete ifc_file;
|
||||
}
|
||||
|
||||
if (settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
for (auto& p : all_processed_native_elements_) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& p : all_processed_elements_) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
v0.6.0
|
||||
|
||||
People not following the development of IfcOpenShell actively and happily using the master branch of the github repository might be surprised to know there is a lot of activity happening in the v0.6.0 and v0.7.0 branches. This post discusses the changes in the v0.6.0 branch. The following post will elaborate on some of the design decisions we are making in the v0.7.0 branch.
|
||||
|
||||
Schemas
|
||||
|
||||
The most significant improvement in the v0.6.0 branch is that multiple schemas (IFC2X3, IFC4, IFC4X1 and IFC4X2) are supported from within the same executable, module or plug-in. Previously, selecting the schema had been a compile-time option.
|
||||
|
||||
In IfcOpenShell and most other EXPRESS-based toolkits, the IFC schema is compiled into (a) the early-bound definitions: a class hierarchy with member functions and (b) a set of methods to operate on the schema definitions at runtime (late-bound access). C++ only allows very limited introspection (but the development of C++ is very active, see for example P1240 https://github.com/cplusplus/papers/issues/545) so to complement the lack of introspection a set of methods exists to query for example all attribute names or the sub- and supertypes of an entity. In the master branch these methods are static, in the v0.6.0 branch these are the member functions of a schema class, that is a more complete reference mirrorring the EXPRESS schema definition at runtime. See IfcBaseEntity::declararation() or IfcParse::schema::declaration_by_name("IfcWall")->as_entity()->all_attribute_names().
|
||||
|
||||
Writing schema agnostic code
|
||||
|
||||
The code generated from the four schemas are completely orthogonal class hiercharies. For the C++ compiler there is no relationship between a Ifc2x3::IfcWall and a Ifc4::IfcWall. But IfcOpenShell offers three ways to write code that adapts to the schema of the file known at runtime.
|
||||
|
||||
(a) preprocessor
|
||||
|
||||
This is the approach taken in the IfcGeom modules in v0.6.0. Essentially the same code base is compiled multiple times where the schema is available as a preprocessor constant. This means you can enable specific code paths with for example #ifdef directives. In this way the added entities in Ifc4 (IfcBSplineSurface, yay!) can be selectively compiled for example.
|
||||
|
||||
https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom/IfcGeomFaces.cpp#L1127
|
||||
|
||||
Smaller code blocks can be written as macros as well.
|
||||
|
||||
https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom_schema_agnostic/Kernel.cpp#L74
|
||||
|
||||
Benefits: fairly readible code, full autocompletion typically in an IDE when using the static library approach
|
||||
Downsides: Some infrastructure required to compile the different libraries and select the correct implementation at runtime
|
||||
|
||||
(b) late-bound access
|
||||
|
||||
There are two modes of accessing schemas. In the early-bound approach function signatures and return types are known at compilation time. In the late-bound approach attribute names are referenced by strings and types are
|
||||
|
||||
Ifc2x3::IfcWall* wall;
|
||||
// Early-bound access;
|
||||
std::string global_id = wall->GlobalId();
|
||||
// Late-bound access.
|
||||
std::string global_id = *wall->get("GlobalId");
|
||||
// ERROR: By dereferencing the return type, it is casted into a string, which will cause an exception *at runtime* when the types do not match.
|
||||
int global_id = *wall->get("GlobalId");
|
||||
|
||||
Benefits:
|
||||
fairly readible code
|
||||
no complicated setup of different libraries
|
||||
Downsides:
|
||||
no code completion
|
||||
errors are only spotted at runtime, not compile-time
|
||||
late-bound manipulation of inverse attributes is not well supported currently in IfcOpenShell
|
||||
less means for the compiler to create highly optimized code
|
||||
|
||||
(c) templates
|
||||
|
||||
C++ has very extensive support for compile time generic arguments: templates.
|
||||
|
||||
template <Schema>
|
||||
void print_globalid(Schema::IfcWall* wall) {
|
||||
std::cout << wall->GlobalId();
|
||||
}
|
||||
|
||||
Benefits:
|
||||
no complicated setup of different libraries
|
||||
no autocompletion typically, but errors caught at compile-time
|
||||
Downsides:
|
||||
fairly unreadible code due to additional template and typename keywords.
|
||||
error messages are harder to make sense up (due to two phase lookup rules for example)
|
||||
|
||||
All three approaches are used in the IfcOpenShell code-base.
|
||||
|
||||
Other improvements:
|
||||
|
||||
Multi-threading in collaboration with TNO, MAUC and Airsquire
|
||||
|
||||
Direct binary glTF output (previously supported through Collada and Collada2Gltf) in collaboration with Schuco US.
|
||||
@@ -1,375 +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 IFCGEOM_H
|
||||
#define IFCGEOM_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.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 <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../../../ifcparse/macros.h"
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
#include "../../../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ifc_geom_api.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
|
||||
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#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_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API geometry_exception : public std::exception {
|
||||
protected:
|
||||
std::string message;
|
||||
public:
|
||||
geometry_exception(const std::string& m)
|
||||
: message(m) {}
|
||||
virtual ~geometry_exception() throw () {}
|
||||
virtual const char* what() const throw() {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API too_many_faces_exception : public geometry_exception {
|
||||
public:
|
||||
too_many_faces_exception()
|
||||
: geometry_exception("Too many faces for operation") {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API POSTFIX_SCHEMA(Cache) {
|
||||
public:
|
||||
#include "IfcRegisterCreateCache.h"
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API POSTFIX_SCHEMA(Kernel) : public IfcGeom::POSTFIX_SCHEMA(AbstractKernel) {
|
||||
private:
|
||||
|
||||
/*
|
||||
faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping
|
||||
M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share
|
||||
the same underlying edge but with orientation reversed. This then later speeds op the process of creating a
|
||||
manifold Shell / Solid from this set of faces. Only IfcPolyLoop instances are used. Points within the tolerance
|
||||
threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c).
|
||||
*/
|
||||
class faceset_helper {
|
||||
private:
|
||||
POSTFIX_SCHEMA(Kernel)* kernel_;
|
||||
std::set<const IfcSchema::IfcPolyLoop*> duplicates_;
|
||||
std::map<int, int> vertex_mapping_;
|
||||
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
||||
double eps_;
|
||||
bool non_manifold_;
|
||||
|
||||
template <typename Fn>
|
||||
void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) {
|
||||
if (ps->size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto a = *(ps->end() - 1);
|
||||
auto A = a->data().id();
|
||||
for (auto& b : *ps) {
|
||||
auto B = b->data().id();
|
||||
auto C = vertex_mapping_[A], D = vertex_mapping_[B];
|
||||
bool fwd = C < D;
|
||||
if (!fwd) {
|
||||
std::swap(C, D);
|
||||
}
|
||||
if (C != D) {
|
||||
callback(C, D, fwd);
|
||||
A = B;
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
faceset_helper(POSTFIX_SCHEMA(Kernel)* kernel, const IfcSchema::IfcConnectedFaceSet* l);
|
||||
|
||||
~faceset_helper();
|
||||
|
||||
bool non_manifold() const { return non_manifold_; }
|
||||
bool& non_manifold() { return non_manifold_; }
|
||||
|
||||
bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) {
|
||||
int A = vertex_mapping_[a->data().id()];
|
||||
int B = vertex_mapping_[b->data().id()];
|
||||
if (A == B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return edge(A, B, e);
|
||||
}
|
||||
|
||||
bool edge(int A, int B, TopoDS_Edge& e) {
|
||||
auto it = edges_.find({A, B});
|
||||
if (it == edges_.end()) {
|
||||
return false;
|
||||
}
|
||||
e = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) {
|
||||
if (duplicates_.find(loop) != duplicates_.end()) {
|
||||
return false;
|
||||
}
|
||||
BRep_Builder builder;
|
||||
builder.MakeWire(wire);
|
||||
int count = 0;
|
||||
auto ps = loop->Polygon();
|
||||
loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) {
|
||||
TopoDS_Edge e;
|
||||
if (edge(A, B, e)) {
|
||||
if (!fwd) {
|
||||
e.Reverse();
|
||||
}
|
||||
builder.Add(wire, e);
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
if (count >= 3) {
|
||||
wire.Closed(true);
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
if (kernel_->wire_intersections(wire, results)) {
|
||||
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", loop);
|
||||
kernel_->select_largest(results, wire);
|
||||
non_manifold_ = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
double epsilon() const {
|
||||
return eps_;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_CACHE
|
||||
POSTFIX_SCHEMA(Cache) cache;
|
||||
#endif
|
||||
|
||||
faceset_helper* faceset_helper_;
|
||||
|
||||
public:
|
||||
POSTFIX_SCHEMA(Kernel)()
|
||||
: IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade")
|
||||
, faceset_helper_(nullptr)
|
||||
{}
|
||||
|
||||
POSTFIX_SCHEMA(Kernel)(const POSTFIX_SCHEMA(Kernel)& other)
|
||||
: IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade")
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
POSTFIX_SCHEMA(Kernel)& operator=(const POSTFIX_SCHEMA(Kernel)& other) {
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
setValue(GV_MAX_FACES_TO_ORIENT, other.getValue(GV_MAX_FACES_TO_ORIENT));
|
||||
setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT));
|
||||
setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT));
|
||||
setValue(GV_PRECISION, other.getValue(GV_PRECISION));
|
||||
setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY));
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const ConversionResultPlacement* entity_trsf, ConversionResults& cut_shapes);
|
||||
void assert_closed_wire(TopoDS_Wire& wire);
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
#else
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
#endif
|
||||
|
||||
bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height);
|
||||
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
|
||||
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
|
||||
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
|
||||
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
|
||||
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
|
||||
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
|
||||
gp_Pln plane_from_face(const TopoDS_Face& face);
|
||||
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
|
||||
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
|
||||
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
|
||||
void apply_tolerance(TopoDS_Shape& s, double t);
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&, double eps=-1.);
|
||||
bool flatten_wire(TopoDS_Wire&);
|
||||
/// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire.
|
||||
bool triangulate_wire(const std::vector<TopoDS_Wire>&, TopTools_ListOfShape&);
|
||||
bool wire_intersections(const TopoDS_Wire & wire, TopTools_ListOfShape & wires);
|
||||
void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest);
|
||||
|
||||
static double shape_volume(const TopoDS_Shape& s);
|
||||
static double face_area(const TopoDS_Face& f);
|
||||
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const OpenCascadePlacement*);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*);
|
||||
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes);
|
||||
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep);
|
||||
|
||||
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
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 = POSTFIX_SCHEMA(Cache)();
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "IfcRegisterGeomHeader.h"
|
||||
|
||||
virtual IfcGeom::NativeElement<double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return create_brep_for_representation_and_product<double, double>(settings, (IfcSchema::IfcRepresentation*) representation, (IfcSchema::IfcProduct*) product);
|
||||
}
|
||||
|
||||
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
ConversionResults 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, ConversionResultPlacement*& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
gp_Trsf occt_trsf;
|
||||
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), occt_trsf)) {
|
||||
trsf = new OpenCascadePlacement(occt_trsf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,251 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 OPENCASCADEKERNEL_H
|
||||
#define OPENCASCADEKERNEL_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.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 <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
|
||||
#include "../../../ifcgeom/taxonomy.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
|
||||
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#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
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
|
||||
class IFC_GEOM_API geometry_exception : public std::exception {
|
||||
protected:
|
||||
std::string message;
|
||||
public:
|
||||
geometry_exception(const std::string& m)
|
||||
: message(m) {}
|
||||
virtual ~geometry_exception() throw () {}
|
||||
virtual const char* what() const throw() {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API too_many_faces_exception : public geometry_exception {
|
||||
public:
|
||||
too_many_faces_exception()
|
||||
: geometry_exception("Too many faces for operation") {}
|
||||
};
|
||||
|
||||
/*
|
||||
class IFC_GEOM_API POSTFIX_SCHEMA(Cache) {
|
||||
public:
|
||||
#include "IfcRegisterCreateCache.h"
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
class IFC_GEOM_API OpenCascadeKernel : public AbstractKernel {
|
||||
private:
|
||||
/*
|
||||
// faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping
|
||||
// M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share
|
||||
// the same underlying edge but with orientation reversed. This then later speeds op the process of creating a
|
||||
// manifold Shell / Solid from this set of faces. Only IfcPolyLoop instances are used. Points within the tolerance
|
||||
// threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c).
|
||||
class faceset_helper {
|
||||
private:
|
||||
OpenCascadeKernel* kernel_;
|
||||
std::set<const IfcSchema::IfcPolyLoop*> duplicates_;
|
||||
std::map<int, int> vertex_mapping_;
|
||||
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
||||
double eps_;
|
||||
bool non_manifold_;
|
||||
|
||||
template <typename Fn>
|
||||
void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) {
|
||||
if (ps->size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto a = *(ps->end() - 1);
|
||||
auto A = a->data().id();
|
||||
for (auto& b : *ps) {
|
||||
auto B = b->data().id();
|
||||
auto C = vertex_mapping_[A], D = vertex_mapping_[B];
|
||||
bool fwd = C < D;
|
||||
if (!fwd) {
|
||||
std::swap(C, D);
|
||||
}
|
||||
if (C != D) {
|
||||
callback(C, D, fwd);
|
||||
A = B;
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
faceset_helper(OpenCascadeKernel* kernel, const IfcSchema::IfcConnectedFaceSet* l);
|
||||
|
||||
~faceset_helper();
|
||||
|
||||
bool non_manifold() const { return non_manifold_; }
|
||||
bool& non_manifold() { return non_manifold_; }
|
||||
|
||||
bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) {
|
||||
int A = vertex_mapping_[a->data().id()];
|
||||
int B = vertex_mapping_[b->data().id()];
|
||||
if (A == B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return edge(A, B, e);
|
||||
}
|
||||
|
||||
bool edge(int A, int B, TopoDS_Edge& e) {
|
||||
auto it = edges_.find({ A, B });
|
||||
if (it == edges_.end()) {
|
||||
return false;
|
||||
}
|
||||
e = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) {
|
||||
if (duplicates_.find(loop) != duplicates_.end()) {
|
||||
return false;
|
||||
}
|
||||
BRep_Builder builder;
|
||||
builder.MakeWire(wire);
|
||||
int count = 0;
|
||||
auto ps = loop->Polygon();
|
||||
loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) {
|
||||
TopoDS_Edge e;
|
||||
if (edge(A, B, e)) {
|
||||
if (!fwd) {
|
||||
e.Reverse();
|
||||
}
|
||||
builder.Add(wire, e);
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
if (count >= 3) {
|
||||
wire.Closed(true);
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
if (kernel_->wire_intersections(wire, results)) {
|
||||
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", loop);
|
||||
kernel_->select_largest(results, wire);
|
||||
non_manifold_ = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
double epsilon() const {
|
||||
return eps_;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_CACHE
|
||||
POSTFIX_SCHEMA(Cache) cache;
|
||||
#endif
|
||||
*/
|
||||
|
||||
class faceset_helper {};
|
||||
|
||||
faceset_helper* faceset_helper_;
|
||||
double precision_;
|
||||
|
||||
public:
|
||||
OpenCascadeKernel()
|
||||
: AbstractKernel("opencascade")
|
||||
, faceset_helper_(nullptr) {}
|
||||
|
||||
OpenCascadeKernel(const OpenCascadeKernel& other)
|
||||
: AbstractKernel("opencascade") {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool convert(const geometry::taxonomy::extrusion&, TopoDS_Shape&);
|
||||
bool convert(const geometry::taxonomy::face&, TopoDS_Shape&);
|
||||
bool convert(const geometry::taxonomy::matrix4&, gp_Trsf&);
|
||||
bool convert(const geometry::taxonomy::direction3&, gp_Dir&);
|
||||
};
|
||||
|
||||
/*
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,19 @@
|
||||
#define BIND(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) { \
|
||||
try { \
|
||||
return map((IfcSchema::T*)l); \
|
||||
taxonomy::item* item = map((IfcSchema::T*)l); \
|
||||
item->instance = l; \
|
||||
try { \
|
||||
if (l->as<IfcSchema::IfcRepresentationItem>()) { \
|
||||
auto style = find_style(l->as<IfcSchema::IfcRepresentationItem>()); \
|
||||
if (style) { \
|
||||
((taxonomy::geom_item*)item)->surface_style = as<taxonomy::style>(map(style)); \
|
||||
} \
|
||||
} \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
} \
|
||||
return item; \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
} \
|
||||
|
||||
+632
-14
@@ -20,19 +20,69 @@
|
||||
#include "mapping.h"
|
||||
|
||||
#include "../../ifcparse/IfcLogger.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
using namespace IfcUtil;
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
taxonomy::item* mapping::map(const IfcBaseClass* l) {
|
||||
#include "bind_convert_impl.i"
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return nullptr;
|
||||
namespace {
|
||||
struct POSTFIX_SCHEMA(factory_t) {
|
||||
abstract_mapping* operator()(IfcParse::IfcFile* file) const {
|
||||
ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)* m = new ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)(file);
|
||||
return m;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void MAKE_INIT_FN(MappingImplementation)(ifcopenshell::geometry::impl::MappingFactoryImplementation* mapping) {
|
||||
static const std::string schema_name = STRINGIFY(IfcSchema);
|
||||
POSTFIX_SCHEMA(factory_t) factory;
|
||||
mapping->bind(schema_name, factory);
|
||||
}
|
||||
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
|
||||
namespace {
|
||||
// Hacks around not wanting to use if constexpr
|
||||
template <typename T>
|
||||
class loop_to_face_upgrade {
|
||||
public:
|
||||
loop_to_face_upgrade(taxonomy::item*) {}
|
||||
|
||||
operator bool() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
operator taxonomy::face() const {
|
||||
throw taxonomy::topology_error();
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
throw taxonomy::topology_error();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class loop_to_face_upgrade<taxonomy::face> {
|
||||
private:
|
||||
boost::optional<taxonomy::face> face_;
|
||||
public:
|
||||
loop_to_face_upgrade(taxonomy::item* item) {
|
||||
taxonomy::loop* loop = dynamic_cast<taxonomy::loop*>(item);
|
||||
if (loop) {
|
||||
face_ = taxonomy::face(loop->instance, loop->matrix, *loop);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return face_.is_initialized();
|
||||
}
|
||||
|
||||
operator taxonomy::face() const {
|
||||
return *face_;
|
||||
}
|
||||
};
|
||||
|
||||
// A RAII-based mechanism to cast the conversion results
|
||||
// from map() into the right type expected by the higher
|
||||
// level typology items. An exception is thrown if the
|
||||
@@ -52,33 +102,601 @@ namespace {
|
||||
as(taxonomy::item* item) : item_(item) {}
|
||||
operator T() const {
|
||||
if (!item_) {
|
||||
throw taxonomy::topology_error;
|
||||
throw taxonomy::topology_error();
|
||||
}
|
||||
T* t = dynamic_cast<T*>(item_);
|
||||
if (t) {
|
||||
return *t;
|
||||
} else {
|
||||
if constexpr (std::is_same<T, topology::face>::value) {
|
||||
topology::loop* loop = dynamic_cast<T*>(item_);
|
||||
if (loop) {
|
||||
return topology::face(loop.id, loop.matrix, *loop);
|
||||
{
|
||||
loop_to_face_upgrade<T> upgrade(item_);
|
||||
if (upgrade) {
|
||||
return upgrade;
|
||||
}
|
||||
}
|
||||
throw taxonomy::topology_error;
|
||||
throw taxonomy::topology_error();
|
||||
}
|
||||
}
|
||||
~as() {
|
||||
delete item;
|
||||
delete item_;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) {
|
||||
// @todo length unit
|
||||
return new taxonomy::extrusion(
|
||||
inst->data().id(),
|
||||
inst,
|
||||
as<taxonomy::matrix4>(map(inst->Position())),
|
||||
as<taxonomy::face>(map(inst->SweptArea())),
|
||||
as<taxonomy::direction3>(map(inst->ExtrudedDirection())),
|
||||
inst->Depth()
|
||||
);
|
||||
}
|
||||
|
||||
taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) {
|
||||
// @todo length unit
|
||||
return new taxonomy::matrix4();
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||
|
||||
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
if (maps->size() == 1) {
|
||||
IfcSchema::IfcRepresentationMap* rmap = *maps->begin();
|
||||
taxonomy::matrix4 origin = as<taxonomy::matrix4>(map(rmap->MappingOrigin()));
|
||||
if (origin.components.isIdentity()) {
|
||||
IfcSchema::IfcMappedItem::list::ptr items = rmap->MapUsage();
|
||||
for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
|
||||
IfcSchema::IfcMappedItem* item = *it;
|
||||
if (item->StyledByItem()->size() != 0) continue;
|
||||
|
||||
taxonomy::matrix4 target = as<taxonomy::matrix4>(map(item->MappingTarget()));
|
||||
if (target.components.isIdentity()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = item->data().getInverse((&IfcSchema::IfcRepresentation::Class()), -1)->as<IfcSchema::IfcRepresentation>();
|
||||
for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation* rep = *jt;
|
||||
if (rep->Items()->size() != 1) continue;
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps_mapped = rep->OfProductRepresentation();
|
||||
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps_mapped->begin(); kt != prodreps_mapped->end(); ++kt) {
|
||||
IfcSchema::IfcProduct::list::ptr ps = (*kt)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>();
|
||||
products->push(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
namespace {
|
||||
IfcSchema::IfcProduct::list::ptr filter_products(IfcSchema::IfcProduct::list::ptr unfiltered_products, std::vector<filter_t>& filters) {
|
||||
auto ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters, [prod](const filter_t& f) { return f(prod); })) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
return ifcproducts;
|
||||
}
|
||||
}
|
||||
|
||||
bool mapping::reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products) {
|
||||
// With world coords enabled, object transformations are directly applied to
|
||||
// the BRep. There is no way to re-use the geometry for multiple products.
|
||||
if (s.get(settings::USE_WORLD_COORDS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<const IfcSchema::IfcMaterial*> associated_single_materials;
|
||||
|
||||
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) {
|
||||
IfcSchema::IfcProduct* product = *it;
|
||||
|
||||
if (!s.get(settings::DISABLE_OPENING_SUBTRACTIONS) && find_openings(product)->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s.get(settings::APPLY_LAYERSETS)) {
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (assoc) {
|
||||
if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) {
|
||||
// TODO: Check whether single layer?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
|
||||
associated_single_materials.insert(get_single_material_association(product));
|
||||
if (associated_single_materials.size() > 1) return false;
|
||||
}
|
||||
|
||||
return associated_single_materials.size() == 1;
|
||||
}
|
||||
|
||||
IfcEntityList::ptr mapping::find_openings(IfcSchema::IfcProduct* product) {
|
||||
|
||||
IfcEntityList::ptr openings(new IfcEntityList);
|
||||
if (product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
||||
openings = element->HasOpenings()->generalize();
|
||||
}
|
||||
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
IfcSchema::IfcObjectDefinition* obdef = product->as<IfcSchema::IfcObjectDefinition>();
|
||||
for (;;) {
|
||||
auto decomposes = obdef->Decomposes()->generalize();
|
||||
if (decomposes->size() != 1) break;
|
||||
IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->as<IfcSchema::IfcRelAggregates>()->RelatingObject();
|
||||
if (rel_obdef->declaration().is(IfcSchema::IfcElement::Class()) && !rel_obdef->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef;
|
||||
openings->push(element->HasOpenings()->generalize());
|
||||
}
|
||||
|
||||
obdef = rel_obdef;
|
||||
}
|
||||
|
||||
return openings;
|
||||
}
|
||||
|
||||
|
||||
void mapping::get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters, settings& s) {
|
||||
IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
std::set<std::string> allowed_context_types;
|
||||
allowed_context_types.insert("model");
|
||||
allowed_context_types.insert("plan");
|
||||
allowed_context_types.insert("notdefined");
|
||||
|
||||
std::set<std::string> context_types;
|
||||
if (!s.get(settings::EXCLUDE_SOLIDS_AND_SURFACES)) {
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// Some earlier (?) versions DDS-CAD output their own ContextTypes
|
||||
context_types.insert("model view");
|
||||
context_types.insert("detail view");
|
||||
}
|
||||
if (s.get(settings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
file_->instances_by_type<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts(new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type = context->ContextType();
|
||||
boost::to_lower(context_type);
|
||||
|
||||
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
|
||||
Logger::Warning(std::string("ContextType '") + context->ContextType() + "' not allowed:", context);
|
||||
}
|
||||
if (context_types.find(context_type) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// In case no contexts are identified based on their ContextType, all contexts are
|
||||
// considered. Note that sub contexts are excluded as they are considered later on.
|
||||
if (filtered_contexts->size() == 0) {
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
}
|
||||
// There is no need for full recursion as the following is governed by the schema:
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered in relevant contexts, using all");
|
||||
representations = file_->instances_by_type<IfcSchema::IfcRepresentation>();
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations;
|
||||
|
||||
int task_index = 0;
|
||||
|
||||
for (auto representation : *representations) {
|
||||
|
||||
// Init. the list of filtered IfcProducts for this representation
|
||||
|
||||
// Include only the desired products for processing.
|
||||
IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation), filters);
|
||||
|
||||
if (ifcproducts->size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto geometry_reuse_ok_for_current_representation_ = reuse_ok_(s, ifcproducts);
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
|
||||
if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) {
|
||||
// unfiltered_products contains products represented by this representation by means of mapped items.
|
||||
// For example because of openings applied to products, reuse might not be acceptable and then the
|
||||
// products will be processed by means of their immediate representation and not the mapped representation.
|
||||
|
||||
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map
|
||||
// is indeed used by IfcMappedItems.
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (map->MapUsage()->size() > 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this represenation has (or will be) processed as part its mapped representation
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
IfcSchema::IfcRepresentation* rep_mapped_to = representation_mapped_to(representation);
|
||||
if (rep_mapped_to) {
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
|
||||
ok_mapped_representations->contains(rep_mapped_to) || reuse_ok_(s, filter_products(products_represented_by(rep_mapped_to), filters)));
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
ok_mapped_representations->push(rep_mapped_to);
|
||||
continue;
|
||||
}
|
||||
|
||||
geometry_conversion_task task;
|
||||
task.index = task_index++;
|
||||
task.representation = representation;
|
||||
task.products = ifcproducts->generalize();
|
||||
|
||||
tasks.emplace_back(task);
|
||||
}
|
||||
}
|
||||
|
||||
const IfcSchema::IfcMaterial* mapping::get_single_material_association(const IfcSchema::IfcProduct* product) {
|
||||
IfcSchema::IfcMaterial* single_material = 0;
|
||||
IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (associated_materials->size() == 1) {
|
||||
IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
|
||||
single_material = associated_material->as<IfcSchema::IfcMaterial>();
|
||||
|
||||
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
|
||||
// in accordance with other viewers.
|
||||
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
|
||||
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
|
||||
if (layerset->MaterialLayers()->size() == 1) {
|
||||
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
|
||||
if (layer->hasMaterial()) {
|
||||
single_material = layer->Material();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return single_material;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* mapping::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items();
|
||||
if (items->size() == 1) {
|
||||
IfcSchema::IfcRepresentationItem* item = *items->begin();
|
||||
if (item->declaration().is(IfcSchema::IfcMappedItem::Class())) {
|
||||
if (item->StyledByItem()->size() == 0) {
|
||||
IfcSchema::IfcMappedItem* mapped_item = item->as<IfcSchema::IfcMappedItem>();
|
||||
taxonomy::matrix4 target = as<taxonomy::matrix4>(map(mapped_item->MappingTarget()));
|
||||
if (target.components.isIdentity()) {
|
||||
IfcSchema::IfcRepresentationMap* rmap = mapped_item->MappingSource();
|
||||
taxonomy::matrix4 origin = as<taxonomy::matrix4>(map(rmap->MappingOrigin()));
|
||||
if (origin.components.isIdentity()) {
|
||||
representation_mapped_to = rmap->MappedRepresentation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return representation_mapped_to;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
|
||||
while (item->declaration().is(IfcSchema::IfcBooleanClippingResult::Class())) {
|
||||
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
|
||||
// IfcGeometricRepresentationItem
|
||||
item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand();
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
|
||||
// But neither are these very prevalent, nor does the current IfcOpenShell style
|
||||
// mechanism enable to conveniently style subshapes, which would be necessary for
|
||||
// distinctly styled union operands.
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::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);
|
||||
}
|
||||
|
||||
const IfcSchema::IfcStyledItem* find_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 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 *styled_items->begin();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taxonomy::item* mapping::map(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
return map(*it);
|
||||
}
|
||||
}
|
||||
|
||||
taxonomy::style* material_style = new taxonomy::style;
|
||||
return material_style;
|
||||
|
||||
// @todo
|
||||
// IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
|
||||
// return &(style_cache[material->data().id()] = material_style);
|
||||
}
|
||||
|
||||
taxonomy::item* mapping::map(const IfcSchema::IfcStyledItem* inst) {
|
||||
static taxonomy::colour white = taxonomy::colour(1., 1., 1.);
|
||||
|
||||
taxonomy::style* surface_style = new taxonomy::style;
|
||||
|
||||
auto style_pair = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(inst);
|
||||
|
||||
IfcSchema::IfcSurfaceStyle* style = style_pair.first;
|
||||
IfcSchema::IfcSurfaceStyleShading* shading = style_pair.second;
|
||||
|
||||
surface_style->instance = style;
|
||||
if (style->hasName()) {
|
||||
surface_style->name = style->Name();
|
||||
}
|
||||
|
||||
double rgb[3];
|
||||
if (process_colour(shading->SurfaceColour(), rgb)) {
|
||||
surface_style->diffuse.emplace();
|
||||
(*surface_style->diffuse).components << rgb[0], rgb[1], rgb[2];
|
||||
}
|
||||
|
||||
if (auto rendering_style = shading->as<IfcSchema::IfcSurfaceStyleRendering>()) {
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
const taxonomy::colour& old_diffuse = surface_style->diffuse.get_value_or(white);
|
||||
surface_style->diffuse.reset(taxonomy::colour(old_diffuse.r() * rgb[0], old_diffuse.g() * rgb[1], old_diffuse.b() * rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasDiffuseTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasReflectionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
|
||||
surface_style->specular.reset(taxonomy::colour(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style->specularity.reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
|
||||
surface_style->specularity.reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasTransparency()) {
|
||||
const double d = rendering_style->Transparency();
|
||||
surface_style->transparency.reset(d);
|
||||
}
|
||||
}
|
||||
|
||||
return surface_style;
|
||||
}
|
||||
|
||||
|
||||
taxonomy::item* mapping::map(const IfcBaseClass* l) {
|
||||
#include "bind_convert_impl.i"
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
IfcUtil::IfcBaseEntity* get_RelatingObject(IfcSchema::IfcRelDecomposes* decompose) {
|
||||
#ifdef SCHEMA_IfcRelDecomposes_HAS_RelatingObject
|
||||
return decompose->RelatingObject();
|
||||
#else
|
||||
IfcSchema::IfcRelAggregates* aggr = decompose->as<IfcSchema::IfcRelAggregates>();
|
||||
if (aggr != nullptr) {
|
||||
return aggr->RelatingObject();
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) {
|
||||
IfcSchema::IfcObjectDefinition* parent = 0;
|
||||
auto product = inst->as<IfcSchema::IfcProduct>();
|
||||
if (!product) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/* In case of an opening element, parent to the RelatingBuildingElement */
|
||||
if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
|
||||
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product;
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements();
|
||||
if (voids->size()) {
|
||||
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin();
|
||||
parent = ifc_void->RelatingBuildingElement();
|
||||
}
|
||||
} else if (product->declaration().is(IfcSchema::IfcElement::Class())) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
||||
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids();
|
||||
/* In case of a RelatedBuildingElement parent to the opening element */
|
||||
if (fills->size() && include_openings) {
|
||||
for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) {
|
||||
IfcSchema::IfcRelFillsElement* fill = *it;
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement();
|
||||
if (product == ifc_objectdef) continue;
|
||||
parent = ifc_objectdef;
|
||||
}
|
||||
}
|
||||
/* Else simply parent to the containing structure */
|
||||
if (!parent) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure();
|
||||
if (parents->size()) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin();
|
||||
parent = container->RelatingStructure();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Parent decompositions to the RelatingObject */
|
||||
if (!parent) {
|
||||
IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1);
|
||||
parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1));
|
||||
for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) {
|
||||
IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it;
|
||||
IfcUtil::IfcBaseEntity* ifc_objectdef;
|
||||
ifc_objectdef = get_RelatingObject(decompose);
|
||||
if (product == ifc_objectdef) continue;
|
||||
parent = ifc_objectdef->as<IfcSchema::IfcObjectDefinition>();
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "../abstract_mapping.h"
|
||||
#include "../../ifcparse/macros.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
@@ -13,7 +14,20 @@ namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
|
||||
class POSTFIX_SCHEMA(mapping) : public abstract_mapping {
|
||||
private:
|
||||
IfcParse::IfcFile* file_;
|
||||
public:
|
||||
POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) {}
|
||||
virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*);
|
||||
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters, settings& s);
|
||||
|
||||
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct* product);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
|
||||
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation);
|
||||
bool reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products);
|
||||
IfcEntityList::ptr find_openings(IfcSchema::IfcProduct* product);
|
||||
IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings);
|
||||
|
||||
#include "bind_convert_decl.i"
|
||||
};
|
||||
|
||||
|
||||
@@ -126,4 +126,8 @@ BIND(IfcCartesianTransformationOperator2D);
|
||||
BIND(IfcCartesianTransformationOperator3D);
|
||||
BIND(IfcObjectPlacement);
|
||||
BIND(IfcVector);
|
||||
BIND(IfcPlane);
|
||||
BIND(IfcPlane);
|
||||
|
||||
BIND(IfcColourRgb);
|
||||
BIND(IfcMaterial);
|
||||
BIND(IfcStyledItem);
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/settings.h"
|
||||
#include "../../ifcgeom/taxonomy.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
namespace Representation {
|
||||
template <typename P>
|
||||
class IFC_GEOM_API Triangulation;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API ConversionResultShape {
|
||||
public:
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const = 0;
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const = 0;
|
||||
virtual void Triangulate(const ifcopenshell::geometry::settings & settings, const ifcopenshell::geometry::ConversionResultPlacement* place, ifcopenshell::geometry::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;
|
||||
@@ -57,16 +57,16 @@ namespace IfcGeom {
|
||||
int id;
|
||||
ConversionResultPlacement* placement;
|
||||
ConversionResultShape* shape;
|
||||
const SurfaceStyle* style;
|
||||
ifcopenshell::geometry::taxonomy::style style;
|
||||
public:
|
||||
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style)
|
||||
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style)
|
||||
: id(id), placement(placement->clone()), shape(shape->clone()), style(style) {}
|
||||
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape)
|
||||
: id(id), placement(placement->clone()), shape(shape->clone()), style(0) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape, const SurfaceStyle* style)
|
||||
: id(id), placement(placement->clone()), shape(shape->clone()) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style)
|
||||
: id(id), placement(0), shape(shape->clone()), style(style) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape)
|
||||
: id(id), placement(0), shape(shape->clone()), style(0) {}
|
||||
: id(id), placement(0), shape(shape->clone()) {}
|
||||
void append(const ConversionResultPlacement* trsf) {
|
||||
if (placement == 0) {
|
||||
placement = trsf->clone();
|
||||
@@ -83,12 +83,13 @@ namespace IfcGeom {
|
||||
}
|
||||
const ConversionResultShape* Shape() const { return shape; }
|
||||
const ConversionResultPlacement* Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
|
||||
// @todo
|
||||
bool hasStyle() const { return style.diffuse.is_initialized(); }
|
||||
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<ConversionResult> ConversionResults;
|
||||
}
|
||||
}}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,413 @@
|
||||
#include "Converter.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
|
||||
ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
kernel_ = kernels::impl::kernel_implementations().construct(geometry_library, file);
|
||||
mapping_ = impl::mapping_implementations().construct(file);
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(
|
||||
const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) {
|
||||
|
||||
std::stringstream representation_id_builder;
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
// @todo
|
||||
element_settings s(settings, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product, trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
const std::string guid = product->get_value<std::string>("GlobalId");
|
||||
const std::string name = product->get_value_or<std::string>("Name", "");
|
||||
|
||||
representation_id_builder << representation->data().id();
|
||||
|
||||
ifcopenshell::geometry::Representation::BRep* shape;
|
||||
ifcopenshell::geometry::ConversionResults shapes;
|
||||
|
||||
auto rep_item = mapping_->map(representation);
|
||||
auto placement = mapping_->map(product);
|
||||
kernel_->convert(rep_item, shapes);
|
||||
|
||||
shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes);
|
||||
|
||||
return new NativeElement(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
// @todo
|
||||
"",
|
||||
trsf,
|
||||
boost::shared_ptr<ifcopenshell::geometry::Representation::BRep>(shape),
|
||||
product
|
||||
);
|
||||
|
||||
/*
|
||||
std::stringstream representation_id_builder;
|
||||
|
||||
representation_id_builder << representation->data().id();
|
||||
|
||||
ifcopenshell::geometry::kernels::Representation::BRep* shape;
|
||||
ifcopenshell::geometry::kernels::ConversionResults shapes;
|
||||
|
||||
if (!convert_shapes(representation, shapes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
|
||||
if (apply_layerset(product, shapes)) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool material_style_applied = false;
|
||||
|
||||
const IfcSchema::IfcMaterial* single_material = get_single_material_association(product);
|
||||
if (single_material) {
|
||||
const ifcopenshell::geometry::kernels::SurfaceStyle* s = get_style(single_material);
|
||||
for (ifcopenshell::geometry::kernels::ConversionResults::iterator 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 (ifcopenshell::geometry::kernels::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
if (!it->hasStyle()) {
|
||||
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();
|
||||
}
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as<IfcSchema::IfcRelVoidsElement>();
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
|
||||
|
||||
if (!settings.get(ifcopenshell::geometry::kernels::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
|
||||
representation_id_builder << "-openings";
|
||||
for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) {
|
||||
representation_id_builder << "-" << (*it)->data().id();
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::kernels::ConversionResults opened_shapes;
|
||||
bool caught_error = false;
|
||||
try {
|
||||
convert_openings(product, openings, shapes, trsf, 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(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (ifcopenshell::geometry::kernels::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
representation_id_builder << "-world-coords";
|
||||
}
|
||||
shape = new ifcopenshell::geometry::kernels::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes);
|
||||
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (ifcopenshell::geometry::kernels::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
representation_id_builder << "-world-coords";
|
||||
shape = new ifcopenshell::geometry::kernels::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
} else {
|
||||
shape = new ifcopenshell::geometry::kernels::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
|
||||
auto elem = new NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
boost::shared_ptr<ifcopenshell::geometry::kernels::Representation::BRep>(shape),
|
||||
product
|
||||
);
|
||||
|
||||
if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
|
||||
validate_quantities(product, elem->geometry());
|
||||
}
|
||||
|
||||
return elem;
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
template <typename P, typename PP>
|
||||
ifcopenshell::geometry::kernels::NativeElement<P, PP>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation(
|
||||
const IteratorSettings& //* settings /, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product,
|
||||
ifcopenshell::geometry::kernels::NativeElement<P, PP>* brep) {
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->hasName() ? product->Name() : "";
|
||||
const std::string guid = product->GlobalId();
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
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 NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
brep->geometry_pointer(),
|
||||
product
|
||||
);
|
||||
}
|
||||
*/
|
||||
//#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;
|
||||
//}
|
||||
//
|
||||
//IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() {
|
||||
// static KernelFactoryImplementation impl;
|
||||
// return impl;
|
||||
//}
|
||||
//
|
||||
//extern void init_KernelImplementation_opencascade_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
//extern void init_KernelImplementation_opencascade_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
//#ifdef IFOPSH_USE_CGAL
|
||||
//extern void init_KernelImplementation_cgal_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
//extern void init_KernelImplementation_cgal_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
//#endif
|
||||
//
|
||||
//IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
|
||||
// init_KernelImplementation_opencascade_Ifc2x3(this);
|
||||
// init_KernelImplementation_opencascade_Ifc4(this);
|
||||
//#ifdef IFOPSH_USE_CGAL
|
||||
// init_KernelImplementation_cgal_Ifc2x3(this);
|
||||
// init_KernelImplementation_cgal_Ifc4(this);
|
||||
//#endif
|
||||
//}
|
||||
//
|
||||
//void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, const std::string& geometry_library, IfcGeom::impl::kernel_fn fn) {
|
||||
// const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
// this->insert(std::make_pair(std::make_pair(schema_name_lower, geometry_library), fn));
|
||||
//}
|
||||
//
|
||||
//IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
// const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
// std::map<std::pair<std::string, std::string>, IfcGeom::impl::kernel_fn>::const_iterator it;
|
||||
// it = this->find(std::make_pair(schema_name_lower, geometry_library));
|
||||
// if (it == end()) {
|
||||
// throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
|
||||
// }
|
||||
// return it->second(file);
|
||||
//}
|
||||
//
|
||||
//
|
||||
//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());
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//namespace {
|
||||
// template <typename Schema>
|
||||
// static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers_impl(typename Schema::IfcProduct* prod) {
|
||||
// std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
|
||||
// if (prod->hasRepresentation()) {
|
||||
// IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
|
||||
// typename Schema::IfcRepresentation::list::ptr representations = r->template as<typename Schema::IfcRepresentation>();
|
||||
// for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) {
|
||||
// typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments();
|
||||
// for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
|
||||
// layers[(*jt)->Name()] = *jt;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return layers;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//std::map<std::string, IfcUtil::IfcBaseEntity*> IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) {
|
||||
// if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
// return get_layers_impl<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
|
||||
// } else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
// return get_layers_impl<Ifc4>(inst->as<Ifc4::IfcProduct>());
|
||||
// } 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;
|
||||
// }
|
||||
//}
|
||||
@@ -2,19 +2,21 @@
|
||||
#define ITERATOR_KERNEL_H
|
||||
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/settings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
#include "../../ifcgeom/abstract_mapping.h"
|
||||
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class NativeElement;
|
||||
|
||||
class Kernel {
|
||||
class Converter {
|
||||
private:
|
||||
Kernel* implementation_;
|
||||
abstract_mapping* mapping_;
|
||||
kernels::AbstractKernel* kernel_;
|
||||
|
||||
public:
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
@@ -47,10 +49,13 @@ namespace IfcGeom {
|
||||
GV_DIMENSIONALITY
|
||||
};
|
||||
|
||||
Kernel(const std::string& geometry_library, IfcParse::IfcFile* file_ = 0);
|
||||
Converter(const std::string& geometry_library, IfcParse::IfcFile* file);
|
||||
|
||||
virtual ~Kernel() {}
|
||||
~Converter() {}
|
||||
|
||||
abstract_mapping* mapping() const { return mapping_; }
|
||||
|
||||
/*
|
||||
virtual void setValue(GeomValue var, double value) {
|
||||
implementation_->setValue(var, value);
|
||||
}
|
||||
@@ -58,43 +63,42 @@ namespace IfcGeom {
|
||||
virtual double getValue(GeomValue var) const {
|
||||
return implementation_->getValue(var);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
virtual NativeElement<double, double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
*/
|
||||
|
||||
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
return implementation_->convert(item);
|
||||
ifcopenshell::geometry::ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
auto geom_item = mapping_->map(item);
|
||||
ifcopenshell::geometry::ConversionResults results;
|
||||
kernel_->convert(geom_item, results);
|
||||
return results;
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
|
||||
return implementation_->convert_placement(item, trsf);
|
||||
bool convert_placement(IfcUtil::IfcBaseClass* item, ifcopenshell::geometry::ConversionResultPlacement*& trsf) {
|
||||
throw std::runtime_error("not implemented");
|
||||
// return implementation_->convert_placement(item, trsf);
|
||||
}
|
||||
|
||||
static int count(const ConversionResultShape*, int, bool unique=false);
|
||||
static int surface_genus(const ConversionResultShape*);
|
||||
ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product);
|
||||
ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep);
|
||||
|
||||
static bool is_manifold(const ConversionResultShape*);
|
||||
/*
|
||||
static int count(const ifcopenshell::geometry::ConversionResultShape*, int, bool unique=false);
|
||||
static int surface_genus(const ifcopenshell::geometry::ConversionResultShape*);
|
||||
|
||||
static bool is_manifold(const ifcopenshell::geometry::ConversionResultShape*);
|
||||
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true);
|
||||
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
|
||||
static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product);
|
||||
*/
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
|
||||
|
||||
class KernelFactoryImplementation : public std::map<std::pair<std::string, std::string>, kernel_fn> {
|
||||
public:
|
||||
KernelFactoryImplementation();
|
||||
void bind(const std::string& schema_name, const std::string& geometry_library, kernel_fn);
|
||||
Kernel* construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile*);
|
||||
};
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -27,18 +27,17 @@
|
||||
#include "../../ifcparse/Argument.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/settings.h"
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
template <typename P>
|
||||
class Matrix {
|
||||
private:
|
||||
std::vector<P> _data;
|
||||
std::vector<double> _data;
|
||||
public:
|
||||
Matrix(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf) {
|
||||
Matrix(const element_settings& settings, const ConversionResultPlacement* 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
|
||||
@@ -49,30 +48,29 @@ namespace IfcGeom {
|
||||
const double trsf_value = (trsf == nullptr)
|
||||
? (i == j ? 1. : 0.)
|
||||
: trsf->Value(j,i);
|
||||
const double matrix_value = (i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS))
|
||||
const double matrix_value = (i == 4 && settings.get(settings::CONVERT_BACK_UNITS))
|
||||
? trsf_value / settings.unit_magnitude()
|
||||
: trsf_value;
|
||||
_data.push_back(static_cast<P>(matrix_value));
|
||||
_data.push_back(static_cast<double>(matrix_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::vector<P>& data() const { return _data; }
|
||||
const std::vector<double>& data() const { return _data; }
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Transformation {
|
||||
private:
|
||||
ElementSettings settings_;
|
||||
element_settings settings_;
|
||||
ConversionResultPlacement* trsf_;
|
||||
Matrix<P> matrix_;
|
||||
Matrix matrix_;
|
||||
public:
|
||||
Transformation(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf)
|
||||
Transformation(const element_settings& settings, const ConversionResultPlacement* trsf)
|
||||
: settings_(settings)
|
||||
, trsf_(trsf ? trsf->clone() : nullptr)
|
||||
, matrix_(settings, trsf)
|
||||
{}
|
||||
const IfcGeom::ConversionResultPlacement* data() const { return trsf_; }
|
||||
const Matrix<P>& matrix() const { return matrix_; }
|
||||
const ConversionResultPlacement* data() const { return trsf_; }
|
||||
const Matrix& matrix() const { return matrix_; }
|
||||
|
||||
Transformation inverted() const {
|
||||
return Transformation(settings_, trsf_->inverted());
|
||||
@@ -83,7 +81,6 @@ namespace IfcGeom {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class Element {
|
||||
private:
|
||||
int _id;
|
||||
@@ -93,17 +90,17 @@ namespace IfcGeom {
|
||||
std::string _guid;
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation<PP> _transformation;
|
||||
Transformation _transformation;
|
||||
IfcUtil::IfcBaseEntity* product_;
|
||||
std::vector<const IfcGeom::Element<P, PP>*> _parents;
|
||||
std::vector<const Element*> _parents;
|
||||
public:
|
||||
|
||||
friend bool operator == (const Element<P, PP> & element1, const Element<P, PP> & element2) {
|
||||
friend bool operator == (const Element & element1, const Element & element2) {
|
||||
return element1.id() == element2.id();
|
||||
}
|
||||
|
||||
// Use the id to compare, or the elevation is the elements are IfcBuildingStoreys and the elevation is set
|
||||
friend bool operator < (const Element<P, PP> & element1, const Element<P, PP> & element2) {
|
||||
friend bool operator < (const Element & element1, const Element & element2) {
|
||||
if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") {
|
||||
size_t attr_index = element1.product()->declaration().attribute_index("Elevation");
|
||||
Argument* elev_attr1 = element1.product()->data().getArgument(attr_index);
|
||||
@@ -127,13 +124,13 @@ namespace IfcGeom {
|
||||
const std::string& guid() const { return _guid; }
|
||||
const std::string& context() const { return _context; }
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation<PP>& transformation() const { return _transformation; }
|
||||
const Transformation& transformation() const { return _transformation; }
|
||||
IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const std::vector<const IfcGeom::Element<P, PP>*> parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element<P, PP>*> newparents) { _parents = newparents; }
|
||||
const std::vector<const Element*> parents() const { return _parents; }
|
||||
void SetParents(std::vector<const 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 IfcGeom::ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product)
|
||||
Element(const element_settings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
, product_(product)
|
||||
{
|
||||
@@ -162,17 +159,16 @@ namespace IfcGeom {
|
||||
virtual ~Element() {}
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class NativeElement : public Element<P, PP> {
|
||||
class NativeElement : public Element {
|
||||
private:
|
||||
boost::shared_ptr<Representation::BRep> _geometry;
|
||||
public:
|
||||
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
|
||||
const Representation::BRep& geometry() const { return *_geometry; }
|
||||
NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
IfcUtil::IfcBaseEntity* product)
|
||||
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
|
||||
: Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
|
||||
@@ -184,19 +180,18 @@ namespace IfcGeom {
|
||||
NativeElement& operator=(const NativeElement& other);
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class TriangulationElement : public Element<P, PP> {
|
||||
class TriangulationElement : public Element {
|
||||
private:
|
||||
boost::shared_ptr< Representation::Triangulation<P> > _geometry;
|
||||
boost::shared_ptr<Representation::Triangulation> _geometry;
|
||||
public:
|
||||
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
|
||||
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
|
||||
TriangulationElement(const NativeElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
|
||||
const Representation::Triangulation& geometry() const { return *_geometry; }
|
||||
const boost::shared_ptr< Representation::Triangulation >& geometry_pointer() const { return _geometry; }
|
||||
TriangulationElement(const NativeElement& shape_model)
|
||||
: Element(shape_model)
|
||||
, _geometry(boost::shared_ptr<Representation::Triangulation >(new Representation::Triangulation(shape_model.geometry())))
|
||||
{}
|
||||
TriangulationElement(const Element<P, PP>& element, const boost::shared_ptr<Representation::Triangulation<P> >& geometry)
|
||||
: Element<P, PP>(element)
|
||||
TriangulationElement(const Element& element, const boost::shared_ptr<Representation::Triangulation >& geometry)
|
||||
: Element(element)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
private:
|
||||
@@ -204,14 +199,13 @@ namespace IfcGeom {
|
||||
TriangulationElement& operator=(const TriangulationElement& other);
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class SerializedElement : public Element<P, PP> {
|
||||
class SerializedElement : public Element {
|
||||
private:
|
||||
Representation::Serialization* _geometry;
|
||||
public:
|
||||
const Representation::Serialization& geometry() const { return *_geometry; }
|
||||
SerializedElement(const NativeElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
SerializedElement(const NativeElement& shape_model)
|
||||
: Element(shape_model)
|
||||
, _geometry(new Representation::Serialization(shape_model.geometry()))
|
||||
{}
|
||||
virtual ~SerializedElement() {
|
||||
@@ -221,6 +215,6 @@ namespace IfcGeom {
|
||||
SerializedElement(const SerializedElement& other);
|
||||
SerializedElement& operator=(const SerializedElement& other);
|
||||
};
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
#ifndef IFCGEOMFILTER_H
|
||||
#define IFCGEOMFILTER_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/abstract_mapping.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function.hpp>
|
||||
@@ -65,7 +66,11 @@ 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.
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file);
|
||||
while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) {
|
||||
if (pred(parent)) {
|
||||
return true;
|
||||
}
|
||||
@@ -170,7 +175,8 @@ namespace IfcGeom {
|
||||
: wildcard_filter(include, traverse, patterns) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
layer_map_t layers = IfcGeom::Kernel::get_layers(prod);
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file);
|
||||
layer_map_t layers = mapping->get_layers(prod);
|
||||
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,130 +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 {
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class 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<P, PP>* implementation_;
|
||||
|
||||
public:
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade", int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
|
||||
}
|
||||
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, const std::string& geometry_library = "opencascade", int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
, filters_(filters)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
|
||||
}
|
||||
|
||||
bool initialize() {
|
||||
return implementation_->initialize();
|
||||
}
|
||||
|
||||
int progress() const { return implementation_->progress(); }
|
||||
|
||||
void compute_bounds() { implementation_->compute_bounds(); }
|
||||
|
||||
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<P, PP>* get() { return implementation_->get(); }
|
||||
|
||||
NativeElement<P, PP>* get_native() { return implementation_->get_native(); }
|
||||
|
||||
const Element<P, PP>* get_object(int id) { return implementation_->get_object(id); }
|
||||
|
||||
IfcUtil::IfcBaseClass* create() { return implementation_->create(); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
#include "IfcGeomIteratorImplementation.h"
|
||||
@@ -0,0 +1,617 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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). *
|
||||
* *
|
||||
* ifcopenshell::geometry::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 *
|
||||
* *
|
||||
* ifcopenshell::geometry::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 *
|
||||
* *
|
||||
* ifcopenshell::geometry::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* ifcopenshell::geometry::Iterator::get() *
|
||||
* returns a pointer to the current ifcopenshell::geometry::Element *
|
||||
* *
|
||||
* ifcopenshell::geometry::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* ifcopenshell::geometry::Iterator::get() *
|
||||
* *
|
||||
* ifcopenshell::geometry::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#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/macros.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../ifcgeom/settings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
|
||||
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/Converter.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
#include <atomic>
|
||||
|
||||
// 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 {
|
||||
ifcopenshell::geometry::Element* process_based_on_settings(
|
||||
const ifcopenshell::geometry::settings& settings,
|
||||
ifcopenshell::geometry::NativeElement* elem,
|
||||
ifcopenshell::geometry::TriangulationElement* previous=nullptr)
|
||||
{
|
||||
if (settings.get(ifcopenshell::geometry::settings::USE_BREP_DATA)) {
|
||||
try {
|
||||
return new ifcopenshell::geometry::SerializedElement(*elem);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
return nullptr;
|
||||
}
|
||||
} else if (!settings.get(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION)) {
|
||||
try {
|
||||
if (!previous) {
|
||||
return new ifcopenshell::geometry::TriangulationElement(*elem);
|
||||
} else {
|
||||
return new ifcopenshell::geometry::TriangulationElement(*elem, previous->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
void create_element(
|
||||
ifcopenshell::geometry::Converter* converter,
|
||||
const ifcopenshell::geometry::settings& settings,
|
||||
ifcopenshell::geometry::geometry_conversion_task* rep)
|
||||
{
|
||||
IfcUtil::IfcBaseEntity* representation = rep->representation;
|
||||
IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *rep->products->begin();
|
||||
auto brep = converter->create_brep_for_representation_and_product(settings, representation, product);
|
||||
if (!brep) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto elem = process_based_on_settings(settings, brep);
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
rep->breps = { brep };
|
||||
rep->elements = { elem };
|
||||
|
||||
for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) {
|
||||
auto brep2 = converter->create_brep_for_processed_representation(settings, representation, (IfcUtil::IfcBaseEntity*) *it, brep);
|
||||
if (brep2) {
|
||||
auto elem2 = process_based_on_settings(settings, brep, dynamic_cast<ifcopenshell::geometry::TriangulationElement*>(elem));
|
||||
if (elem2) {
|
||||
rep->breps.push_back(brep2);
|
||||
rep->elements.push_back(elem2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
|
||||
int num_threads_;
|
||||
std::atomic<int> progress_;
|
||||
std::vector<geometry_conversion_task> tasks_;
|
||||
std::vector<geometry_conversion_task>::iterator task_iterator_;
|
||||
|
||||
std::vector<ifcopenshell::geometry::Element*> all_processed_elements_;
|
||||
std::vector<ifcopenshell::geometry::NativeElement*> all_processed_native_elements_;
|
||||
size_t task_result_index_;
|
||||
|
||||
std::string geometry_library_;
|
||||
|
||||
Iterator(const Iterator&); // N/I
|
||||
Iterator& operator=(const Iterator&); // N/I
|
||||
|
||||
Converter* converter_;
|
||||
settings settings_;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
std::string unit_name;
|
||||
double unit_magnitude;
|
||||
|
||||
gp_XYZ bounds_min_;
|
||||
gp_XYZ bounds_max_;
|
||||
|
||||
std::vector<filter_t> filters_;
|
||||
|
||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
||||
public:
|
||||
|
||||
bool initialize() {
|
||||
converter_->mapping()->get_representations(tasks_, filters_, settings_);
|
||||
|
||||
if (tasks_.size() == 0) {
|
||||
Logger::Warning("No representations encountered, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
task_iterator_ = tasks_.begin();
|
||||
|
||||
done = 0;
|
||||
total = tasks_.size();
|
||||
|
||||
if (num_threads_ != 1) {
|
||||
process_concurrently();
|
||||
} else {
|
||||
if (!create()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void process_concurrently() {
|
||||
size_t conc_threads = num_threads_;
|
||||
if (conc_threads > tasks_.size()) {
|
||||
conc_threads = tasks_.size();
|
||||
}
|
||||
|
||||
std::vector<Converter*> kernel_pool;
|
||||
kernel_pool.reserve(conc_threads);
|
||||
for (unsigned i = 0; i < conc_threads; ++i) {
|
||||
kernel_pool.push_back(new Converter(geometry_library_, ifc_file));
|
||||
}
|
||||
|
||||
std::vector<std::future<void>> threadpool;
|
||||
|
||||
int old_progress = -1;
|
||||
int processed = 0;
|
||||
|
||||
Logger::ProgressBar(0);
|
||||
|
||||
for (auto& rep : tasks_) {
|
||||
Converter* K = nullptr;
|
||||
if (threadpool.size() < kernel_pool.size()) {
|
||||
K = kernel_pool[threadpool.size()];
|
||||
}
|
||||
|
||||
while (threadpool.size() == conc_threads) {
|
||||
for (int i = 0; i < (int)threadpool.size(); i++) {
|
||||
std::future<void> &fu = threadpool[i];
|
||||
std::future_status status;
|
||||
status = fu.wait_for(std::chrono::seconds(0));
|
||||
if (status == std::future_status::ready) {
|
||||
fu.get();
|
||||
|
||||
processed += 1;
|
||||
progress_ = processed * 50 / tasks_.size();
|
||||
if (progress_ != old_progress) {
|
||||
Logger::ProgressBar(progress_);
|
||||
old_progress = progress_;
|
||||
}
|
||||
|
||||
std::swap(threadpool[i], threadpool.back());
|
||||
threadpool.pop_back();
|
||||
std::swap(kernel_pool[i], kernel_pool.back());
|
||||
K = kernel_pool.back();
|
||||
break;
|
||||
} // if
|
||||
} // for
|
||||
} // while
|
||||
|
||||
std::future<void> fu = std::async(std::launch::async, create_element, K, std::ref(settings_), &rep);
|
||||
threadpool.emplace_back(std::move(fu));
|
||||
}
|
||||
|
||||
for (std::future<void> &fu : threadpool) {
|
||||
fu.get();
|
||||
|
||||
processed += 1;
|
||||
progress_ = processed * 50 / tasks_.size();
|
||||
if (progress_ != old_progress) {
|
||||
Logger::ProgressBar(progress_);
|
||||
old_progress = progress_;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& rep : tasks_) {
|
||||
all_processed_elements_.insert(all_processed_elements_.end(), rep.elements.begin(), rep.elements.end());
|
||||
all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep.breps.begin(), rep.breps.end());
|
||||
}
|
||||
|
||||
task_result_index_ = 0;
|
||||
|
||||
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
|
||||
" objects) ");
|
||||
}
|
||||
|
||||
/// Computes model's bounding box (bounds_min and bounds_max).
|
||||
/// @note Can take several minutes for large files.
|
||||
void compute_bounds()
|
||||
{
|
||||
// @todo
|
||||
|
||||
/*
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
|
||||
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type<IfcSchema::IfcProduct>();
|
||||
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
|
||||
IfcSchema::IfcProduct* product = *iter;
|
||||
if (product->hasObjectPlacement()) {
|
||||
// Use a fresh trsf every time in order to prevent the result to be concatenated
|
||||
ConversionResultPlacement* trsf;
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
success = kernel->convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double X, Y, Z;
|
||||
trsf->TranslationPart(X, Y, Z);
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), X));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), Y));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), Z));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), X));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), Y));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), Z));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int progress() const {
|
||||
if (num_threads_ == 1) {
|
||||
return 100 * done / total;
|
||||
} else {
|
||||
return progress_;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& getUnitName() const { return unit_name; }
|
||||
|
||||
/// @note Double always as per IFC specification.
|
||||
double getUnitMagnitude() const { return unit_magnitude; }
|
||||
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return ifc_file; }
|
||||
|
||||
const std::vector<ifcopenshell::geometry::filter_t>& filters() const { return filters_; }
|
||||
std::vector<ifcopenshell::geometry::filter_t>& filters() { return filters_; }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
||||
const gp_XYZ& bounds_max() const { return bounds_max_; }
|
||||
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
++task_iterator_;
|
||||
++done;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() {
|
||||
geometry_conversion_task* task = nullptr;
|
||||
while (task_iterator_ != tasks_.end()) {
|
||||
task = &*task_iterator_++;
|
||||
create_element(converter_, settings_, task);
|
||||
if (task->elements.empty()) {
|
||||
task = nullptr;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (task) {
|
||||
all_processed_elements_.insert(all_processed_elements_.end(), task->elements.begin(), task->elements.end());
|
||||
all_processed_native_elements_.insert(all_processed_native_elements_.end(), task->breps.begin(), task->breps.end());
|
||||
return (*task->products)[0];
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
IfcUtil::IfcBaseClass* next() {
|
||||
if (num_threads_ != 1) {
|
||||
task_result_index_++;
|
||||
if (task_result_index_ == all_processed_elements_.size()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return all_processed_elements_[task_result_index_]->product();
|
||||
}
|
||||
} else {
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
++task_result_index_;
|
||||
if (task_result_index_ == all_processed_elements_.size()) {
|
||||
return create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the representation of the current geometrical entity.
|
||||
Element* get()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
Element* ret = 0;
|
||||
|
||||
ret = all_processed_elements_[task_result_index_];
|
||||
|
||||
// If we want to organize the element considering their hierarchy
|
||||
if (settings_.get(settings::SEARCH_FLOOR))
|
||||
{
|
||||
// We are going to build a vector with the element parents.
|
||||
// First, create the parent vector
|
||||
std::vector<const ifcopenshell::geometry::Element*> parents;
|
||||
|
||||
// if the element has a parent
|
||||
if (ret->parent_id() != -1)
|
||||
{
|
||||
const ifcopenshell::geometry::Element* parent_object = NULL;
|
||||
bool hasParent = true;
|
||||
|
||||
// get the parent
|
||||
try {
|
||||
parent_object = get_object(ret->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
// We need to find all the parents
|
||||
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1)
|
||||
{
|
||||
// Find the next parent
|
||||
try {
|
||||
parent_object = get_object(parent_object->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
// Add the previously found parent to the vector
|
||||
if (hasParent) parents.insert(parents.begin(), parent_object);
|
||||
|
||||
hasParent = hasParent && parent_object->parent_id() != -1;
|
||||
}
|
||||
|
||||
// when done push the parent list in the Element object
|
||||
ret->SetParents(parents);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
NativeElement* get_native()
|
||||
{
|
||||
return all_processed_native_elements_[task_result_index_];
|
||||
}
|
||||
|
||||
const Element* get_object(int id) {
|
||||
// @todo
|
||||
return nullptr;
|
||||
/*
|
||||
ConversionResultPlacement* trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcSchema::IfcProduct* ifc_product = 0;
|
||||
|
||||
try {
|
||||
IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id);
|
||||
instance_type = ifc_entity->declaration().name();
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) {
|
||||
IfcSchema::IfcRoot* ifc_root = ifc_entity->as<IfcSchema::IfcRoot>();
|
||||
product_guid = ifc_root->GlobalId();
|
||||
product_name = ifc_root->hasName() ? ifc_root->Name() : "";
|
||||
}
|
||||
|
||||
if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) {
|
||||
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to find decomposing entity");
|
||||
}
|
||||
|
||||
try {
|
||||
kernel->convert_placement(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
}
|
||||
} 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 returning product");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error returning product");
|
||||
}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
|
||||
Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product);
|
||||
return ifc_object;
|
||||
*/
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* create() {
|
||||
IfcUtil::IfcBaseClass* product = nullptr;
|
||||
try {
|
||||
product = create_shape_model_for_next_entity();
|
||||
} 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 geometry");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating geometry");
|
||||
}
|
||||
return product;
|
||||
}
|
||||
private:
|
||||
void _initialize() {
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
// @todo
|
||||
|
||||
/*
|
||||
kernel->setValue(ifcopenshell::geometry::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(settings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel->setValue(ifcopenshell::geometry::Kernel::GV_DIMENSIONALITY, (settings.get(settings::INCLUDE_CURVES)
|
||||
? (settings.get(settings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
|
||||
if (settings.get(settings::BUILDING_LOCAL_PLACEMENT)) {
|
||||
if (settings.get(settings::SITE_LOCAL_PLACEMENT)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
|
||||
}
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
|
||||
} else if (settings.get(settings::SITE_LOCAL_PLACEMENT)) {
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool owns_ifc_file;
|
||||
public:
|
||||
Iterator(const std::string& geometry_library, const settings& settings, IfcParse::IfcFile* file, const std::vector<ifcopenshell::geometry::filter_t>& filters, int num_threads)
|
||||
: settings_(settings)
|
||||
, ifc_file(file)
|
||||
, filters_(filters)
|
||||
, owns_ifc_file(false)
|
||||
, num_threads_(num_threads)
|
||||
, geometry_library_(geometry_library)
|
||||
{
|
||||
_initialize();
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
if (owns_ifc_file) {
|
||||
delete ifc_file;
|
||||
}
|
||||
|
||||
if (settings_.get(settings::DISABLE_TRIANGULATION)) {
|
||||
for (auto& p : all_processed_native_elements_) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& p : all_processed_elements_) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +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.};
|
||||
|
||||
IfcGeom::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
|
||||
bool IfcGeom::Material::hasDiffuse() const { return style->Diffuse() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecular() const { return style->Specular() ? true : false; }
|
||||
bool IfcGeom::Material::hasTransparency() const { return style->Transparency() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecularity() const { return 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->Name(); }
|
||||
const std::string &IfcGeom::Material::original_name() const { return style->original_name(); }
|
||||
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
|
||||
@@ -1,51 +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 "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
explicit Material(const IfcGeom::SurfaceStyle* style = 0); // TODO default constructor for vector?
|
||||
// Material(const Material& other);
|
||||
// Material& operator=(const Material& other);
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
#include "../../ifcgeom/taxonomy.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
@@ -29,72 +30,7 @@
|
||||
#include <sstream>
|
||||
|
||||
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);
|
||||
boost::replace_all(sanitized, " ", "-");
|
||||
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; }
|
||||
|
||||
/// 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; }
|
||||
boost::optional<ColorComponent>& Diffuse() { return diffuse; }
|
||||
boost::optional<ColorComponent>& Specular() { return specular; }
|
||||
boost::optional<double>& Transparency() { return transparency; }
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
};
|
||||
|
||||
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API const ifcopenshell::geometry::taxonomy::style& get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API void set_default_style_file(const std::string& json_file);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
#ifndef IFCGEOMREPRESENTATION_H
|
||||
#define IFCGEOMREPRESENTATION_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../../ifcgeom/settings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
@@ -34,37 +33,37 @@ namespace IfcGeom {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings settings_;
|
||||
const element_settings settings_;
|
||||
public:
|
||||
explicit Representation(const ElementSettings& settings)
|
||||
explicit Representation(const element_settings& settings)
|
||||
: settings_(settings)
|
||||
{}
|
||||
const ElementSettings& settings() const { return settings_; }
|
||||
const element_settings& settings() const { return settings_; }
|
||||
virtual ~Representation() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
const IfcGeom::ConversionResults shapes_;
|
||||
const ifcopenshell::geometry::ConversionResults shapes_;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes)
|
||||
BRep(const element_settings& settings, const std::string& id, const ifcopenshell::geometry::ConversionResults& shapes)
|
||||
: Representation(settings)
|
||||
, id_(id)
|
||||
, shapes_(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
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_; }
|
||||
ifcopenshell::geometry::ConversionResults::const_iterator begin() const { return shapes_.begin(); }
|
||||
ifcopenshell::geometry::ConversionResults::const_iterator end() const { return shapes_.end(); }
|
||||
const ifcopenshell::geometry::ConversionResults& shapes() const { return shapes_; }
|
||||
const std::string& id() const { return id_; }
|
||||
IfcGeom::ConversionResultShape* as_compound(bool force_meters = false) const;
|
||||
ifcopenshell::geometry::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 IfcGeom::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const;
|
||||
bool calculate_projected_surface_area(const ifcopenshell::geometry::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
@@ -84,57 +83,55 @@ namespace IfcGeom {
|
||||
Serialization& operator=(const Serialization&);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Triangulation : public Representation {
|
||||
private:
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
|
||||
typedef typename std::pair<double, std::pair<double, double> > Coordinate;
|
||||
typedef typename std::pair<int, Coordinate> VertexKey;
|
||||
typedef std::map<VertexKey, int> VertexKeyMap;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
std::string id_;
|
||||
std::vector<P> _verts;
|
||||
std::vector<double> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<double> _normals;
|
||||
std::vector<double> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style> _materials;
|
||||
VertexKeyMap welds;
|
||||
|
||||
public:
|
||||
const std::string& id() const { return id_; }
|
||||
const std::vector<P>& verts() const { return _verts; }
|
||||
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<P>& normals() const { return _normals; }
|
||||
const std::vector<P>& uvs() const { return uvs_; }
|
||||
const std::vector<double>& normals() const { return _normals; }
|
||||
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)
|
||||
: Representation(shape_model.settings())
|
||||
, id_(shape_model.id())
|
||||
{
|
||||
for ( IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
for ( ifcopenshell::geometry::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(&iit->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style>::const_iterator 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);
|
||||
if (settings().get(ifcopenshell::geometry::settings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
const ifcopenshell::geometry::taxonomy::style& material = IfcGeom::get_default_style(settings().element_type());
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
@@ -150,16 +147,16 @@ namespace IfcGeom {
|
||||
|
||||
/// Generates UVs for a single mesh using box projection.
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
|
||||
static std::vector<double> box_project_uvs(const std::vector<double> &vertices, const std::vector<double> &normals)
|
||||
{
|
||||
std::vector<P> uvs;
|
||||
std::vector<double> uvs;
|
||||
uvs.resize(vertices.size() / 3 * 2);
|
||||
for (size_t uv_idx = 0, v_idx = 0;
|
||||
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
|
||||
uv_idx += 2, v_idx += 3) {
|
||||
|
||||
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
double n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
double v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
|
||||
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_z;
|
||||
@@ -181,13 +178,13 @@ namespace IfcGeom {
|
||||
public:
|
||||
|
||||
// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, P X, P Y, P Z) {
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
X = static_cast<P>(convert ? (X / settings().unit_magnitude()) : X);
|
||||
Y = static_cast<P>(convert ? (Y / settings().unit_magnitude()) : Y);
|
||||
Z = static_cast<P>(convert ? (Z / settings().unit_magnitude()) : Z);
|
||||
int addVertex(int material_index, double X, double Y, double Z) {
|
||||
const bool convert = settings().get(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS);
|
||||
X = static_cast<double>(convert ? (X / settings().unit_magnitude()) : X);
|
||||
Y = static_cast<double>(convert ? (Y / settings().unit_magnitude()) : Y);
|
||||
Z = static_cast<double>(convert ? (Z / settings().unit_magnitude()) : Z);
|
||||
int i = (int) _verts.size() / 3;
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
if (settings().get(ifcopenshell::geometry::settings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
@@ -207,7 +204,7 @@ namespace IfcGeom {
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
|
||||
inline void addNormal(P X, P Y, P Z) {
|
||||
inline void addNormal(double X, double Y, double Z) {
|
||||
_normals.push_back(X);
|
||||
_normals.push_back(Y);
|
||||
_normals.push_back(Z);
|
||||
@@ -233,6 +230,6 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#include "IteratorImplementation.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>& iterator_implementations() {
|
||||
static IteratorFactoryImplementation<P, PP> impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
template IteratorFactoryImplementation<float, float>& iterator_implementations<float, float>();
|
||||
template IteratorFactoryImplementation<float, double>& iterator_implementations<float, double>();
|
||||
template IteratorFactoryImplementation<double, double>& iterator_implementations<double, double>();
|
||||
|
||||
template <typename P, typename PP>
|
||||
extern void init_IteratorImplementation_Ifc2x3(IteratorFactoryImplementation<P, PP>*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
extern void init_IteratorImplementation_Ifc4(IteratorFactoryImplementation<P, PP>*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>::IteratorFactoryImplementation() {
|
||||
init_IteratorImplementation_Ifc2x3(this);
|
||||
init_IteratorImplementation_Ifc4(this);
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
typename std::map<std::string, typename get_factory_type<P, PP>::type>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == this->end()) {
|
||||
throw IfcParse::IfcException("No geometry iterator registered for " + schema_name);
|
||||
}
|
||||
return it->second(geometry_library, settings, file, filters, num_threads);
|
||||
}
|
||||
|
||||
|
||||
template class IteratorFactoryImplementation<float, float>;
|
||||
template class IteratorFactoryImplementation<float, double>;
|
||||
template class IteratorFactoryImplementation<double, double>;
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef ITERATOR_IMPLEMENTATION_H
|
||||
#define ITERATOR_IMPLEMENTATION_H
|
||||
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
|
||||
#include <gp_XYZ.hxx>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace IfcGeom {
|
||||
template <typename P, typename PP>
|
||||
class IteratorImplementation;
|
||||
|
||||
template <typename P, typename PP>
|
||||
class Element;
|
||||
|
||||
template <typename P, typename PP>
|
||||
class NativeElement;
|
||||
}
|
||||
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<float, float>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<float, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<double, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
|
||||
|
||||
template <typename P, typename PP>
|
||||
struct get_factory_type {};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<float, float> {
|
||||
typedef iterator_float_float_fn type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<float, double> {
|
||||
typedef iterator_float_double_fn type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_factory_type<double, double> {
|
||||
typedef iterator_double_double_fn type;
|
||||
};
|
||||
|
||||
template <typename P, typename PP>
|
||||
class IteratorFactoryImplementation : public std::map<std::string, typename get_factory_type<P, PP>::type> {
|
||||
public:
|
||||
IteratorFactoryImplementation();
|
||||
void bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn);
|
||||
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
|
||||
};
|
||||
|
||||
template <typename P, typename PP>
|
||||
IteratorFactoryImplementation<P, PP>& iterator_implementations();
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class IteratorImplementation {
|
||||
public:
|
||||
virtual bool initialize() = 0;
|
||||
virtual void compute_bounds() = 0;
|
||||
virtual const gp_XYZ& bounds_min() const = 0;
|
||||
virtual const gp_XYZ& bounds_max() const = 0;
|
||||
virtual int progress() const = 0;
|
||||
virtual const std::string& getUnitName() const = 0;
|
||||
virtual double getUnitMagnitude() const = 0;
|
||||
virtual IfcParse::IfcFile* file() const = 0;
|
||||
virtual IfcUtil::IfcBaseClass* next() = 0;
|
||||
virtual Element<P, PP>* get() = 0;
|
||||
virtual NativeElement<P, PP>* get_native() = 0;
|
||||
virtual const Element<P, PP>* get_object(int id) = 0;
|
||||
virtual IfcUtil::IfcBaseClass* create() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,268 +0,0 @@
|
||||
#include "Kernel.h"
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() {
|
||||
static KernelFactoryImplementation impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
extern void init_KernelImplementation_opencascade_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_opencascade_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
#ifdef IFOPSH_USE_CGAL
|
||||
extern void init_KernelImplementation_cgal_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_cgal_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
#endif
|
||||
|
||||
IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
|
||||
init_KernelImplementation_opencascade_Ifc2x3(this);
|
||||
init_KernelImplementation_opencascade_Ifc4(this);
|
||||
#ifdef IFOPSH_USE_CGAL
|
||||
init_KernelImplementation_cgal_Ifc2x3(this);
|
||||
init_KernelImplementation_cgal_Ifc4(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, const std::string& geometry_library, IfcGeom::impl::kernel_fn fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(std::make_pair(schema_name_lower, geometry_library), fn));
|
||||
}
|
||||
|
||||
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
std::map<std::pair<std::string, std::string>, IfcGeom::impl::kernel_fn>::const_iterator it;
|
||||
it = this->find(std::make_pair(schema_name_lower, geometry_library));
|
||||
if (it == end()) {
|
||||
throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
|
||||
}
|
||||
return it->second(file);
|
||||
}
|
||||
|
||||
#define CREATE_GET_DECOMPOSING_ENTITY(IfcSchema) \
|
||||
\
|
||||
IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product, bool include_openings) {\
|
||||
IfcSchema::IfcObjectDefinition* parent = 0; \
|
||||
\
|
||||
/* In case of an opening element, parent to the RelatingBuildingElement */ \
|
||||
if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \
|
||||
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; \
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); \
|
||||
if (voids->size()) { \
|
||||
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); \
|
||||
parent = ifc_void->RelatingBuildingElement(); \
|
||||
} \
|
||||
} else if (product->declaration().is(IfcSchema::IfcElement::Class())) { \
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; \
|
||||
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); \
|
||||
/* In case of a RelatedBuildingElement parent to the opening element */ \
|
||||
if (fills->size() && include_openings) { \
|
||||
for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { \
|
||||
IfcSchema::IfcRelFillsElement* fill = *it; \
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); \
|
||||
if (product == ifc_objectdef) continue; \
|
||||
parent = ifc_objectdef; \
|
||||
} \
|
||||
} \
|
||||
/* Else simply parent to the containing structure */ \
|
||||
if (!parent) { \
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); \
|
||||
if (parents->size()) { \
|
||||
IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); \
|
||||
parent = container->RelatingStructure(); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Parent decompositions to the RelatingObject */ \
|
||||
if (!parent) { \
|
||||
IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); \
|
||||
parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); \
|
||||
for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { \
|
||||
IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; \
|
||||
IfcUtil::IfcBaseEntity* ifc_objectdef; \
|
||||
\
|
||||
ifc_objectdef = get_RelatingObject(decompose); \
|
||||
\
|
||||
if (product == ifc_objectdef) continue; \
|
||||
parent = ifc_objectdef->as<IfcSchema::IfcObjectDefinition>(); \
|
||||
} \
|
||||
} \
|
||||
return parent; \
|
||||
}
|
||||
|
||||
namespace {
|
||||
IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc4::IfcRelDecomposes* decompose) {
|
||||
Ifc4::IfcRelAggregates* aggr = decompose->as<Ifc4::IfcRelAggregates>();
|
||||
if (aggr != nullptr) {
|
||||
return aggr->RelatingObject();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc2x3::IfcRelDecomposes* decompose) {
|
||||
return decompose->RelatingObject();
|
||||
}
|
||||
|
||||
CREATE_GET_DECOMPOSING_ENTITY(Ifc2x3);
|
||||
CREATE_GET_DECOMPOSING_ENTITY(Ifc4);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename Schema>
|
||||
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers_impl(typename Schema::IfcProduct* prod) {
|
||||
std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
|
||||
if (prod->hasRepresentation()) {
|
||||
IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
|
||||
typename Schema::IfcRepresentation::list::ptr representations = r->template as<typename Schema::IfcRepresentation>();
|
||||
for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) {
|
||||
typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments();
|
||||
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
|
||||
layers[(*jt)->Name()] = *jt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, IfcUtil::IfcBaseEntity*> IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) {
|
||||
if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
return get_layers_impl<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
|
||||
} else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
return get_layers_impl<Ifc4>(inst->as<Ifc4::IfcProduct>());
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename Schema>
|
||||
IfcEntityList::ptr find_openings_helper(typename Schema::IfcProduct* product) {
|
||||
|
||||
typename IfcEntityList::ptr openings(new IfcEntityList);
|
||||
if (product->declaration().is(Schema::IfcElement::Class()) && !product->declaration().is(Schema::IfcOpeningElement::Class())) {
|
||||
typename Schema::IfcElement* element = (typename Schema::IfcElement*)product;
|
||||
openings = element->HasOpenings()->generalize();
|
||||
}
|
||||
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
typename Schema::IfcObjectDefinition* obdef = product->template as<typename Schema::IfcObjectDefinition>();
|
||||
for (;;) {
|
||||
auto decomposes = obdef->Decomposes()->generalize();
|
||||
if (decomposes->size() != 1) break;
|
||||
typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->template as<typename Schema::IfcRelAggregates>()->RelatingObject();
|
||||
if (rel_obdef->declaration().is(Schema::IfcElement::Class()) && !rel_obdef->declaration().is(Schema::IfcOpeningElement::Class())) {
|
||||
typename Schema::IfcElement* element = (typename Schema::IfcElement*)rel_obdef;
|
||||
openings->push(element->HasOpenings()->generalize());
|
||||
}
|
||||
|
||||
obdef = rel_obdef;
|
||||
}
|
||||
|
||||
return openings;
|
||||
}
|
||||
}
|
||||
|
||||
IfcEntityList::ptr IfcGeom::Kernel::find_openings(IfcUtil::IfcBaseEntity* inst) {
|
||||
if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
return find_openings_helper<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
|
||||
} else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
return find_openings_helper<Ifc4>(inst->as<Ifc4::IfcProduct>());
|
||||
} else {
|
||||
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
|
||||
}
|
||||
}
|
||||
@@ -7,49 +7,49 @@
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
static 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", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.65));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSlab", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.4, 0.4, 0.4));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWall", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWindow", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.75));
|
||||
default_materials["IfcWindow"].transparency.reset(0.3);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcDoor", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.55, 0.3, 0.15));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcBeam", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.7, 0.7));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcRailing", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcMember", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcPlate", 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.reset(ifcopenshell::geometry::taxonomy::colour(0.8, 0.8, 0.8));
|
||||
|
||||
default_material = 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.reset(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) {
|
||||
boost::optional<ifcopenshell::geometry::taxonomy::colour> read_colour_component(const boost::optional<pt::ptree&> list) {
|
||||
if (!list) {
|
||||
return boost::none;
|
||||
}
|
||||
@@ -65,7 +65,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) {
|
||||
@@ -78,46 +78,45 @@ 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, 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.reset(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");
|
||||
}
|
||||
}
|
||||
|
||||
// Is "*" present? If yes, remove it and make it the default style.
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find("*");
|
||||
std::map<std::string, ifcopenshell::geometry::taxonomy::style>::const_iterator it = default_materials.find("*");
|
||||
if (it != default_materials.end()) {
|
||||
IfcGeom::SurfaceStyle star = it->second;
|
||||
default_material.Diffuse() = star.Diffuse();
|
||||
default_material.Specular() = star.Specular();
|
||||
default_material.Specularity() = star.Specularity();
|
||||
default_material.Transparency() = star.Transparency();
|
||||
ifcopenshell::geometry::taxonomy::style star = it->second;
|
||||
default_material.diffuse = star.diffuse;
|
||||
default_material.specular = star.specular;
|
||||
default_material.specularity = star.specularity;
|
||||
default_material.transparency = star.transparency;
|
||||
default_materials.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
const ifcopenshell::geometry::taxonomy::style& IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
std::map<std::string, ifcopenshell::geometry::taxonomy::style>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse() = default_material.Diffuse();
|
||||
default_materials[s].Specular() = default_material.Specular();
|
||||
default_materials[s].Specularity() = default_material.Specularity();
|
||||
default_materials[s].Transparency() = default_material.Transparency();
|
||||
default_materials.insert(std::make_pair(s, ifcopenshell::geometry::taxonomy::style(s)));
|
||||
default_materials[s].diffuse = default_material.diffuse;
|
||||
default_materials[s].specular = default_material.specular;
|
||||
default_materials[s].specularity = default_material.specularity;
|
||||
default_materials[s].transparency = default_material.transparency;
|
||||
it = default_materials.find(s);
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -36,75 +36,76 @@
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
|
||||
class OpenCascadePlacement : public ConversionResultPlacement {
|
||||
public:
|
||||
OpenCascadePlacement(const gp_GTrsf& trsf)
|
||||
: trsf_(trsf) {}
|
||||
class OpenCascadePlacement : public ConversionResultPlacement {
|
||||
public:
|
||||
OpenCascadePlacement(const gp_GTrsf& trsf)
|
||||
: trsf_(trsf) {}
|
||||
|
||||
const gp_GTrsf& trsf() const { return trsf_; }
|
||||
operator const gp_GTrsf& () { return trsf_; }
|
||||
const gp_GTrsf& trsf() const { return trsf_; }
|
||||
operator const gp_GTrsf& () { return trsf_; }
|
||||
|
||||
virtual double Value(int i, int j) const {
|
||||
return trsf_.Value(i, j);
|
||||
}
|
||||
virtual double Value(int i, int j) const {
|
||||
return trsf_.Value(i, j);
|
||||
}
|
||||
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new OpenCascadePlacement(trsf_);
|
||||
}
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new OpenCascadePlacement(trsf_);
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* inverted() const {
|
||||
return new OpenCascadePlacement(trsf_.Inverted());
|
||||
}
|
||||
virtual ConversionResultPlacement* inverted() const {
|
||||
return new OpenCascadePlacement(trsf_.Inverted());
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement* other) const {
|
||||
return new OpenCascadePlacement(trsf_.Multiplied(((OpenCascadePlacement*)other)->trsf_));
|
||||
}
|
||||
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement* other) const {
|
||||
return new OpenCascadePlacement(trsf_.Multiplied(((OpenCascadePlacement*)other)->trsf_));
|
||||
}
|
||||
|
||||
virtual void TranslationPart(double& X, double& Y, double& Z) const {
|
||||
X = trsf_.TranslationPart().X();
|
||||
Y = trsf_.TranslationPart().Y();
|
||||
Z = trsf_.TranslationPart().Z();
|
||||
}
|
||||
private:
|
||||
gp_GTrsf trsf_;
|
||||
};
|
||||
|
||||
class OpenCascadeShape : public ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape)
|
||||
{}
|
||||
virtual void TranslationPart(double& X, double& Y, double& Z) const {
|
||||
X = trsf_.TranslationPart().X();
|
||||
Y = trsf_.TranslationPart().Y();
|
||||
Z = trsf_.TranslationPart().Z();
|
||||
}
|
||||
private:
|
||||
gp_GTrsf trsf_;
|
||||
};
|
||||
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
class OpenCascadeShape : public ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape) {}
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const;
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const;
|
||||
virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation<float>* t, int surface_style_id) const;
|
||||
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation<double>* t, int surface_style_id) const;
|
||||
|
||||
virtual ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual int surface_genus() const;
|
||||
private:
|
||||
TopoDS_Shape shape_;
|
||||
};
|
||||
|
||||
virtual ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
|
||||
virtual int surface_genus() const;
|
||||
private:
|
||||
TopoDS_Shape shape_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,14 +20,17 @@
|
||||
#ifndef IFCGEOMITERATORSETTINGS_H
|
||||
#define IFCGEOMITERATORSETTINGS_H
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../../ifcparse/IfcException.h"
|
||||
#include "../../ifcparse/IfcBaseClass.h"
|
||||
#include "../../ifcparse/IfcLogger.h"
|
||||
// #include "ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom
|
||||
{
|
||||
class IFC_GEOM_API IteratorSettings
|
||||
#define IFC_GEOM_API
|
||||
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
|
||||
namespace ifcopenshell { namespace geometry {
|
||||
|
||||
class IFC_GEOM_API settings
|
||||
{
|
||||
public:
|
||||
/// Enumeration of setting identifiers. These settings define the
|
||||
@@ -93,7 +96,7 @@ namespace IfcGeom
|
||||
/// Used to store logical OR combination of setting flags.
|
||||
typedef unsigned SettingField;
|
||||
|
||||
IteratorSettings()
|
||||
settings()
|
||||
: settings_(WELD_VERTICES) // OR options that default to true here
|
||||
, deflection_tolerance_(1.e-3)
|
||||
{
|
||||
@@ -136,13 +139,13 @@ namespace IfcGeom
|
||||
double deflection_tolerance_;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ElementSettings : public IteratorSettings
|
||||
class IFC_GEOM_API element_settings : public settings
|
||||
{
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
element_settings(const settings& s,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
: settings(s)
|
||||
, unit_magnitude_(unit_magnitude)
|
||||
, element_type_(element_type)
|
||||
{
|
||||
@@ -155,6 +158,7 @@ namespace IfcGeom
|
||||
double unit_magnitude_;
|
||||
std::string element_type_;
|
||||
};
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
+106
-19
@@ -1,6 +1,17 @@
|
||||
#ifndef TAXONOMY_H
|
||||
#define TAXONOMY_H
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <exception>
|
||||
#include <cstdalign>
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
@@ -8,11 +19,16 @@ namespace geometry {
|
||||
|
||||
namespace taxonomy {
|
||||
|
||||
struct item {
|
||||
int instance_id;
|
||||
virtual item* clone() const = 0;
|
||||
enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE, COLOUR, STYLE };
|
||||
|
||||
item(int id) : instance_id(id) {}
|
||||
struct item {
|
||||
const IfcUtil::IfcBaseClass* instance;
|
||||
virtual item* clone() const = 0;
|
||||
virtual kinds kind() const = 0;
|
||||
|
||||
item(const IfcUtil::IfcBaseClass* instance = nullptr) : instance(instance) {}
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
struct matrix4 : public item {
|
||||
@@ -20,53 +36,94 @@ struct matrix4 : public item {
|
||||
IDENTITY, AFFINE_WO_SCALE, AFFINE_W_UNIFORM_SCALE, AFFINE_W_NONUNIFORM_SCALE, OTHER
|
||||
};
|
||||
tag_t tag;
|
||||
std::array<double, 16> components;
|
||||
matrix4() : components({1. ,0., 0., 0., 0., 1., 0., 0., 0., 0., 1. ,0., 0., 0., 0., 1.}), tag(IDENTITY) {}
|
||||
|
||||
Eigen::Matrix4d components;
|
||||
|
||||
matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {}
|
||||
|
||||
virtual item* clone() const { return new matrix4(*this); }
|
||||
virtual kinds kind() const { return MATRIX4; }
|
||||
};
|
||||
|
||||
struct colour : public item {
|
||||
Eigen::Vector3d components;
|
||||
|
||||
virtual item* clone() const { return new colour(*this); }
|
||||
virtual kinds kind() const { return COLOUR; }
|
||||
|
||||
colour() : components(Eigen::Vector3d::Zero()) {}
|
||||
colour(double r, double g, double b) { components << r, g, b; }
|
||||
|
||||
const double& r() const { return components[0]; }
|
||||
const double& g() const { return components[1]; }
|
||||
const double& b() const { return components[2]; }
|
||||
};
|
||||
|
||||
struct style : public item {
|
||||
// @todo this is not very efficient wrt alignment
|
||||
boost::optional<std::string> name;
|
||||
boost::optional<colour> diffuse;
|
||||
boost::optional<colour> specular;
|
||||
boost::optional<double> specularity, transparency;
|
||||
|
||||
virtual item* clone() const { return new style(*this); }
|
||||
virtual kinds kind() const { return STYLE; }
|
||||
|
||||
// @todo equality implementation based on values?
|
||||
bool operator==(const style& other) const { return instance == other.instance; }
|
||||
|
||||
style() {}
|
||||
style(const std::string& name) : name(name) {}
|
||||
};
|
||||
|
||||
struct geom_item : public item {
|
||||
// geometry::style surface_style;
|
||||
style surface_style;
|
||||
matrix4 matrix;
|
||||
|
||||
geom_item(int id) : item(id) {}
|
||||
geom_item(int id, matrix4 m) : item(id), matrix(m) {}
|
||||
geom_item(const IfcUtil::IfcBaseClass* instance = nullptr) : item(instance) {}
|
||||
geom_item(const IfcUtil::IfcBaseClass* instance, matrix4 m) : item(instance), matrix(m) {}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct cartesian_base : public geom_item {
|
||||
std::array<double, N> components;
|
||||
Eigen::Vector3d components;
|
||||
|
||||
cartesian_base(double x, double y, double z = 0.) : components{ {x, y, z} } {}
|
||||
cartesian_base() : components(Eigen::Vector3d::Zero()) {}
|
||||
cartesian_base(double x, double y, double z = 0.) { components << x, y, z; }
|
||||
};
|
||||
|
||||
struct point3 : public cartesian_base<3> {
|
||||
virtual item* clone() const { return new point3(*this); }
|
||||
virtual kinds kind() const { return POINT3; }
|
||||
|
||||
point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {}
|
||||
};
|
||||
|
||||
struct direction3 : public cartesian_base<3> {
|
||||
virtual item* clone() const { return new direction3(*this); }
|
||||
virtual kinds kind() const { return DIRECTION3; }
|
||||
|
||||
direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {}
|
||||
};
|
||||
|
||||
struct line : public geom_item {
|
||||
virtual item* clone() const { return new line(*this); }
|
||||
virtual kinds kind() const { return LINE; }
|
||||
};
|
||||
|
||||
struct circle : public geom_item {
|
||||
virtual item* clone() const { return new circle(*this); }
|
||||
virtual kinds kind() const { return CIRCLE; }
|
||||
};
|
||||
|
||||
struct ellipse : public geom_item {
|
||||
virtual item* clone() const { return new ellipse(*this); }
|
||||
virtual kinds kind() const { return ELLIPSE; }
|
||||
};
|
||||
|
||||
struct bspline : public geom_item {
|
||||
virtual item* clone() const { return new bspline(*this); }
|
||||
virtual kinds kind() const { return BSPLINE; }
|
||||
};
|
||||
|
||||
typedef boost::variant<line, circle, ellipse, bspline> curve;
|
||||
@@ -76,12 +133,14 @@ struct edge : public geom_item {
|
||||
boost::optional<curve> basis;
|
||||
|
||||
virtual item* clone() const { return new edge(*this); }
|
||||
virtual kinds kind() const { return EDGE; }
|
||||
};
|
||||
|
||||
struct loop : public geom_item {
|
||||
std::vector<edge> edges;
|
||||
|
||||
virtual item* clone() const { return new loop(*this); }
|
||||
virtual kinds kind() const { return LOOP; }
|
||||
};
|
||||
|
||||
struct face : public geom_item {
|
||||
@@ -89,18 +148,19 @@ struct face : public geom_item {
|
||||
std::vector<loop> inner;
|
||||
|
||||
virtual item* clone() const { return new face(*this); }
|
||||
virtual kinds kind() const { return FACE; }
|
||||
|
||||
face(int id, loop o) : geom_item(id), outer(o) {}
|
||||
face(int id, loop o, std::vector<loop> i) : geom_item(id), outer(o), inner(i) {}
|
||||
face(int id, matrix4 m, loop o) : geom_item(id, m), outer(o) {}
|
||||
face(int id, matrix4 m, loop o, std::vector<loop> i) : geom_item(id, m), outer(o), inner(i) {}
|
||||
face(const IfcUtil::IfcBaseClass* instance, loop o) : geom_item(instance), outer(o) {}
|
||||
face(const IfcUtil::IfcBaseClass* instance, loop o, std::vector<loop> i) : geom_item(instance), outer(o), inner(i) {}
|
||||
face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o) : geom_item(instance, m), outer(o) {}
|
||||
face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o, std::vector<loop> i) : geom_item(instance, m), outer(o), inner(i) {}
|
||||
};
|
||||
|
||||
struct sweep : public geom_item {
|
||||
face basis;
|
||||
|
||||
sweep(int id, face b) : geom_item(id), basis(b) {}
|
||||
sweep(int id, matrix4 m, face b) : geom_item(id, m), basis(b) {}
|
||||
sweep(const IfcUtil::IfcBaseClass* instance, face b) : geom_item(instance), basis(b) {}
|
||||
sweep(const IfcUtil::IfcBaseClass* instance, matrix4 m, face b) : geom_item(instance, m), basis(b) {}
|
||||
};
|
||||
|
||||
struct extrusion : public sweep {
|
||||
@@ -108,11 +168,36 @@ struct extrusion : public sweep {
|
||||
double depth;
|
||||
|
||||
virtual item* clone() const { return new extrusion(*this); }
|
||||
extrusion(int id, matrix4 m, face basis, direction3 dir, double d) : sweep(id, m, basis), direction(dir), depth(d) {}
|
||||
virtual kinds kind() const { return EXTRUSION; }
|
||||
|
||||
extrusion(const IfcUtil::IfcBaseClass* instance, matrix4 m, face basis, direction3 dir, double d) : sweep(instance, m, basis), direction(dir), depth(d) {}
|
||||
};
|
||||
|
||||
struct node : public geom_item {
|
||||
std::map<std::string, geom_item*> representations;
|
||||
std::vector<node*> children;
|
||||
|
||||
virtual item* clone() const { return new node(*this); }
|
||||
virtual kinds kind() const { return NODE; }
|
||||
|
||||
node(const IfcUtil::IfcBaseClass* instance, matrix4 m, const std::map<std::string, geom_item*>& representations, const std::vector<node*>& children) : geom_item(instance, m), representations(representations), children(children) {}
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
// enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE };
|
||||
typedef std::tuple<matrix4, point3, direction3, line, circle, ellipse, bspline, edge, loop, face, extrusion, node> KindsTuple;
|
||||
}
|
||||
|
||||
struct type_by_kind {
|
||||
template <std::size_t N>
|
||||
using type = typename std::tuple_element<N, impl::KindsTuple>::type;
|
||||
|
||||
static const size_t max = std::tuple_size< impl::KindsTuple>::value;
|
||||
};
|
||||
|
||||
class topology_error : public std::runtime_error {
|
||||
|
||||
public:
|
||||
topology_error() : std::runtime_error("Generic topology error") {}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -122,3 +207,5 @@ class topology_error : public std::runtime_error {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user