1919
2020#include " TtlWktSerializer.h"
2121
22+ #ifdef IFOPSH_WITH_OPENCASCADE
23+ #include " ../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
24+
25+ #include < TopTools_HSequenceOfShape.hxx>
26+ #include < BRepBuilderAPI_Transform.hxx>
27+ #include < BRepBndLib.hxx>
28+ #include < BRepAlgoAPI_Section.hxx>
29+ #include < ShapeAnalysis_FreeBounds.hxx>
30+ #include < BRepTools_WireExplorer.hxx>
31+ #include < TopoDS.hxx>
32+
33+ #endif
34+
2235#include < iomanip>
2336#include < iostream>
2437#include < vector>
@@ -210,8 +223,15 @@ TtlWktSerializer::TtlWktSerializer(const stream_or_filename& filename, const ifc
210223 , filename_(filename)
211224{
212225 const auto & tri_setting = geometry_settings.get <ifcopenshell::geometry::settings::TriangulationType>().get ();
213- if (tri_setting != ifcopenshell::geometry::settings::POLYHEDRON_WITH_HOLES) {
214- throw std::runtime_error (" The RDF Turtle WKT serializer needs POLYHEDRON_WITH_HOLES triangulation output" );
226+ if (settings_.get <ifcopenshell::geometry::settings::WktUseSection>().get ()) {
227+ const auto & it_output = geometry_settings.get <ifcopenshell::geometry::settings::IteratorOutput>().get ();
228+ if (it_output != ifcopenshell::geometry::settings::NATIVE) {
229+ throw std::runtime_error (" The RDF Turtle WKT serializer needs native geometry when section mode is enabled" );
230+ }
231+ } else {
232+ if (tri_setting != ifcopenshell::geometry::settings::POLYHEDRON_WITH_HOLES) {
233+ throw std::runtime_error (" The RDF Turtle WKT serializer needs POLYHEDRON_WITH_HOLES triangulation output" );
234+ }
215235 }
216236 filename_.stream << std::setprecision (settings.get <ifcopenshell::geometry::settings::FloatingPointDigits>().get ());
217237}
@@ -237,32 +257,16 @@ void TtlWktSerializer::writeHeader()
237257
238258void TtlWktSerializer::write (const IfcGeom::TriangulationElement* o)
239259{
240- auto ttl_object_id = [&](const char * const postfix = nullptr ) {
241- using namespace ifcopenshell ::geometry::settings;
242- auto oid = boost::replace_all_copy (object_id (o), " -" , " _" );
243- if (oid.find (' $' ) == std::string::npos) {
244- return " base:" + oid + (postfix ? postfix : (const char * const )" " );
245- } else {
246- std::string base;
247- if (settings_.get <BaseUri>().has ()) {
248- base = settings_.get <BaseUri>().get ();
249- } else {
250- base = " http://example.org/" ;
251- }
252- return " <" + base + oid + (postfix ? postfix : (const char * const ) " " ) + " >" ;
253- }
254- };
255-
256- filename_.stream << ttl_object_id () << " a geo:Feature ;\n " ;
260+ filename_.stream << ttl_object_id (o) << " a geo:Feature ;\n " ;
257261 filename_.stream << " dcterms:identifier " << escape_for_turtle (
258262 IfcUtil::convert_utf8_to_utf32 (o->guid ())) << " ;\n " ;
259263 filename_.stream << " rdfs:label " << escape_for_turtle (
260264 IfcUtil::convert_utf8_to_utf32 (o->name ())
261265 ) << " ;\n " ;
262- filename_.stream << " geo:hasGeometry " << ttl_object_id (" _geometry" ) << " .\n\n " ;
266+ filename_.stream << " geo:hasGeometry " << ttl_object_id (o, " _geometry" ) << " .\n\n " ;
263267
264268 if (!o->geometry ().polyhedral_faces_with_holes ().empty ()) {
265- filename_.stream << ttl_object_id (" _geometry" ) << " a geo:Geometry ;\n " ;
269+ filename_.stream << ttl_object_id (o, " _geometry" ) << " a geo:Geometry ;\n " ;
266270 filename_.stream << " geo:asWKT " << escape_for_turtle (
267271 IfcUtil::convert_utf8_to_utf32 (
268272 capture_output (
@@ -304,8 +308,8 @@ void TtlWktSerializer::write(const IfcGeom::TriangulationElement* o)
304308 }
305309
306310 if (lowest_face) {
307- filename_.stream << ttl_object_id () << " geo:hasGeometry " << ttl_object_id (" _footprint_geometry" ) << " .\n\n " ;
308- filename_.stream << ttl_object_id (" _footprint_geometry" ) << " a geo:Geometry ;\n " ;
311+ filename_.stream << ttl_object_id (o ) << " geo:hasGeometry " << ttl_object_id (o, " _footprint_geometry" ) << " .\n\n " ;
312+ filename_.stream << ttl_object_id (o, " _footprint_geometry" ) << " a geo:Geometry ;\n " ;
309313 filename_.stream << " geo:asWKT " << escape_for_turtle (
310314 IfcUtil::convert_utf8_to_utf32 (
311315 capture_output (
@@ -319,7 +323,7 @@ void TtlWktSerializer::write(const IfcGeom::TriangulationElement* o)
319323 ) << " ^^geo:wktLiteral .\n\n " ;
320324 }
321325 } else {
322- filename_.stream << ttl_object_id (" _geometry" ) << " a geo:Geometry ;\n " ;
326+ filename_.stream << ttl_object_id (o, " _geometry" ) << " a geo:Geometry ;\n " ;
323327 bool force_2d = true ;
324328 double z_value;
325329 for (size_t i = 2 ; i < o->geometry ().verts ().size (); i += 3 ) {
@@ -343,3 +347,118 @@ void TtlWktSerializer::write(const IfcGeom::TriangulationElement* o)
343347 ) << " ^^geo:wktLiteral .\n\n " ;
344348 }
345349}
350+
351+ void TtlWktSerializer::write (const IfcGeom::BRepElement* brep_obj) {
352+ #ifdef IFOPSH_WITH_OPENCASCADE
353+ filename_.stream << ttl_object_id (brep_obj) << " a geo:Feature ;\n " ;
354+ filename_.stream << " dcterms:identifier " << escape_for_turtle (
355+ IfcUtil::convert_utf8_to_utf32 (brep_obj->guid ())) << " ;\n " ;
356+ filename_.stream << " rdfs:label " << escape_for_turtle (
357+ IfcUtil::convert_utf8_to_utf32 (brep_obj->name ())
358+ ) << " .\n " ;
359+
360+ // @todo unify logic with SVG serializer
361+
362+ auto itm = brep_obj->geometry ().as_compound ();
363+ TopoDS_Shape compound_local = ((ifcopenshell::geometry::OpenCascadeShape*)itm)->shape ();
364+ delete itm;
365+
366+ gp_Trsf trsf;
367+ const auto & m = brep_obj->transformation ().data ()->ccomponents ();
368+ trsf.SetValues (
369+ m (0 , 0 ), m (0 , 1 ), m (0 , 2 ), m (0 , 3 ),
370+ m (1 , 0 ), m (1 , 1 ), m (1 , 2 ), m (1 , 3 ),
371+ m (2 , 0 ), m (2 , 1 ), m (2 , 2 ), m (2 , 3 )
372+ );
373+
374+ BRepBuilderAPI_Transform make_transform_global (compound_local, trsf, true );
375+ make_transform_global.Build ();
376+ auto compound = make_transform_global.Shape ();
377+
378+ Bnd_Box bb;
379+ try {
380+ BRepBndLib::Add (compound, bb);
381+ } catch (const Standard_Failure&) {}
382+
383+ // Empty geometry
384+ if (bb.IsVoid ()) {
385+ return ;
386+ }
387+
388+ double x1, y1, zmin, x2, y2, zmax;
389+ bb.Get (x1, y1, zmin, x2, y2, zmax);
390+
391+ gp_Pln pln (gp_Pnt (0 , 0 , zmin + 1 .), gp::DZ ());
392+
393+ Handle (TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape ();
394+
395+ size_t N = 0 ;
396+ TopoDS_Iterator it (compound);
397+ // Iterate over components of compound to have better chance of matching section edges to closed wires
398+ for (; it.More (); it.Next ()) {
399+ Handle (TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape ();
400+ TopoDS_Shape result = BRepAlgoAPI_Section (it.Value (), pln);
401+
402+ {
403+ TopExp_Explorer exp (result, TopAbs_EDGE);
404+ for (; exp.More (); exp.Next ()) {
405+ edges->Append (exp.Current ());
406+ }
407+ }
408+
409+ ShapeAnalysis_FreeBounds::ConnectEdgesToWires (edges, 1e-4 , false , wires);
410+ for (int i = 1 ; i <= wires->Length (); ++i) {
411+ const TopoDS_Wire& wire = TopoDS::Wire (wires->Value (i));
412+ BRepTools_WireExplorer it (wire);
413+ std::vector<double > loop_coords;
414+ for (; it.More (); it.Next ()) {
415+ const auto & v = it.CurrentVertex ();
416+ auto pnt = BRep_Tool::Pnt (v);
417+ loop_coords.push_back (pnt.X ());
418+ loop_coords.push_back (pnt.Y ());
419+ loop_coords.push_back (pnt.Z ());
420+ }
421+ std::vector<int > loop_idxs (loop_coords.size () / 3 );
422+ for (int i = 0 ; i < loop_idxs.size (); ++i) {
423+ loop_idxs[i] = i;
424+ }
425+
426+ std::string postfix = " _section_geometry_" + std::to_string (N++);
427+
428+ filename_.stream << ttl_object_id (brep_obj) << " geo:hasGeometry " << ttl_object_id (brep_obj, postfix.c_str ()) << " .\n\n " ;
429+ filename_.stream << ttl_object_id (brep_obj, postfix.c_str ()) << " a geo:Geometry ;\n " ;
430+ filename_.stream << " geo:asWKT " << escape_for_turtle (
431+ IfcUtil::convert_utf8_to_utf32 (
432+ capture_output (
433+ emit_line_component,
434+ loop_coords,
435+ loop_idxs,
436+ true ,
437+ POLYGON))
438+ ) << " ^^geo:wktLiteral .\n\n " ;
439+ }
440+ }
441+ #endif
442+ }
443+
444+ std::string TtlWktSerializer::ttl_object_id (const IfcGeom::Element* o, const char * const postfix)
445+ {
446+ using namespace ifcopenshell ::geometry::settings;
447+ auto oid = boost::replace_all_copy (object_id (o), " -" , " _" );
448+ if (oid.find (' $' ) == std::string::npos) {
449+ return " base:" + oid + (postfix ? postfix : (const char * const )" " );
450+ } else {
451+ std::string base;
452+ if (settings_.get <BaseUri>().has ()) {
453+ base = settings_.get <BaseUri>().get ();
454+ } else {
455+ base = " http://example.org/" ;
456+ }
457+ return " <" + base + oid + (postfix ? postfix : (const char * const )" " ) + " >" ;
458+ }
459+ }
460+
461+ bool TtlWktSerializer::isTesselated () const {
462+ using namespace ifcopenshell ::geometry::settings;
463+ return !settings_.get <WktUseSection>().get ();
464+ }
0 commit comments