@@ -39,6 +39,11 @@ struct filtered_files_t {};
3939#include < BRepBndLib.hxx>
4040#include < BRep_Builder.hxx>
4141#include < BRepTools.hxx>
42+ #include < ProjLib.hxx>
43+ #include < TopExp_Explorer.hxx>
44+ #include < BRepPrimAPI_MakeBox.hxx>
45+ #include < BRepBuilderAPI_MakeFace.hxx>
46+ #include < BRepAlgoAPI_Common.hxx>
4247
4348#include < set>
4449#include < map>
@@ -155,6 +160,29 @@ class voxel_operation {
155160 virtual ~voxel_operation () {}
156161};
157162
163+ namespace {
164+ json_logger::meta_data dump_info (abstract_voxel_storage* voxels) {
165+ if (dynamic_cast <abstract_chunked_voxel_storage*>(voxels)) {
166+ auto left = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->grid_offset ();
167+ auto nc = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->num_chunks ();
168+ auto right = (left + nc.as <long >()) - (decltype (left)::element_type)1 ;
169+ auto sz = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->voxel_size ();
170+ auto szl = (long )dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->chunk_size ();
171+ auto left_world = ((voxels->bounds ()[0 ].as <long >() + left * szl).as <double >() * sz);
172+ auto right_world = ((voxels->bounds ()[1 ].as <long >() + left * szl).as <double >() * sz);
173+
174+ return {
175+ {" count" , (long )voxels->count ()},
176+ {" grid" , left.format () + " - " + right.format ()},
177+ {" bounds" , voxels->bounds ()[0 ].format () + " - " + voxels->bounds ()[1 ].format ()},
178+ {" world" , left_world.format () + " - " + right_world.format ()},
179+ {" bits" , (long )voxels->value_bits ()}
180+ };
181+ }
182+ return {};
183+ }
184+ }
185+
158186#ifdef WITH_IFC
159187class op_parse_ifc_file : public voxel_operation {
160188public:
@@ -537,6 +565,32 @@ class op_print_components : public voxel_operation {
537565 }
538566};
539567
568+ class op_describe_components : public voxel_operation {
569+ public:
570+ const std::vector<argument_spec>& arg_names () const {
571+ static std::vector<argument_spec> nm_ = { { true , " output_path" , " string" }, { true , " input" , " voxels" } };
572+ return nm_;
573+ }
574+ symbol_value invoke (const scope_map& scope) const {
575+ const std::string output_path = scope.get_value <std::string>(" output_path" );
576+ std::ofstream ofs (output_path.c_str ());
577+ ofs << " [" ;
578+ bool first = true ;
579+ abstract_voxel_storage* voxels = scope.get_value <abstract_voxel_storage*>(" input" );
580+ connected_components ((regular_voxel_storage*)voxels, [&ofs, &first](regular_voxel_storage* c) {
581+ if (!first) {
582+ ofs << " ," ;
583+ }
584+ auto info = dump_info (c);
585+ ofs << json_logger::to_json_string (info);
586+ first = false ;
587+ });
588+ ofs << " ]" ;
589+ symbol_value v;
590+ return v;
591+ }
592+ };
593+
540594class op_keep_components : public voxel_operation {
541595public:
542596 const std::vector<argument_spec>& arg_names () const {
@@ -559,27 +613,6 @@ class op_keep_components : public voxel_operation {
559613};
560614
561615namespace {
562- json_logger::meta_data dump_info (abstract_voxel_storage* voxels) {
563- if (dynamic_cast <abstract_chunked_voxel_storage*>(voxels)) {
564- auto left = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->grid_offset ();
565- auto nc = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->num_chunks ();
566- auto right = (left + nc.as <long >()) - (decltype (left)::element_type)1 ;
567- auto sz = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->voxel_size ();
568- auto szl = (long )dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->chunk_size ();
569- auto left_world = ((voxels->bounds ()[0 ].as <long >() + left * szl).as <double >() * sz);
570- auto right_world = ((voxels->bounds ()[1 ].as <long >() + left * szl).as <double >() * sz);
571-
572- return {
573- {" count" , (long )voxels->count ()},
574- {" grid" , left.format () + " - " + right.format ()},
575- {" bounds" , voxels->bounds ()[0 ].format () + " - " + voxels->bounds ()[1 ].format ()},
576- {" world" , left_world.format () + " - " + right_world.format ()},
577- {" bits" , (long )voxels->value_bits ()}
578- };
579- }
580- return {};
581- }
582-
583616 template <typename Fn, typename Fn2>
584617 void revoxelize_and_check_overlap (abstract_voxel_storage* voxels, const geometry_collection_t & surfaces, Fn fn, Fn2 fn2) {
585618 BRep_Builder B;
@@ -899,6 +932,101 @@ class op_offset : public voxel_operation {
899932 }
900933};
901934
935+ class op_zeros : public voxel_operation {
936+ public:
937+ const std::vector<argument_spec>& arg_names () const {
938+ static std::vector<argument_spec> nm_ = { { true , " input" , " voxels" } };
939+ return nm_;
940+ }
941+ symbol_value invoke (const scope_map& scope) const {
942+ abstract_voxel_storage* voxels = scope.get_value <abstract_voxel_storage*>(" input" );
943+ // @todo also implement empty_copy_as() here.
944+ return voxels->empty_copy ();
945+ }
946+ };
947+
948+ class op_plane : public voxel_operation {
949+ public:
950+ const std::vector<argument_spec>& arg_names () const {
951+ static std::vector<argument_spec> nm_ = { { true , " input" , " voxels" }, {true , " a" , " real" }, {true , " b" , " real" }, {true , " c" , " real" }, {true , " d" , " real" } };
952+ return nm_;
953+ }
954+ symbol_value invoke (const scope_map& scope) const {
955+ abstract_voxel_storage* v = scope.get_value <abstract_voxel_storage*>(" input" );
956+
957+ auto voxels = dynamic_cast <abstract_chunked_voxel_storage*>(v);
958+ if (voxels == nullptr ) {
959+ throw std::runtime_error (" expected chunked storage" );
960+ }
961+
962+ auto result = voxels->empty_copy ();
963+
964+ if (voxels->count () == 0 ) {
965+ return result;
966+ }
967+
968+ gp_Pln pln (
969+ scope.get_value <double >(" a" ),
970+ scope.get_value <double >(" b" ),
971+ scope.get_value <double >(" c" ),
972+ scope.get_value <double >(" d" )
973+ );
974+
975+ auto left = voxels->grid_offset ();
976+ auto sz = dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->voxel_size ();
977+ auto szl = (long )dynamic_cast <abstract_chunked_voxel_storage*>(voxels)->chunk_size ();
978+ auto left_world = ((voxels->bounds ()[0 ].as <long >() + left * szl).as <double >() * sz);
979+ auto right_world = ((voxels->bounds ()[1 ].as <long >() + left * szl).as <double >() * sz);
980+
981+ BRepPrimAPI_MakeBox mb (gp_Pnt (
982+ left_world.get <0 >(),
983+ left_world.get <1 >(),
984+ left_world.get <2 >()
985+ ), gp_Pnt (
986+ right_world.get <0 >(),
987+ right_world.get <1 >(),
988+ right_world.get <2 >()
989+ ));
990+
991+ auto box = mb.Solid ();
992+ static double inf = std::numeric_limits<double >::infinity ();
993+ std::array<std::array<double , 2 >, 2 > uv_min_max = {{ {{+inf, +inf}}, {{-inf,-inf}} }};
994+
995+ TopExp_Explorer exp (box, TopAbs_VERTEX);
996+ for (; exp.More (); exp.Next ()) {
997+ auto p = BRep_Tool::Pnt (TopoDS::Vertex (exp.Current ()));
998+ auto p2d = ProjLib::Project (pln, p);
999+ for (int i = 0 ; i < 2 ; ++i) {
1000+ auto v = p2d.ChangeCoord ().ChangeCoord (i + 1 );
1001+ auto & min_v = uv_min_max[0 ][i];
1002+ auto & max_v = uv_min_max[1 ][i];
1003+ if (v < min_v) min_v = v;
1004+ if (v > max_v) max_v = v;
1005+ }
1006+ }
1007+
1008+ auto face = BRepBuilderAPI_MakeFace (pln,
1009+ uv_min_max[0 ][0 ], uv_min_max[1 ][0 ],
1010+ uv_min_max[0 ][1 ], uv_min_max[1 ][1 ]
1011+ );
1012+
1013+ auto face_inside = BRepAlgoAPI_Common (face, box).Shape ();
1014+ TopoDS_Compound C;
1015+ if (face_inside.ShapeType () == TopAbs_COMPOUND) {
1016+ C = TopoDS::Compound (face_inside);
1017+ } else {
1018+ BRep_Builder B;
1019+ B.MakeCompound (C);
1020+ B.Add (C, face_inside);
1021+ }
1022+
1023+ BRepMesh_IncrementalMesh (C, 0.001 );
1024+
1025+ geometry_collection_t * single = new geometry_collection_t { { 0 , C} };
1026+ return single;
1027+ }
1028+ };
1029+
9021030class op_offset_xy : public voxel_operation {
9031031public:
9041032 const std::vector<argument_spec>& arg_names () const {
@@ -1315,7 +1443,7 @@ class op_create_prop_filter : public voxel_operation {
13151443class op_mesh : public voxel_operation {
13161444public:
13171445 const std::vector<argument_spec>& arg_names () const {
1318- static std::vector<argument_spec> nm_ = { { true , " input" , " voxels" }, { true , " filename" , " string" }, {false , " use_value" , " integer" } };
1446+ static std::vector<argument_spec> nm_ = { { true , " input" , " voxels" }, { true , " filename" , " string" }, {false , " use_value" , " integer" }, { false , " with_components " , " integer " } };
13191447 return nm_;
13201448 }
13211449 symbol_value invoke (const scope_map& scope) const {
@@ -1324,7 +1452,8 @@ class op_mesh : public voxel_operation {
13241452 auto filename = scope.get_value <std::string>(" filename" );
13251453 std::ofstream ofs (filename.c_str ());
13261454 if (voxels->value_bits () == 1 ) {
1327- ((regular_voxel_storage*)voxels)->obj_export (ofs);
1455+ auto with_components = scope.get_value_or <int >(" with_components" , -1 );
1456+ ((regular_voxel_storage*)voxels)->obj_export (ofs, with_components != 0 );
13281457 } else {
13291458 ((regular_voxel_storage*)voxels)->obj_export (ofs, use_value != 1 , use_value == 1 );
13301459 }
0 commit comments