diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a96c523bc1..27f4159424 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -427,7 +427,8 @@ IF(MSVC) ENDIF() # Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66)) - add_definitions(-permissive-) + # @todo currently fails + # add_definitions(-permissive-) endif() # Link against the static VC runtime # TODO Make this configurable diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 1c174dae13..3d426b9d67 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -182,6 +182,7 @@ int main(int argc, char** argv) exclusion_traverse_filter exclude_traverse_filter; std::string filter_filename; std::string default_material_filename; + std::string geometry_kernel; po::options_description ifc_options("IFC options"); ifc_options.add_options() @@ -190,6 +191,8 @@ int main(int argc, char** argv) po::options_description geom_options("Geometry options"); geom_options.add_options() + ("kernel", po::value(&geometry_kernel)->default_value("opencascade"), + "Geometry kernel to use (opencascade or cgal).") ("plan", "Specifies whether to include curves in the output result. Typically " "these are representations of type Plan or Axis. Excluded by default.") @@ -652,7 +655,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, "cgal"); + IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, geometry_kernel); if (!context_iterator.initialize()) { /// @todo It would be nice to know and print separate error prints for a case where we found no entities /// and for a case we found no entities that satisfy our filtering criteria. diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp new file mode 100644 index 0000000000..41e4ad5689 --- /dev/null +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -0,0 +1,557 @@ +#include "AbstractKernel.h" + +#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_WIRE_CREATION_TOLERANCE: + wire_creation_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_WIRE_CREATION_TOLERANCE: + return wire_creation_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(); + if (associated_materials->size() == 1) { + IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); + single_material = associated_material->as(); + + // 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::IfcMaterialLayerSet* layerset = associated_material->as()->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(); + 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::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(); + 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(); + 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; + } + } + + // 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 + std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { +#ifdef USE_IFC4 + 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(0, 0); + } + + template + std::pair 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()) { + return _get_surface_style(representation_item->as()); + } + 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(*styled_items->begin()); + } + return std::make_pair(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(colour_or_factor), rgb); + } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { + return process_colour(static_cast(colour_or_factor), rgb); + } else { + return false; + } + } +} + +const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) { + return internalize_surface_style(get_surface_style(item)); +} + +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()); + } + for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { + const std::pair ss = get_surface_style(*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& shading_styles) { + if (shading_styles.second == 0) { + return 0; + } + int surface_style_id = shading_styles.first->data().id(); + std::map::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::IfcSurfaceStyleShading* shading = shading_styles.second->as(); + + 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(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 +IfcGeom::NativeElement* 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(); + 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()) { + 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(); + + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + boost::shared_ptr(shape), + product + ); + + if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { + validate_quantities(product, elem->geometry()); + } + + return elem; +} + +template +IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, + IfcGeom::NativeElement* brep) { + int parent_id = -1; + try { + IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); + if (parent_object && parent_object->as()) { + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + brep->geometry_pointer(), + product + ); +} + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h new file mode 100644 index 0000000000..a88431c4ce --- /dev/null +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -0,0 +1,74 @@ +#ifndef ABSTRACT_KERNEL_H +#define ABSTRACT_KERNEL_H + +#include "../../ifcparse/macros.h" +#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h" +#include "../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" + +#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) +#include INCLUDE_SCHEMA(IfcSchema) +#undef INCLUDE_SCHEMA + +namespace IfcGeom { + + class IFC_GEOM_API MAKE_TYPE_NAME(AbstractKernel) : public IfcGeom::Kernel { + protected: + // For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) + const IfcParse::declaration* placement_rel_to; + + double deflection_tolerance; + double wire_creation_tolerance; + double point_equality_tolerance; + double max_faces_to_sew; + double ifc_length_unit; + double ifc_planeangle_unit; + double modelling_precision; + double dimensionality; + + std::map style_cache; + + public: + MAKE_TYPE_NAME(AbstractKernel)(const std::string& geometry_library) + : IfcGeom::Kernel(geometry_library, nullptr) + , deflection_tolerance(0.001) + , wire_creation_tolerance(0.0001) + , point_equality_tolerance(0.00001) + , max_faces_to_sew(-1.0) + , ifc_length_unit(1.0) + , ifc_planeangle_unit(-1.0) + , modelling_precision(0.00001) + , dimensionality(1.) + , 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; + + 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& shading_style); + + template + IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + + template + IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp index 6bc2225c0f..2c9e313eef 100644 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp @@ -1,5 +1,4 @@ #include "IfcGeomIteratorImplementation.h" -#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" namespace IfcGeom { template class MAKE_TYPE_NAME(IteratorImplementation_); diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h index 0f1577eab0..a93b1186cf 100644 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h @@ -73,9 +73,9 @@ #include #include +#include "../../ifcparse/macros.h" #include "../../ifcparse/IfcFile.h" -#include "../../ifcgeom/kernels/opencascade/IfcGeom.h" #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" #include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" @@ -84,7 +84,11 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h" #include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" -#include "../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h" + +#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) +#include INCLUDE_SCHEMA(IfcSchema) +#undef INCLUDE_SCHEMA // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -103,7 +107,7 @@ namespace IfcGeom { 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(Kernel)* kernel; + MAKE_TYPE_NAME(AbstractKernel)* kernel; IteratorSettings settings; IfcParse::IfcFile* ifc_file; @@ -265,11 +269,11 @@ namespace IfcGeom { IfcSchema::IfcProduct* product = *iter; if (product->hasObjectPlacement()) { // Use a fresh trsf every time in order to prevent the result to be concatenated - gp_Trsf trsf; + ConversionResultPlacement* trsf; bool success = false; try { - success = kernel->convert(product->ObjectPlacement(), trsf); + success = kernel->convert_placement(product->ObjectPlacement(), trsf); } catch (const std::exception& e) { Logger::Error(e); } catch (...) { @@ -280,13 +284,14 @@ namespace IfcGeom { continue; } - const gp_XYZ& pos = trsf.TranslationPart(); - bounds_min_.SetX(std::min(bounds_min_.X(), pos.X())); - bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y())); - bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z())); - bounds_max_.SetX(std::max(bounds_max_.X(), pos.X())); - bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y())); - bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z())); + 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)); } } } @@ -311,13 +316,6 @@ namespace IfcGeom { private: // Move to the next IfcRepresentation void _nextShape() { - // In order to conserve memory and reduce cache insertion times, the cache is - // cleared after an arbitrary number of processed representations. This has been - // benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47 - static const int clear_interval = 64; - if (done % clear_interval == clear_interval - 1) { - kernel->purge_cache(); - } ifcproducts.reset(); ++ representation_iterator; ++ done; @@ -554,7 +552,7 @@ namespace IfcGeom { } const Element* get_object(int id) { - gp_Trsf trsf; + ConversionResultPlacement* trsf; int parent_id = -1; std::string instance_type, product_name, product_guid; IfcSchema::IfcProduct* ifc_product = 0; @@ -584,7 +582,7 @@ namespace IfcGeom { } try { - kernel->convert(ifc_product->ObjectPlacement(), trsf); + kernel->convert_placement(ifc_product->ObjectPlacement(), trsf); } catch (const std::exception& e) { Logger::Error(e); } catch (...) { @@ -605,7 +603,7 @@ namespace IfcGeom { ElementSettings element_settings(settings, unit_magnitude, instance_type); - Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", new OpenCascadePlacement(trsf), ifc_product); + Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product); return ifc_object; } @@ -685,7 +683,7 @@ namespace IfcGeom { , filters_(filters) , owns_ifc_file(false) { - kernel = (MAKE_TYPE_NAME(Kernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file); + kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file); // kernel = new Kernel(geometry_library, file); _initialize(); } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 5983748042..e796e39f01 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -36,7 +36,7 @@ void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplem #define CgalKernel MAKE_TYPE_NAME(CgalKernel) -bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { +bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()"); return false; /* @@ -80,154 +80,15 @@ bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { */ } -template -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) -{ - IfcGeom::Representation::BRep* shape; - IfcGeom::ConversionResults shapes, shapes2; - - if (!convert_shapes(representation, shapes)) { - return 0; - } - - if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { - Logger::Message(Logger::LOG_ERROR, "Not implemented APPLY_LAYERSETS"); - } - - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - cgal_placement_t trsf; - try { - // convert(product->ObjectPlacement(), trsf); - } catch (...) {} - - std::stringstream representation_id_builder; - representation_id_builder << representation->data().id(); - - // Does the IfcElement have any IfcOpenings? - // Note that openings for IfcOpeningElements are not processed - IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as(); - - 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()) { - Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); - } - - 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(); - } - - return new NativeElement( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new CgalPlacement(trsf), - boost::shared_ptr(shape), - product - ); +bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { + throw std::runtime_error("not implemented"); } -template -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) -{ - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - cgal_placement_t trsf; - try { - // convert(product->ObjectPlacement(), trsf); - } catch (...) {} - - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new CgalPlacement(trsf), - brep->geometry_pointer(), - product - ); +bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { + throw std::runtime_error("not implemented"); } -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); - - -void IfcGeom::CgalKernel::setValue(GeomValue var, double value) { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - deflection_tolerance = value; - break; - case GV_DIMENSIONALITY: - dimensionality = value; - break; - default: - throw std::runtime_error("Not implemented for this kernel"); - } +bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { + throw std::runtime_error("not implemented"); } -double IfcGeom::CgalKernel::getValue(GeomValue var) const { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - return deflection_tolerance; - case GV_DIMENSIONALITY: - return dimensionality; - } - throw std::runtime_error("Not implemented for this kernel"); -} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 86f878fd4c..3a6be54476 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -36,6 +36,9 @@ if ( it != cache.T.end() ) { e = it->second; return true; } */ #include "../../../ifcparse/macros.h" + +#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h" + #include "../../../ifcgeom/schema_agnostic/Kernel.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" @@ -55,10 +58,11 @@ namespace IfcGeom { std::map Shape; }; - class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public Kernel { + class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) { public: - MAKE_TYPE_NAME(CgalKernel)() : Kernel("cgal") {} + MAKE_TYPE_NAME(CgalKernel)() + : MAKE_TYPE_NAME(AbstractKernel)("cgal") {} #ifndef NO_CACHE CgalCache cache; @@ -72,9 +76,6 @@ namespace IfcGeom { bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); - virtual void setValue(GeomValue var, double value); - virtual double getValue(GeomValue var) const; - // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); void purge_cache() { @@ -86,16 +87,10 @@ namespace IfcGeom { #endif } - virtual bool is_identity_transform(IfcUtil::IfcBaseClass*); - - template - IfcGeom::NativeElement* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - - template - IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); - + 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); + 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); #include "CgalEntityMappingDeclaration.h" diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h index c3f933ad27..9af42283ec 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -52,6 +52,8 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #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" @@ -108,7 +110,7 @@ public: std::map Shape; }; -class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel { +class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::MAKE_TYPE_NAME(AbstractKernel) { private: /* @@ -203,46 +205,23 @@ private: double epsilon() const { return eps_; } - }; - - double deflection_tolerance; - double wire_creation_tolerance; - double point_equality_tolerance; - double max_faces_to_sew; - double ifc_length_unit; - double ifc_planeangle_unit; - double modelling_precision; - double dimensionality; + }; #ifndef NO_CACHE MAKE_TYPE_NAME(Cache) cache; #endif - std::map style_cache; - - const SurfaceStyle* internalize_surface_style(const std::pair& shading_style); - - // For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) - const IfcParse::declaration* placement_rel_to; - faceset_helper* faceset_helper_; public: MAKE_TYPE_NAME(Kernel)() - : IfcGeom::Kernel("opencascade", 0) - , deflection_tolerance(0.001) - , wire_creation_tolerance(0.0001) - , point_equality_tolerance(0.00001) - , max_faces_to_sew(-1.0) - , ifc_length_unit(1.0) - , ifc_planeangle_unit(-1.0) - , modelling_precision(0.00001) - , dimensionality(1.) - , placement_rel_to(0) + : IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade") , faceset_helper_(nullptr) {} - MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) : IfcGeom::Kernel(0) { + MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) + : IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade") + { *this = other; } @@ -267,8 +246,7 @@ public: 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 gp_Trsf& entity_trsf, ConversionResults& cut_shapes); - bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + 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&, std::vector&, std::vector&); @@ -302,8 +280,6 @@ public: bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end); - IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item); - const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item); bool 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); @@ -332,91 +308,25 @@ public: static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&); static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&); - bool is_identity_transform(IfcUtil::IfcBaseClass*); + 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 initializeUnits(IfcSchema::IfcUnitAssignment*); - template - IfcGeom::NativeElement* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - - template - IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); - - 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*); - - template std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { -#ifdef USE_IFC4 - 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(0,0); - } - - template std::pair 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()) { - return _get_surface_style(representation_item->as()); - } - 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(*styled_items->begin()); - } - return std::make_pair(0,0); - } - - void purge_cache() { + void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control // for large files. SurfaceStyles need to be kept at all costs, as they // are read later on when serializing Collada files. #ifndef NO_CACHE cache = MAKE_TYPE_NAME(Cache)(); #endif - } - - void set_conversion_placement_rel_to(const IfcParse::declaration* type); + } #include "IfcRegisterGeomHeader.h" - virtual void setValue(GeomValue var, double value); - virtual double getValue(GeomValue var) const; - virtual IfcGeom::NativeElement* convert( const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation, IfcUtil::IfcBaseClass* product) @@ -433,12 +343,15 @@ public: return items; } - virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) { + virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { if (item->as()) { - return convert(item->as(), trsf); - } else { - return false; + gp_Trsf occt_trsf; + if (convert(item->as(), occt_trsf)) { + trsf = new OpenCascadePlacement(occt_trsf); + return true; + } } + return false; } }; diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 5bc687e718..66819ef849 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -506,259 +506,6 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha return solid; } -bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { - - // TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use - // the same code base and conform to the same checks and logging messages. - - // Iterate over IfcOpeningElements - IfcGeom::ConversionResults opening_shapes; - unsigned int last_size = 0; - for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { - IfcSchema::IfcRelVoidsElement* v = *it; - IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - if (!fes->hasRepresentation()) continue; - - // Convert the IfcRepresentation of the IfcOpeningElement - gp_Trsf opening_trsf; - if (fes->hasObjectPlacement()) { - try { - convert(fes->ObjectPlacement(),opening_trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - } - - // Move the opening into the coordinate system of the IfcProduct - opening_trsf.PreMultiply(entity_trsf.Inverted()); - - IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); - IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - - for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { - convert_shapes(*it2,opening_shapes); - } - - const unsigned int current_size = (const unsigned int) opening_shapes.size(); - for ( unsigned int i = last_size; i < current_size; ++ i ) { - OpenCascadePlacement p((gp_GTrsf)opening_trsf); - opening_shapes[i].prepend(&p); - } - last_size = current_size; - } - } - - // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { - TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it3->Shape(), entity_shape_solid); - const OpenCascadePlacement* entity_shape_gtrsf = (OpenCascadePlacement*) it3->Placement(); - - TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); - - // Iterate over the shapes of the IfcOpeningElements - for ( IfcGeom::ConversionResults::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { - TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it4->Shape(),opening_shape_solid); - const OpenCascadePlacement* opening_shape_gtrsf = (OpenCascadePlacement*)it4->Placement(); - TopoDS_Shape opening_shape = apply_transformation(opening_shape_unlocated, opening_shape_gtrsf); - - double opening_volume; - if (Logger::LOG_WARNING >= Logger::Verbosity()) { - opening_volume = shape_volume(opening_shape); - if ( opening_volume <= ALMOST_ZERO ) - Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity); - } - - if (entity_shape.ShapeType() == TopAbs_COMPSOLID) { - - // For compound solids process the subtraction for the constituent - // solids individually and write the result back as a compound solid. - - TopoDS_CompSolid compound; - BRep_Builder builder; - builder.MakeCompSolid(compound); - - TopExp_Explorer exp(entity_shape, TopAbs_SOLID); - - for (; exp.More(); exp.Next()) { - -#if OCC_VERSION_HEX < 0x60900 - BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape); -#else - BRepAlgoAPI_Cut brep_cut; - TopTools_ListOfShape s1s; - s1s.Append(exp.Current()); - TopTools_ListOfShape s2s; - s2s.Append(opening_shape); - brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); - brep_cut.SetArguments(s1s); - brep_cut.SetTools(s2s); - brep_cut.Build(); -#endif - - bool added = false; - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - BRepCheck_Analyzer analyser(brep_cut_result); - bool is_valid = analyser.IsValid() != 0; - if (is_valid) { - TopExp_Explorer exp2(brep_cut_result, TopAbs_SOLID); - for (; exp2.More(); exp2.Next()) { - builder.Add(compound, exp2.Current()); - added = true; - } - } - } - if (!added) { - // Add the original in case subtraction fails - builder.Add(compound, exp.Current()); - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity); - } - } - - entity_shape = compound; - - } else { -#if OCC_VERSION_HEX < 0x60900 - BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); -#else - BRepAlgoAPI_Cut brep_cut; - TopTools_ListOfShape s1s; - s1s.Append(entity_shape); - TopTools_ListOfShape s2s; - s2s.Append(opening_shape); - brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); - brep_cut.SetArguments(s1s); - brep_cut.SetTools(s2s); - brep_cut.Build(); -#endif - - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - - ShapeFix_Shape fix(brep_cut_result); - try { - fix.Perform(); - brep_cut_result = fix.Shape(); - } catch (...) { - Logger::Error("Shape healing failed on opening subtraction result", entity); - } - - BRepCheck_Analyzer analyser(brep_cut_result); - bool is_valid = analyser.IsValid() != 0; - if ( is_valid ) { - entity_shape = brep_cut_result; - if (Logger::LOG_WARNING >= Logger::Verbosity()) { - const double volume_after_subtraction = shape_volume(entity_shape); - double original_shape_volume = shape_volume(entity_shape); - if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) - Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity); - } - } else { - Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity); - } - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity); - } - } - - } - cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), it3->Placement()->clone(), new OpenCascadeShape(entity_shape), &it3->Style())); - } - - return true; -} - -#if OCC_VERSION_HEX < 0x60900 -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { - - // Create a compound of all opening shapes in order to speed up the boolean operations - TopoDS_Compound opening_compound; - BRep_Builder builder; - builder.MakeCompound(opening_compound); - - for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { - IfcSchema::IfcRelVoidsElement* v = *it; - IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - if (!fes->hasRepresentation()) continue; - - // Convert the IfcRepresentation of the IfcOpeningElement - gp_Trsf opening_trsf; - if (fes->hasObjectPlacement()) { - try { - convert(fes->ObjectPlacement(),opening_trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - } - - // Move the opening into the coordinate system of the IfcProduct - opening_trsf.PreMultiply(entity_trsf.Inverted()); - - IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); - IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - - IfcGeom::ConversionResults opening_shapes; - - for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { - convert_shapes(*it2,opening_shapes); - } - - for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { - gp_GTrsf gtrsf = opening_shapes[i].Placement(); - gtrsf.PreMultiply(opening_trsf); - TopoDS_Shape opening_shape = apply_transformation(opening_shapes[i].Shape(), gtrsf); - builder.Add(opening_compound, opening_shape); - } - - } - } - - // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { - TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); - if (entity_shape_gtrsf.Form() == gp_Other) { - Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity); - } - TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); - - BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound); - - bool is_valid = false; - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - - BRepCheck_Analyzer analyser(brep_cut_result); - is_valid = analyser.IsValid() != 0; - if ( is_valid ) { - cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), brep_cut_result, &it3->Style())); - } - } - if ( !is_valid ) { - // Apparently processing the boolean operation failed or resulted in an invalid result - // in which case the original shape without the subtractions is returned instead - // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity); - return false; - } - - } - return true; -} -#else - namespace { struct opening_sorter { bool operator()(const std::pair& a, const std::pair& b) const { @@ -767,8 +514,10 @@ namespace { }; } -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { +bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const ConversionResultPlacement* entity_place, IfcGeom::ConversionResults& cut_shapes) { + + const gp_Trsf entity_trsf = ((OpenCascadePlacement*)entity_place)->trsf().Trsf(); std::vector< std::pair > opening_vector; @@ -859,7 +608,6 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } return true; } -#endif bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& w, TopoDS_Face& face) { TopoDS_Wire wire = w; @@ -1084,63 +832,6 @@ void IfcGeom::Kernel::apply_tolerance(TopoDS_Shape& s, double t) { #endif } -void IfcGeom::Kernel::setValue(GeomValue var, double value) { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - deflection_tolerance = value; - break; - case GV_WIRE_CREATION_TOLERANCE: - wire_creation_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::Kernel::getValue(GeomValue var) const { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - return deflection_tolerance; - case GV_WIRE_CREATION_TOLERANCE: - return wire_creation_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; -} - namespace { // Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex @@ -1407,422 +1098,6 @@ void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, T w = builder.Wire(); } -const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(const IfcSchema::IfcProduct* product) { - IfcSchema::IfcMaterial* single_material = 0; - IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as(); - if (associated_materials->size() == 1) { - IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); - single_material = associated_material->as(); - - // 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::IfcMaterialLayerSet* layerset = associated_material->as()->ForLayerSet(); - if (layerset->MaterialLayers()->size() == 1) { - IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin()); - if (layer->hasMaterial()) { - single_material = layer->Material(); - } - } - } - } - return single_material; -} - -template -IfcGeom::NativeElement* IfcGeom::Kernel::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, shapes2; - - if ( !convert_shapes(representation, shapes) ) { - return 0; - } - - if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { - TopoDS_Shape merge; - if (flatten_shape_list(shapes, merge, false)) { - if (count(merge, TopAbs_FACE) > 0) { - std::vector thickness; - std::vector layers; - std::vector< std::vector > folded_layers; - std::vector styles; - if (convert_layerset(product, layers, styles, thickness)) { - - IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); - for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) { - IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as(); - if (associates_material) { - unsigned layerset_id = associates_material->RelatingMaterial()->data().id(); - representation_id_builder << "-layerset-" << layerset_id; - break; - } - } - - if (styles.size() > 1) { - // If there's only a single layer there is no need to manipulate geometries. - bool success = true; - if (product->as() && fold_layers(product->as(), shapes, layers, thickness, folded_layers)) { - if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) { - std::swap(shapes, shapes2); - success = true; - } - } else { - if (apply_layerset(shapes, layers, styles, shapes2)) { - std::swap(shapes, shapes2); - success = true; - } - } - - if (!success) { - Logger::Error("Failed processing layerset"); - } - } - } - } - } - } - - 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()) { - 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(); - - gp_Trsf trsf; - try { - convert(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(); - - 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 { -#if OCC_VERSION_HEX < 0x60900 - const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS); -#else - const bool faster_booleans = true; -#endif - if (faster_booleans) { - bool success = convert_openings_fast(product,openings,shapes,trsf,opened_shapes); -#if OCC_VERSION_HEX < 0x60900 - if (!success) { - opened_shapes.clear(); - convert_openings(product,openings,shapes,trsf,opened_shapes); - } -#else - (void)success; -#endif - } else { - 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 ) { - OpenCascadePlacement p(trsf); - it->prepend(&p); - } - trsf = gp_Trsf(); - 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 ) { - OpenCascadePlacement p(trsf); - it->prepend(&p); - } - trsf = gp_Trsf(); - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new OpenCascadePlacement(trsf), - boost::shared_ptr(shape), - product - ); - - if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { - auto rels = product->IsDefinedBy(); - for (auto& rel : *rels) { - if (rel->as()) { - auto pdef = rel->as()->RelatingPropertyDefinition(); - if (pdef->as()) { - std::string organization_name; - try { - // A couple of files are not according to the schema here. - organization_name = pdef->as()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name(); - } catch (...) {} - if (organization_name == "IfcOpenShell") { - auto qs = pdef->as()->Quantities(); - for (auto& q : *qs) { - if (q->as() && q->Name() == "Total Surface Area") { - double a_calc; - double a_file = q->as()->AreaValue(); - if (elem->geometry().calculate_surface_area(a_calc)) { - double diff = std::abs(a_calc - a_file); - if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) { - Logger::Error("Validation of surface area failed for:", product); - } else { - Logger::Notice("Validation of surface area succeeded for:", product); - } - } else { - Logger::Error("Validation of surface area failed for:", product); - } - } else if (q->as() && q->Name() == "Volume") { - double v_calc; - double v_file = q->as()->VolumeValue(); - if (elem->geometry().calculate_volume(v_calc)) { - double diff = std::abs(v_calc - v_file); - if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) { - Logger::Error("Validation of volume failed for:", product); - } else { - Logger::Notice("Validation of volume succeeded for:", product); - } - } else { - Logger::Error("Validation of volume failed for:", product); - } - } else if (q->as() && q->Name() == "Shape Validation Properties") { - auto qs2 = q->as()->HasQuantities(); - bool all_succeeded = qs2->size() > 0; - for (auto& q2 : *qs2) { - if (q2->as() && q2->Name() == "Surface Genus" && q2->hasDescription()) { - int item_id = boost::lexical_cast(q2->Description().substr(1)); - int genus = q2->as()->CountValue(); - for (auto& part : elem->geometry()) { - if (part.ItemId() == item_id) { - if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { - all_succeeded = false; - } - } - } - } - } - if (!all_succeeded) { - Logger::Error("Validation of surface genus failed for:", product); - } else { - Logger::Notice("Validation of surface genus succeeded for:", product); - } - } - } - } - } - } - } - } - - return elem; -} - -IfcSchema::IfcRepresentation* IfcGeom::Kernel::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(); - 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::Kernel::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::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(); - 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(); - products->push(ps); - } - } - } - } - } - - return products; -} - -template -IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) -{ - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - gp_Trsf trsf; - try { - convert(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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new OpenCascadePlacement(trsf), - brep->geometry_pointer(), - product - ); -} - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); - std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { // Set default units, set length to meters, angles to undefined setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, 1.0); @@ -2951,36 +2226,14 @@ bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape return vertex_count > 0; } -const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { - if (item->StyledByItem()->size()) { - return item; - } +bool IfcGeom::Kernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { + const IfcSchema::IfcAxis2Placement2D* ax2d; + const IfcSchema::IfcAxis2Placement3D* ax3d; - 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; -} - -bool IfcGeom::Kernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { - IfcSchema::IfcAxis2Placement2D* ax2d; - IfcSchema::IfcAxis2Placement3D* ax3d; - - IfcSchema::IfcCartesianTransformationOperator2D* op2d; - IfcSchema::IfcCartesianTransformationOperator3D* op3d; - IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; - IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; + const IfcSchema::IfcCartesianTransformationOperator2D* op2d; + const IfcSchema::IfcCartesianTransformationOperator3D* op3d; + const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; + const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; if((op2dnonu = l->as()) != 0) { gp_GTrsf2d gtrsf2d; @@ -3846,4 +3099,112 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema: if (loops_removed || (non_manifold && l->declaration().is(IfcSchema::IfcClosedShell::Class()))) { Logger::Warning(boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", l); } +} + +bool IfcGeom::Kernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { + IfcGeom::ConversionResults shapes2; + + bool success = false; + + TopoDS_Shape merge; + if (flatten_shape_list(shapes, merge, false)) { + if (count(merge, TopAbs_FACE) > 0) { + std::vector thickness; + std::vector layers; + std::vector< std::vector > folded_layers; + std::vector styles; + if (convert_layerset(product, layers, styles, thickness)) { + if (styles.size() > 1) { + // If there's only a single layer there is no need to manipulate geometries. + success = true; + if (product->as() && fold_layers(product->as(), shapes, layers, thickness, folded_layers)) { + if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) { + std::swap(shapes, shapes2); + success = true; + } + } else { + if (apply_layerset(shapes, layers, styles, shapes2)) { + std::swap(shapes, shapes2); + success = true; + } + } + + if (!success) { + Logger::Error("Failed processing layerset"); + } + } + } + } + } + + return success; +} + +bool IfcGeom::Kernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { + auto rels = product->IsDefinedBy(); + for (auto& rel : *rels) { + if (rel->as()) { + auto pdef = rel->as()->RelatingPropertyDefinition(); + if (pdef->as()) { + std::string organization_name; + try { + // A couple of files are not according to the schema here. + organization_name = pdef->as()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name(); + } catch (...) {} + if (organization_name == "IfcOpenShell") { + auto qs = pdef->as()->Quantities(); + for (auto& q : *qs) { + if (q->as() && q->Name() == "Total Surface Area") { + double a_calc; + double a_file = q->as()->AreaValue(); + if (brep.calculate_surface_area(a_calc)) { + double diff = std::abs(a_calc - a_file); + if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) { + Logger::Error("Validation of surface area failed for:", product); + } else { + Logger::Notice("Validation of surface area succeeded for:", product); + } + } else { + Logger::Error("Validation of surface area failed for:", product); + } + } else if (q->as() && q->Name() == "Volume") { + double v_calc; + double v_file = q->as()->VolumeValue(); + if (brep.calculate_volume(v_calc)) { + double diff = std::abs(v_calc - v_file); + if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) { + Logger::Error("Validation of volume failed for:", product); + } else { + Logger::Notice("Validation of volume succeeded for:", product); + } + } else { + Logger::Error("Validation of volume failed for:", product); + } + } else if (q->as() && q->Name() == "Shape Validation Properties") { + auto qs2 = q->as()->HasQuantities(); + bool all_succeeded = qs2->size() > 0; + for (auto& q2 : *qs2) { + if (q2->as() && q2->Name() == "Surface Genus" && q2->hasDescription()) { + int item_id = boost::lexical_cast(q2->Description().substr(1)); + int genus = q2->as()->CountValue(); + for (auto& part : brep) { + if (part.ItemId() == item_id) { + if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { + all_succeeded = false; + } + } + } + } + } + if (!all_succeeded) { + Logger::Error("Validation of surface genus failed for:", product); + } else { + Logger::Notice("Validation of surface genus succeeded for:", product); + } + } + } + } + } + } + } } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp index 99db68c5ab..1c941b88d6 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp @@ -362,10 +362,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d return true; } -void IfcGeom::Kernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) { - placement_rel_to = type; -} - bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) { IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf) if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) { diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp deleted file mode 100644 index edc2085b79..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp +++ /dev/null @@ -1,140 +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 . * - * * - ********************************************************************************/ - -#include - -#include "IfcGeom.h" - -namespace { - - 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(colour_or_factor), rgb); - } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { - return process_colour(static_cast(colour_or_factor), rgb); - } else { - return false; - } - } - -} - -#define Kernel MAKE_TYPE_NAME(Kernel) - -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair& shading_styles) { - if (shading_styles.second == 0) { - return 0; - } - int surface_style_id = shading_styles.first->data().id(); - std::map::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::IfcSurfaceStyleShading* shading = shading_styles.second->as(); - - 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(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); -} - -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) { - return internalize_surface_style(get_surface_style(item)); -} - -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::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()); - } - for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { - const std::pair ss = get_surface_style(*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); -} diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index e4f5b55211..e413f2c0ea 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -34,6 +34,7 @@ namespace IfcGeom { public: virtual void Multiply(const ConversionResultPlacement*) = 0; virtual void PreMultiply(const ConversionResultPlacement*) = 0; + virtual void TranslationPart(double& X, double& Y, double& Z) const = 0; virtual ConversionResultPlacement* inverted() const = 0; virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const = 0; virtual double Value(int i, int j) const = 0; diff --git a/src/ifcgeom/schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Kernel.h index 549e6be0c8..5bbb050649 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Kernel.h @@ -72,7 +72,7 @@ namespace IfcGeom { return implementation_->convert(item); } - virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) { + virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { return implementation_->convert_placement(item, trsf); } diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h index 6f231d1efa..9bb534437f 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h @@ -66,6 +66,10 @@ namespace IfcGeom { virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const { throw std::runtime_error("Not implemented"); } + + virtual void TranslationPart(double& X, double& Y, double& Z) const { + throw std::runtime_error("Not implemented"); + } private: cgal_placement_t trsf_; }; diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h index 621f030960..75a41dd1b1 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h @@ -69,6 +69,12 @@ namespace IfcGeom { 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_; }; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index d1af9174f4..06427e4331 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -512,9 +512,11 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) { for (auto jt = insts->begin(); jt != insts->end(); ++jt) { IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *jt; if (!product->get("ObjectPlacement")->isNull()) { - gp_Trsf trsf; + IfcGeom::ConversionResultPlacement* trsf; if (kernel.convert_placement(*product->get("ObjectPlacement"), trsf)) { - setSectionHeight(trsf.TranslationPart().Z() + 1.); + double X, Y, Z; + trsf->TranslationPart(X, Y, Z); + setSectionHeight(Z + 1.); Logger::Warning("No building storeys encountered, used for reference:", product); return; }