mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
Rename geometry and serializer files
Apply the rename manifest, normalize serializer filenames to the classes they define, and update includes and CMake source lists. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
set(geometry_serialization_plugin_runtime_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
||||
|
||||
add_subdirectory(schema)
|
||||
|
||||
add_library(geometry_serializer serialization.cpp opencascade_geometry_ifc_writer_plugin.cpp)
|
||||
target_include_directories(geometry_serializer PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
if((NOT WIN32) AND BUILD_SHARED_LIBS AND NOT WASM_BUILD AND NOT CREATE_BUNDLE AND NOT CMAKE_INSTALL_RPATH AND COMMAND SET_INSTALL_SELF_RPATH)
|
||||
SET_INSTALL_SELF_RPATH(geometry_serializer)
|
||||
endif()
|
||||
set_target_properties(geometry_serializer PROPERTIES
|
||||
OUTPUT_NAME "ifcopenshell.geometry.writer"
|
||||
COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
)
|
||||
target_link_libraries(geometry_serializer plugin IfcGeom IfcParse geometry_kernel_opencascade ${OpenCASCADE_LIBRARIES})
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer")
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
|
||||
|
||||
install(FILES serialization.h
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/serialization
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS geometry_serializer ${geometry_serializer_libraries}
|
||||
EXPORT ${IFCOPENSHELL_EXPORT_TARGETS}
|
||||
)
|
||||
|
||||
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
|
||||
@@ -0,0 +1,35 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFC_GEOMSERIALIZATION_API_H
|
||||
#define IFC_GEOMSERIALIZATION_API_H
|
||||
|
||||
#ifdef SWIG
|
||||
#define IFC_GEOMSERIALIZATION_API
|
||||
#elif defined(_WIN32)
|
||||
#ifdef IFC_GEOMSERIALIZATION_EXPORTS
|
||||
#define IFC_GEOMSERIALIZATION_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOMSERIALIZATION_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOMSERIALIZATION_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace plugin {
|
||||
PLUGIN_API std::filesystem::path add_search_paths_or_default(manager& manager, std::filesystem::path (*default_search_path)());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr const char* opencascade_geometry_ifc_writer_plugin_prefix = "geometry.writer.";
|
||||
}
|
||||
|
||||
const char* ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin_registration_symbol() {
|
||||
return "ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1";
|
||||
}
|
||||
|
||||
ifcopenshell::plugin::metadata ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name) {
|
||||
ifcopenshell::plugin::metadata metadata;
|
||||
metadata.kind_ = ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer;
|
||||
metadata.id = opencascade_geometry_ifc_writer_plugin_prefix + boost::to_lower_copy(schema_name);
|
||||
metadata.schema = boost::to_upper_copy(schema_name);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
std::filesystem::path ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin_directory() {
|
||||
return ifcopenshell::plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::geom::load_opencascade_geometry_ifc_writer_plugins));
|
||||
}
|
||||
|
||||
void ifcopenshell::geom::load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry) {
|
||||
ifcopenshell::plugin::manager manager;
|
||||
ifcopenshell::plugin::add_search_paths_or_default(manager, &opencascade_geometry_ifc_writer_plugin_directory);
|
||||
|
||||
for (const auto& path : manager.discover(opencascade_geometry_ifc_writer_plugin_prefix)) {
|
||||
auto module = manager.load(path);
|
||||
if (module.meta().kind_ != ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto register_plugin = module.get_alias<register_opencascade_geometry_ifc_writer_plugin_fn>(opencascade_geometry_ifc_writer_plugin_registration_symbol());
|
||||
register_plugin(registry, module);
|
||||
}
|
||||
}
|
||||
|
||||
bool ifcopenshell::geom::load_opencascade_geometry_ifc_writer_plugin(opencascade_geometry_ifc_writer_registry& registry, const std::string& schema_name) {
|
||||
ifcopenshell::plugin::manager manager;
|
||||
ifcopenshell::plugin::add_search_paths_or_default(manager, &opencascade_geometry_ifc_writer_plugin_directory);
|
||||
|
||||
const auto expected_schema = boost::to_upper_copy(schema_name);
|
||||
const auto basename = std::string(opencascade_geometry_ifc_writer_plugin_prefix) + boost::to_lower_copy(schema_name);
|
||||
|
||||
for (const auto& path : manager.discover_exact(basename)) {
|
||||
auto module = manager.load(path);
|
||||
if (module.meta().kind_ != ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer ||
|
||||
module.meta().schema != expected_schema) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto register_plugin = module.get_alias<register_opencascade_geometry_ifc_writer_plugin_fn>(opencascade_geometry_ifc_writer_plugin_registration_symbol());
|
||||
register_plugin(registry, module);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCOPENSHELL_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
|
||||
#define IFCOPENSHELL_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
|
||||
|
||||
#include "serialization.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace ifcopenshell::geom {
|
||||
|
||||
typedef void register_opencascade_geometry_ifc_writer_plugin_fn(opencascade_geometry_ifc_writer_registry&, const ifcopenshell::plugin::module&);
|
||||
|
||||
IFC_GEOMSERIALIZATION_API const char* opencascade_geometry_ifc_writer_plugin_registration_symbol();
|
||||
IFC_GEOMSERIALIZATION_API ifcopenshell::plugin::metadata opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name);
|
||||
IFC_GEOMSERIALIZATION_API std::filesystem::path opencascade_geometry_ifc_writer_plugin_directory();
|
||||
IFC_GEOMSERIALIZATION_API void load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry);
|
||||
IFC_GEOMSERIALIZATION_API bool load_opencascade_geometry_ifc_writer_plugin(opencascade_geometry_ifc_writer_registry& registry, const std::string& schema_name);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
if (NOT WASM_BUILD)
|
||||
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
add_library(geometry_serializer_ifc${schema} SHARED serialization.cpp plugin.cpp)
|
||||
target_link_libraries(geometry_serializer_ifc${schema} PRIVATE plugin geometry_serializer IfcGeom IfcParse parse_schema_ifc${schema} ${OpenCASCADE_LIBRARIES})
|
||||
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES
|
||||
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
|
||||
OUTPUT_NAME "ifcopenshell.geometry.writer.ifc${schema}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
)
|
||||
ifcopenshell_wasm_plugin_link_options(
|
||||
geometry_serializer_ifc${schema}
|
||||
ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1
|
||||
)
|
||||
list(APPEND geometry_serializer_libraries geometry_serializer_ifc${schema})
|
||||
endforeach()
|
||||
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
|
||||
|
||||
endif()
|
||||
@@ -0,0 +1,69 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include "../../../ifcgeom/kernels/opencascade/opencascade_conversion_result.h"
|
||||
#include "../../../ifcparse/exception.h"
|
||||
#include "../../../ifcparse/macros.h"
|
||||
|
||||
#include <boost/dll/alias.hpp>
|
||||
|
||||
express::base POSTFIX_SCHEMA(serialise)(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
|
||||
express::base POSTFIX_SCHEMA(tesselate)(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
|
||||
|
||||
namespace {
|
||||
const ifcopenshell::geom::open_cascade_shape& require_opencascade_shape(const ifcopenshell::geom::conversion_result_shape& shape) {
|
||||
const auto* oc_shape = dynamic_cast<const ifcopenshell::geom::open_cascade_shape*>(&shape);
|
||||
if (!oc_shape) {
|
||||
throw ifcopenshell::exception("OpenCascade geometry IFC writer requires an opencascade conversion result shape");
|
||||
}
|
||||
return *oc_shape;
|
||||
}
|
||||
|
||||
express::base serialise_adapter(ifcopenshell::file& f, const ifcopenshell::geom::conversion_result_shape& shape, bool advanced) {
|
||||
return POSTFIX_SCHEMA(serialise)(f, require_opencascade_shape(shape).shape(), advanced);
|
||||
}
|
||||
|
||||
express::base tesselate_adapter(ifcopenshell::file& f, const ifcopenshell::geom::conversion_result_shape& shape, double deflection) {
|
||||
return POSTFIX_SCHEMA(tesselate)(f, require_opencascade_shape(shape).shape(), deflection);
|
||||
}
|
||||
}
|
||||
|
||||
namespace ifcopenshell::geom {
|
||||
namespace opencascade_geometry_ifc_writer_plugin {
|
||||
|
||||
ifcopenshell::plugin::abi_info plugin_abi() {
|
||||
return ifcopenshell::plugin::host_abi();
|
||||
}
|
||||
|
||||
ifcopenshell::plugin::metadata plugin_metadata() {
|
||||
return opencascade_geometry_ifc_writer_plugin_metadata(STRINGIFY(IfcSchema));
|
||||
}
|
||||
|
||||
void register_plugin(opencascade_geometry_ifc_writer_registry& registry, const ifcopenshell::plugin::module& module) {
|
||||
registry.bind(STRINGIFY(IfcSchema), &serialise_adapter, &tesselate_adapter, module);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geom::opencascade_geometry_ifc_writer_plugin::register_plugin, ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1)
|
||||
@@ -0,0 +1,848 @@
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array2OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_BezierCurve.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include "../../../ifcparse/macros.h"
|
||||
#include "../../../ifcparse/parse.h"
|
||||
#include "../../../ifcparse/file.h"
|
||||
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/schemas/x.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
#undef INCLUDE_PARENT_PARENT_DIR
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/schemas/x-definitions.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
|
||||
#include <numeric>
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const T& t, U& u, bool /*advanced*/) {
|
||||
u = f.create<U>();
|
||||
u.set_attribute_value(0, std::vector<double>{t.X(), t.Y(), t.Z()});
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint& p, bool advanced) {
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
return convert_to_ifc(f, pnt, p, advanced);
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Vertex& v, IfcSchema::IfcVertexPoint& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (convert_to_ifc(f, v, p, advanced)) {
|
||||
vertex = f.create<IfcSchema::IfcVertexPoint>();
|
||||
vertex.setVertexGeometry(p);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
IfcSchema::IfcDirection x, z;
|
||||
if (!(convert_to_ifc(f, a.Location(), p, advanced) && convert_to_ifc(f, a.Direction(), z, advanced) && convert_to_ifc(f, a.XDirection(), x, advanced))) {
|
||||
ax = IfcSchema::IfcAxis2Placement3D{};
|
||||
return 0;
|
||||
}
|
||||
ax = f.create<IfcSchema::IfcAxis2Placement3D>();
|
||||
ax.setLocation(p);
|
||||
ax.setAxis(z);
|
||||
ax.setRefDirection(x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
|
||||
u.reserve(t.Length());
|
||||
for (int i = t.Lower(); i <= t.Upper(); ++i) {
|
||||
u.push_back(t.Value(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
|
||||
u.reserve(t.RowLength());
|
||||
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
|
||||
std::vector<U> v;
|
||||
v.reserve(t.ColLength());
|
||||
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
|
||||
v.push_back(t.Value(j, i));
|
||||
}
|
||||
u.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcRationalBSplineSurfaceWithKnots
|
||||
namespace {
|
||||
IfcSchema::IfcKnotType::Value opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
|
||||
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
if (bspline_knot_spec == GeomAbs_Uniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
|
||||
}
|
||||
return knot_spec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const opencascade::handle<Geom_Curve>& c, IfcSchema::IfcCurve& curve, bool advanced) {
|
||||
if (c->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
|
||||
opencascade::handle<Geom_TrimmedCurve> trim = opencascade::handle<Geom_TrimmedCurve>::DownCast(c);
|
||||
const opencascade::handle<Geom_Curve> basis = trim->BasisCurve();
|
||||
return convert_to_ifc(f, basis, curve, advanced);
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
IfcSchema::IfcDirection d;
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
|
||||
opencascade::handle<Geom_Line> line = opencascade::handle<Geom_Line>::DownCast(c);
|
||||
|
||||
if (!convert_to_ifc(f, line->Position().Location(), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
if (!convert_to_ifc(f, line->Position().Direction(), d, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcVector v = f.create<IfcSchema::IfcVector>();
|
||||
v.setOrientation(d);
|
||||
v.setMagnitude(1.);
|
||||
IfcSchema::IfcLine l = f.create<IfcSchema::IfcLine>();
|
||||
l.setPnt(p);
|
||||
l.setDir(v);
|
||||
curve = l;
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
IfcSchema::IfcAxis2Placement3D ax;
|
||||
|
||||
opencascade::handle<Geom_Circle> circle = opencascade::handle<Geom_Circle>::DownCast(c);
|
||||
|
||||
convert_to_ifc(f, circle->Position(), ax, advanced);
|
||||
auto circ = f.create<IfcSchema::IfcCircle>();
|
||||
circ.setPosition(ax);
|
||||
circ.setRadius(circle->Radius());
|
||||
curve = circ;
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
IfcSchema::IfcAxis2Placement3D ax;
|
||||
|
||||
opencascade::handle<Geom_Ellipse> ellipse = opencascade::handle<Geom_Ellipse>::DownCast(c);
|
||||
convert_to_ifc(f, ellipse->Position(), ax, advanced);
|
||||
|
||||
auto el = f.create<IfcSchema::IfcEllipse>();
|
||||
el.setPosition(ax);
|
||||
el.setSemiAxis1(ellipse->MajorRadius());
|
||||
el.setSemiAxis2(ellipse->MinorRadius());
|
||||
curve = el;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#ifdef SCHEMA_HAS_IfcRationalBSplineSurfaceWithKnots
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BezierCurve)) {
|
||||
opencascade::handle<Geom_BezierCurve> bezier = opencascade::handle<Geom_BezierCurve>::DownCast(c);
|
||||
|
||||
std::vector<int64_t> mults;
|
||||
std::vector<double> knots;
|
||||
std::vector<double> weights;
|
||||
|
||||
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
NCollection_Array1<gp_Pnt> poles(1, bezier->NbPoles());
|
||||
bezier->Poles(poles);
|
||||
for (int i = 1; i <= bezier->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points.push_back(p);
|
||||
|
||||
if (i == 1 || i == bezier->NbPoles()) {
|
||||
mults.push_back(bezier->Degree() + 1);
|
||||
} else {
|
||||
mults.push_back(bezier->Degree());
|
||||
}
|
||||
|
||||
knots.push_back((double) i - 1);
|
||||
}
|
||||
|
||||
NCollection_Array1<double> bspline_weights(1, bezier->NbPoles());
|
||||
bezier->Weights(bspline_weights);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
auto bspl = f.create<IfcSchema::IfcRationalBSplineCurveWithKnots>();
|
||||
bspl.setDegree(bezier->Degree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setCurveForm(IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED);
|
||||
bspl.setClosedCurve(bezier->IsClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setKnotMultiplicities(mults);
|
||||
bspl.setKnots(knots);
|
||||
bspl.setKnotSpec(knot_spec);
|
||||
bspl.setWeightsData(weights);
|
||||
curve = bspl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
opencascade::handle<Geom_BSplineCurve> bspline = opencascade::handle<Geom_BSplineCurve>::DownCast(c);
|
||||
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
NCollection_Array1<gp_Pnt> poles(1, bspline->NbPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points.push_back(p);
|
||||
}
|
||||
IfcSchema::IfcKnotType::Value knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
|
||||
|
||||
std::vector<int64_t> mults;
|
||||
std::vector<double> knots;
|
||||
std::vector<double> weights;
|
||||
|
||||
NCollection_Array1<int> bspline_mults(1, bspline->NbKnots());
|
||||
NCollection_Array1<double> bspline_knots(1, bspline->NbKnots());
|
||||
NCollection_Array1<double> bspline_weights(1, bspline->NbPoles());
|
||||
|
||||
bspline->Multiplicities(bspline_mults);
|
||||
bspline->Knots(bspline_knots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_mults, mults);
|
||||
opencascade_array_to_vector(bspline_knots, knots);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
if ((*it) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bspline->IsPeriodic() && points.size()) {
|
||||
points.push_back(points.front());
|
||||
weights.push_back(weights[0]);
|
||||
auto sum = std::accumulate(mults.begin(), mults.end(), 0);
|
||||
auto d = sum - (bspline->Degree() + (int) points.size() + 1);
|
||||
(*mults.begin()) -= d / 2;
|
||||
(*mults.rbegin()) -= d / 2;
|
||||
}
|
||||
|
||||
IfcSchema::IfcBSplineCurveWithKnots bspl;
|
||||
|
||||
if (rational) {
|
||||
auto rbspl = f.create<IfcSchema::IfcRationalBSplineCurveWithKnots>();
|
||||
rbspl.setWeightsData(weights);
|
||||
bspl = rbspl;
|
||||
} else {
|
||||
bspl = f.create<IfcSchema::IfcBSplineCurveWithKnots>();
|
||||
}
|
||||
|
||||
bspl.setDegree(bspline->Degree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setCurveForm(IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED);
|
||||
bspl.setClosedCurve(bspline->IsClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setKnotMultiplicities(mults);
|
||||
bspl.setKnots(knots);
|
||||
bspl.setKnotSpec(knot_spec);
|
||||
curve = bspl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const opencascade::handle<Geom_Surface>& s, IfcSchema::IfcSurface& surface, bool advanced) {
|
||||
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
opencascade::handle<Geom_Plane> plane = opencascade::handle<Geom_Plane>::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(f, plane->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
auto pln = f.create<IfcSchema::IfcPlane>();
|
||||
pln.setPosition(place);
|
||||
surface = pln;
|
||||
return 1;
|
||||
}
|
||||
#ifdef SCHEMA_HAS_IfcRationalBSplineSurfaceWithKnots
|
||||
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
|
||||
opencascade::handle<Geom_CylindricalSurface> cyl = opencascade::handle<Geom_CylindricalSurface>::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(f, cyl->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto surf = f.create<IfcSchema::IfcCylindricalSurface>();
|
||||
surf.setPosition(place);
|
||||
surf.setRadius(cyl->Radius());
|
||||
surface = surf;
|
||||
|
||||
return 1;
|
||||
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
|
||||
std::vector<std::vector<IfcSchema::IfcCartesianPoint>> points;
|
||||
opencascade::handle<Geom_BSplineSurface> bspline = opencascade::handle<Geom_BSplineSurface>::DownCast(s);
|
||||
|
||||
NCollection_Array2<gp_Pnt> poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
|
||||
auto& ps = points.emplace_back();
|
||||
ps.reserve(bspline->NbVPoles());
|
||||
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i, j), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
ps.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcKnotType::Value knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
|
||||
IfcSchema::IfcKnotType::Value knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
|
||||
|
||||
if (knot_spec_u != knot_spec_v) {
|
||||
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
}
|
||||
|
||||
std::vector<int64_t> umults;
|
||||
std::vector<int64_t> vmults;
|
||||
std::vector<double> uknots;
|
||||
std::vector<double> vknots;
|
||||
std::vector< std::vector<double> > weights;
|
||||
|
||||
NCollection_Array1<int> bspline_umults(1, bspline->NbUKnots());
|
||||
NCollection_Array1<int> bspline_vmults(1, bspline->NbVKnots());
|
||||
NCollection_Array1<double> bspline_uknots(1, bspline->NbUKnots());
|
||||
NCollection_Array1<double> bspline_vknots(1, bspline->NbVKnots());
|
||||
NCollection_Array2<double> bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
|
||||
bspline->UMultiplicities(bspline_umults);
|
||||
bspline->VMultiplicities(bspline_vmults);
|
||||
bspline->UKnots(bspline_uknots);
|
||||
bspline->VKnots(bspline_vknots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_umults, umults);
|
||||
opencascade_array_to_vector(bspline_vmults, vmults);
|
||||
opencascade_array_to_vector(bspline_uknots, uknots);
|
||||
opencascade_array_to_vector(bspline_vknots, vknots);
|
||||
opencascade_array_to_vector2(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
|
||||
if ((*jt) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcBSplineSurfaceWithKnots bspl;
|
||||
|
||||
if (rational) {
|
||||
auto rbspl = f.create<IfcSchema::IfcRationalBSplineSurfaceWithKnots>();
|
||||
rbspl.setWeightsData(weights);
|
||||
bspl = rbspl;
|
||||
} else {
|
||||
bspl = f.create<IfcSchema::IfcBSplineSurfaceWithKnots>();
|
||||
}
|
||||
|
||||
bspl.setUDegree(bspline->UDegree());
|
||||
bspl.setVDegree(bspline->VDegree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setSurfaceForm(IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED);
|
||||
bspl.setUClosed(bspline->IsUClosed() != 0);
|
||||
bspl.setVClosed(bspline->IsVClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setUMultiplicities(umults);
|
||||
bspl.setVMultiplicities(vmults);
|
||||
bspl.setUKnots(uknots);
|
||||
bspl.setVKnots(vknots);
|
||||
bspl.setKnotSpec(knot_spec_u);
|
||||
|
||||
surface = bspl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Edge& e, IfcSchema::IfcCurve& c, bool advanced) {
|
||||
double a, b;
|
||||
IfcSchema::IfcCurve base;
|
||||
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, a, b);
|
||||
if (!convert_to_ifc(f, crv, base, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ta = f.create<IfcSchema::IfcParameterValue>();
|
||||
ta.set_attribute_value(0, a);
|
||||
auto tb = f.create<IfcSchema::IfcParameterValue>();
|
||||
tb.set_attribute_value(0, b);
|
||||
|
||||
std::vector<IfcSchema::IfcTrimmingSelect> trim1{ta};
|
||||
std::vector<IfcSchema::IfcTrimmingSelect> trim2{tb};
|
||||
|
||||
auto tc = f.create<IfcSchema::IfcTrimmedCurve>();
|
||||
tc.setBasisCurve(base);
|
||||
tc.setTrim1(trim1);
|
||||
tc.setTrim2(trim2);
|
||||
tc.setSenseAgreement(true);
|
||||
tc.setMasterRepresentation(IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
|
||||
c = tc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Edge& e, IfcSchema::IfcEdge& edge, bool advanced) {
|
||||
double a, b;
|
||||
|
||||
TopExp_Explorer exp(e, TopAbs_VERTEX);
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
|
||||
exp.Next();
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
|
||||
|
||||
IfcSchema::IfcVertexPoint vertex1, vertex2;
|
||||
if (!(convert_to_ifc(f, v1, vertex1, advanced) && convert_to_ifc(f, v2, vertex2, advanced))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, a, b);
|
||||
|
||||
if (crv.IsNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
|
||||
IfcSchema::IfcEdge edge2 = f.create<IfcSchema::IfcEdge>();
|
||||
edge2.setEdgeStart(vertex1);
|
||||
edge2.setEdgeEnd(vertex2);
|
||||
|
||||
auto ori = f.create<IfcSchema::IfcOrientedEdge>();
|
||||
ori.setEdgeElement(edge2);
|
||||
ori.setOrientation(true);
|
||||
|
||||
edge = ori;
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcCurve curve;
|
||||
if (!convert_to_ifc(f, crv, curve, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @todo probably not correct
|
||||
const bool sense = e.Orientation() == TopAbs_FORWARD;
|
||||
|
||||
auto ec = f.create<IfcSchema::IfcEdgeCurve>();
|
||||
ec.setEdgeStart(vertex1);
|
||||
ec.setEdgeEnd(vertex2);
|
||||
ec.setEdgeGeometry(curve);
|
||||
ec.setSameSense(true);
|
||||
|
||||
auto ori = f.create<IfcSchema::IfcOrientedEdge>();
|
||||
ori.setEdgeElement(ec);
|
||||
ori.setOrientation(sense);
|
||||
|
||||
edge = ori;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool is_polygonal(const opencascade::handle<Geom_Curve>& crv) {
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
return true;
|
||||
} else if (crv->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
|
||||
return is_polygonal(opencascade::handle<Geom_TrimmedCurve>::DownCast(crv)->BasisCurve());
|
||||
} else if (crv->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
auto bspl = opencascade::handle<Geom_BSplineCurve>::DownCast(crv);
|
||||
return bspl->NbPoles() == 2 && bspl->Degree() == 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Wire& wire, IfcSchema::IfcLoop& loop, bool advanced) {
|
||||
bool polygonal = true;
|
||||
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
if (!is_polygonal(crv)) {
|
||||
polygonal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polygonal && !advanced) {
|
||||
return 0;
|
||||
} else if (polygonal && !advanced) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
for (; exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(f, exp.CurrentVertex(), p, advanced)) {
|
||||
points.push_back(p);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
auto pl = f.create<IfcSchema::IfcPolyLoop>();
|
||||
pl.setPolygon(points);
|
||||
loop = pl;
|
||||
return 1;
|
||||
} else {
|
||||
std::vector<IfcSchema::IfcOrientedEdge> edges;
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcEdge edge;
|
||||
// With advanced set to true convert_to_ifc(ifcopenshell::file& f, TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(f, exp.Current(), edge, true)) {
|
||||
double a, b;
|
||||
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
|
||||
continue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
edges.push_back(edge.as<IfcSchema::IfcOrientedEdge>());
|
||||
}
|
||||
auto el = f.create<IfcSchema::IfcEdgeLoop>();
|
||||
el.setEdgeList(edges);
|
||||
loop = el;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Face& fa, IfcSchema::IfcFace& face, bool advanced) {
|
||||
opencascade::handle<Geom_Surface> surf = BRep_Tool::Surface(fa);
|
||||
TopExp_Explorer exp(fa, TopAbs_WIRE);
|
||||
std::vector<IfcSchema::IfcFaceBound> bounds;
|
||||
int index = 0;
|
||||
auto outer = BRepTools::OuterWire(fa);
|
||||
for (; exp.More(); exp.Next(), ++index) {
|
||||
IfcSchema::IfcLoop loop;
|
||||
if (!convert_to_ifc(f, TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
IfcSchema::IfcFaceBound bnd;
|
||||
if (outer == exp.Current()) {
|
||||
bnd = f.create<IfcSchema::IfcFaceOuterBound>();
|
||||
} else {
|
||||
bnd = f.create<IfcSchema::IfcFaceBound>();
|
||||
}
|
||||
bnd.setBound(loop);
|
||||
bnd.setOrientation(true);
|
||||
|
||||
bounds.push_back(bnd);
|
||||
}
|
||||
|
||||
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
|
||||
|
||||
if (!is_planar && !advanced) {
|
||||
return 0;
|
||||
}
|
||||
if (is_planar && !advanced) {
|
||||
face = f.create<IfcSchema::IfcFace>();
|
||||
face.setBounds(bounds);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedFace
|
||||
IfcSchema::IfcSurface surface;
|
||||
if (!convert_to_ifc(f, surf, surface, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
auto adv = f.create<IfcSchema::IfcAdvancedFace>();
|
||||
adv.setBounds(bounds);
|
||||
adv.setFaceSurface(surface);
|
||||
adv.setSameSense(fa.Orientation() == TopAbs_FORWARD);
|
||||
face = adv;
|
||||
return 1;
|
||||
#else
|
||||
// No IfcAdvancedFace in Ifc2x3
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Shape& s, U& item, bool advanced) {
|
||||
std::vector<IfcSchema::IfcFace> faces;
|
||||
IfcSchema::IfcFace fa;
|
||||
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(f, TopoDS::Face(exp.Current()), fa, advanced)) {
|
||||
faces.push_back(fa);
|
||||
} else {
|
||||
std::set<express::base> created;
|
||||
for (auto& face : faces) {
|
||||
auto resources = f.traverse(face);
|
||||
created.insert(resources.begin(), resources.end());
|
||||
}
|
||||
for (auto& c : created) {
|
||||
f.remove_entity(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
item = f.create<U>();
|
||||
item.setCfsFaces(faces);
|
||||
|
||||
return faces.size();
|
||||
}
|
||||
|
||||
express::base POSTFIX_SCHEMA(serialise)(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced) {
|
||||
|
||||
#ifndef SCHEMA_HAS_IfcAdvancedBrep
|
||||
advanced = false;
|
||||
#endif
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
|
||||
/// @todo CompSolids are not supported
|
||||
return express::base{};
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation rep;
|
||||
std::vector<IfcSchema::IfcRepresentationItem> items;
|
||||
|
||||
// First check if there is a solid with one or more shells
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcClosedShell outer;
|
||||
std::vector<IfcSchema::IfcClosedShell> inner;
|
||||
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
|
||||
IfcSchema::IfcClosedShell shell;
|
||||
if (!convert_to_ifc(f, exp2.Current(), shell, advanced)) {
|
||||
return express::base{};
|
||||
}
|
||||
/// @todo Are shells always in this order or does Orientation() needs to be checked?
|
||||
/// > #4216, no, consider using BRepClass3d::OuterShell()
|
||||
if (outer) {
|
||||
inner.push_back(shell);
|
||||
} else {
|
||||
outer = shell;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedBrep
|
||||
if (advanced) {
|
||||
if (inner.size()) {
|
||||
auto inst = f.create<IfcSchema::IfcAdvancedBrepWithVoids>();
|
||||
inst.setOuter(outer);
|
||||
inst.setVoids(inner);
|
||||
items.push_back(inst);
|
||||
} else {
|
||||
auto inst = f.create<IfcSchema::IfcAdvancedBrep>();
|
||||
inst.setOuter(outer);
|
||||
items.push_back(inst);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
|
||||
if (inner.size()) {
|
||||
auto inst = f.create<IfcSchema::IfcFacetedBrepWithVoids>();
|
||||
inst.setOuter(outer);
|
||||
inst.setVoids(inner);
|
||||
items.push_back(inst);
|
||||
} else {
|
||||
auto inst = f.create<IfcSchema::IfcFacetedBrep>();
|
||||
inst.setOuter(outer);
|
||||
items.push_back(inst);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items.size() > 0) {
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there is a shell
|
||||
std::vector<IfcSchema::IfcShell> shells;
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcOpenShell shell;
|
||||
if (!convert_to_ifc(f, exp.Current(), shell, advanced)) {
|
||||
return express::base{};
|
||||
}
|
||||
shells.push_back(shell);
|
||||
}
|
||||
|
||||
if (shells.size() > 0) {
|
||||
auto inst = f.create<IfcSchema::IfcShellBasedSurfaceModel>();
|
||||
inst.setSbsmBoundary(shells);
|
||||
items.push_back(inst);
|
||||
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
|
||||
IfcSchema::IfcOpenShell shell;
|
||||
int face_count = convert_to_ifc(f, shape, shell, advanced);
|
||||
|
||||
if (face_count > 0) {
|
||||
items.push_back(shell);
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there are any edges. Note that wires are skipped as
|
||||
// they are not commonly top-level geometrical descriptions in IFC.
|
||||
// Also note that edges are written as trimmed curves rather than edges.
|
||||
|
||||
std::vector<express::entity> edges;
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcCurve c;
|
||||
if (!convert_to_ifc(f, TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return express::base{};
|
||||
}
|
||||
edges.push_back(c);
|
||||
}
|
||||
|
||||
if (edges.size() == 0) {
|
||||
return express::base{};
|
||||
} else if (edges.size() == 1) {
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Axis");
|
||||
srep.setRepresentationType("Curve2D");
|
||||
srep.setItems(cast_vector<IfcSchema::IfcRepresentationItem>(edges));
|
||||
rep = srep;
|
||||
} else {
|
||||
// A geometric set is created as that probably (?) makes more sense in IFC
|
||||
auto curves = f.create<IfcSchema::IfcGeometricCurveSet>();
|
||||
curves.setElements(cast_vector<IfcSchema::IfcGeometricSetSelect>(edges));
|
||||
items.push_back(curves);
|
||||
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Axis");
|
||||
srep.setRepresentationType("GeometricCurveSet");
|
||||
srep.setItems(items);
|
||||
rep = srep;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pds = f.create<IfcSchema::IfcProductDefinitionShape>();
|
||||
pds.setRepresentations({rep});
|
||||
|
||||
return pds;
|
||||
}
|
||||
|
||||
express::base POSTFIX_SCHEMA(tesselate)(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection) {
|
||||
// @todo use triangulated face set in ifc4+ schema
|
||||
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
std::vector<IfcSchema::IfcFace> faces;
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint> vertices;
|
||||
for (int i = 1; i <= tri->NbNodes(); ++i) {
|
||||
gp_Pnt pnt = tri->Node(i).Transformed(loc);
|
||||
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
||||
IfcSchema::IfcCartesianPoint cpnt = f.create<IfcSchema::IfcCartesianPoint>();
|
||||
cpnt.setCoordinates(xyz);
|
||||
vertices.push_back(cpnt);
|
||||
}
|
||||
const NCollection_Array1<Poly_Triangle>& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points {
|
||||
vertices[n1 - 1], vertices[n2 - 1], vertices[n3 - 1]
|
||||
};
|
||||
IfcSchema::IfcPolyLoop loop = f.create<IfcSchema::IfcPolyLoop>();
|
||||
loop.setPolygon(points);
|
||||
IfcSchema::IfcFaceOuterBound bound = f.create<IfcSchema::IfcFaceOuterBound>();
|
||||
bound.setBound(loop);
|
||||
bound.setOrientation(face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFace face2 = f.create<IfcSchema::IfcFace>();
|
||||
face2.setBounds({bound});
|
||||
faces.push_back(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto shell = f.create<IfcSchema::IfcOpenShell>();
|
||||
shell.setCfsFaces(faces);
|
||||
|
||||
auto surface_model = f.create<IfcSchema::IfcFaceBasedSurfaceModel>();
|
||||
surface_model.setFbsmFaces({shell});
|
||||
|
||||
auto rep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
rep.setRepresentationIdentifier("Tessellation");
|
||||
rep.setRepresentationType("SurfaceModel");
|
||||
rep.setItems({surface_model});
|
||||
|
||||
auto shapedef = f.create<IfcSchema::IfcProductDefinitionShape>();
|
||||
shapedef.setRepresentations({rep});
|
||||
|
||||
return shapedef;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "serialization.h"
|
||||
#include "opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include "../../ifcgeom/kernels/opencascade/opencascade_conversion_result.h"
|
||||
#include "../../ifcparse/file.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace {
|
||||
std::string writer_schema_key(const std::string& schema_name) {
|
||||
return boost::to_upper_copy(schema_name);
|
||||
}
|
||||
}
|
||||
|
||||
ifcopenshell::geom::opencascade_geometry_ifc_writer_registry& ifcopenshell::geom::opencascade_geometry_ifc_writer_registry_instance() {
|
||||
static opencascade_geometry_ifc_writer_registry registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
void ifcopenshell::geom::opencascade_geometry_ifc_writer_registry::bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module) {
|
||||
entry entry;
|
||||
entry.serialise_ = serialise;
|
||||
entry.tesselate_ = tesselate;
|
||||
entry.module_ = module.meta().id.empty() ? ifcopenshell::plugin::module(opencascade_geometry_ifc_writer_plugin_metadata(schema_name)) : module;
|
||||
entries_[writer_schema_key(schema_name)] = entry;
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::opencascade_geometry_ifc_writer_registry::tesselate(ifcopenshell::file& f, const conversion_result_shape& shape, double deflection) const {
|
||||
auto iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
if (iter == entries_.end()) {
|
||||
load_opencascade_geometry_ifc_writer_plugin(const_cast<opencascade_geometry_ifc_writer_registry&>(*this), f.schema()->name());
|
||||
iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
}
|
||||
if (iter == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
|
||||
}
|
||||
return iter->second.tesselate_(f, shape, deflection);
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::opencascade_geometry_ifc_writer_registry::serialise(ifcopenshell::file& f, const conversion_result_shape& shape, bool advanced) const {
|
||||
auto iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
if (iter == entries_.end()) {
|
||||
load_opencascade_geometry_ifc_writer_plugin(const_cast<opencascade_geometry_ifc_writer_registry&>(*this), f.schema()->name());
|
||||
iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
}
|
||||
if (iter == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
|
||||
}
|
||||
return iter->second.serialise_(f, shape, advanced);
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::tesselate(ifcopenshell::file& f, const conversion_result_shape& shape, double deflection) {
|
||||
return opencascade_geometry_ifc_writer_registry_instance().tesselate(f, shape, deflection);
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::serialise(ifcopenshell::file& f, const conversion_result_shape& shape, bool advanced) {
|
||||
return opencascade_geometry_ifc_writer_registry_instance().serialise(f, shape, advanced);
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection) {
|
||||
ifcopenshell::geom::open_cascade_shape converted(shape);
|
||||
return tesselate(f, converted, deflection);
|
||||
}
|
||||
|
||||
express::base ifcopenshell::geom::serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced) {
|
||||
ifcopenshell::geom::open_cascade_shape converted(shape);
|
||||
return serialise(f, converted, advanced);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef IFC_GEOM_SERIALIZATION_H
|
||||
#define IFC_GEOM_SERIALIZATION_H
|
||||
|
||||
#include "../../ifcparse/express.h"
|
||||
#include "../../plugin/plugin.h"
|
||||
#include "../../ifcgeom/conversion_result.h"
|
||||
|
||||
#include "ifc_geomserialization_api.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace ifcopenshell {
|
||||
class file;
|
||||
}
|
||||
|
||||
namespace ifcopenshell::geom {
|
||||
class IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry {
|
||||
public:
|
||||
typedef boost::function3<express::base, ifcopenshell::file&, const conversion_result_shape&, double> tesselate_fn;
|
||||
typedef boost::function3<express::base, ifcopenshell::file&, const conversion_result_shape&, bool> serialise_fn;
|
||||
|
||||
void bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
|
||||
express::base tesselate(ifcopenshell::file& f, const conversion_result_shape& shape, double deflection) const;
|
||||
express::base serialise(ifcopenshell::file& f, const conversion_result_shape& shape, bool advanced) const;
|
||||
|
||||
private:
|
||||
struct entry {
|
||||
serialise_fn serialise_;
|
||||
tesselate_fn tesselate_;
|
||||
ifcopenshell::plugin::module module_;
|
||||
};
|
||||
|
||||
std::map<std::string, entry> entries_;
|
||||
};
|
||||
|
||||
IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry& opencascade_geometry_ifc_writer_registry_instance();
|
||||
|
||||
IFC_GEOMSERIALIZATION_API express::base tesselate(ifcopenshell::file& f, const conversion_result_shape& shape, double deflection);
|
||||
IFC_GEOMSERIALIZATION_API express::base serialise(ifcopenshell::file& f, const conversion_result_shape& shape, bool advanced);
|
||||
IFC_GEOMSERIALIZATION_API express::base tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
|
||||
IFC_GEOMSERIALIZATION_API express::base serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
|
||||
} // namespace ifcopenshell::geom
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user