565{
566
567
568
570
571 struct Item {
const SketchEntity* e;
size_t idx; };
572 std::vector<Item> valid;
573 valid.reserve(entities.size());
574 for (size_t i = 0; i < entities.size(); ++i) {
575 const SketchEntity& e = entities[i];
576 if (e.construction) continue;
578 valid.push_back({&e, i});
579 }
580 if (valid.empty()) return {};
581
582
583
584
585 auto make_elips = [&](const SketchEntity& c) -> gp_Elips {
586 Vec3d c3 = plane.to_world(c.center);
587 gp_Pnt
center(c3.x(), c3.y(), c3.z());
588
589
590
591
592 const Vec3d nz = plane.x_axis.cross(plane.y_axis);
593 gp_Dir n(nz.x(), nz.y(), nz.z());
594 Vec2d maj2(std::cos(c.rotation), std::sin(c.rotation));
595 Vec3d x3 = plane.to_world(c.center + maj2) - c3;
596 gp_Dir xdir(x3.x(), x3.y(), x3.z());
597 double a = c.radius, b = c.rminor;
598 if (a < b) std::swap(a, b);
599 return gp_Elips(gp_Ax2(
center, n, xdir), a, b);
600 };
601
602
603
604
605 auto make_bspline = [&](const SketchEntity& c) -> Handle(Geom_BSplineCurve) {
606 const int n = int(c.ctrl.size());
607 const int p = n >= 4 ? 3 : (n >= 2 ? n - 1 : 0);
608 if (p < 1) return Handle(Geom_BSplineCurve)();
609 NCollection_Array1<gp_Pnt> poles(1, n);
610 for (int i = 0; i < n; ++i) {
611 Vec3d w = plane.to_world(c.ctrl[i]);
612 poles.SetValue(i + 1, gp_Pnt(w.x(), w.y(), w.z()));
613 }
614 const int interior = n - p - 1;
615 const int nknots = interior + 2;
616 NCollection_Array1<double> knots(1, nknots);
617 NCollection_Array1<int> mults(1, nknots);
618 knots.SetValue(1, 0.0); mults.SetValue(1, p + 1);
619 for (int i = 1; i <= interior; ++i) { knots.SetValue(i + 1, double(i)); mults.SetValue(i + 1, 1); }
620 knots.SetValue(nknots, double(interior + 1)); mults.SetValue(nknots, p + 1);
621 return new Geom_BSplineCurve(poles, knots, mults, p);
622 };
623
624 auto is_chain = [](const SketchEntity& e) {
627 };
628
629
630
631 auto endpoints = [&](
const SketchEntity& e,
Vec2d& a,
Vec2d& b) ->
bool {
633 if (e.ctrl.size() < 2) return false;
634 a = e.ctrl.front(); b = e.ctrl.back();
635 return true;
636 }
637 a = e.p0; b = e.p1;
638 return true;
639 };
640
641
642
643
644
645
646 auto same = [&](
const Vec2d& p,
const Vec2d& q) {
return (p - q).norm() <= tol; };
647
648
649 std::vector<int> parent(valid.size());
650 for (size_t i = 0; i < valid.size(); ++i) parent[i] = int(i);
651 auto find = [&](
int x) {
652 while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; }
653 return x;
654 };
655 auto unite = [&](int x, int y) {
657 if (rx != ry) parent[rx] = ry;
658 };
659
660 std::vector<size_t> chain_idx;
661 chain_idx.reserve(valid.size());
662 for (size_t i = 0; i < valid.size(); ++i)
663 if (is_chain(*valid[i].e)) chain_idx.push_back(i);
664
665 for (size_t a = 0; a < chain_idx.size(); ++a) {
666 const size_t i = chain_idx[a];
668 if (!endpoints(*valid[i].e, i0, i1)) continue;
669 for (size_t b = a + 1; b < chain_idx.size(); ++b) {
670 const size_t j = chain_idx[b];
672 if (!endpoints(*valid[j].e, j0, j1)) continue;
673 if (same(i0, j0) || same(i0, j1) || same(i1, j0) || same(i1, j1))
674 unite(int(i), int(j));
675 }
676 }
677
678
679 std::map<int, std::vector<size_t>> comps;
680 for (size_t i = 0; i < valid.size(); ++i) {
681 if (!is_chain(*valid[i].e)) continue;
682 comps[
find(
int(i))].push_back(i);
683 }
684
685
686 struct Loop {
size_t min_idx{0};
bool closed_single{
false};
size_t member{0}; std::vector<size_t> members; };
687 std::vector<Loop> loops;
688 for (size_t i = 0; i < valid.size(); ++i) {
689 const SketchEntity& e = *valid[i].e;
691 Loop l; l.min_idx = valid[i].idx; l.closed_single =
true; l.member = i;
692 loops.push_back(l);
693 }
694 }
695 for (const auto& kv : comps) {
696 Loop l; l.closed_single =
false; l.members = kv.second;
697 size_t mn = std::numeric_limits<size_t>::max();
698 for (size_t m : kv.second) mn = std::min(mn, valid[m].idx);
699 l.min_idx = mn;
700 loops.push_back(l);
701 }
702
703 std::sort(loops.begin(), loops.end(), [](const Loop& x, const Loop& y) { return x.min_idx < y.min_idx; });
704
705
706 std::vector<TopoDS_Wire> out;
707 out.reserve(loops.size());
708 for (const Loop& loop : loops) {
709 BRepBuilderAPI_MakeWire wm;
710 if (loop.closed_single) {
711 const SketchEntity& c = *valid[loop.member].e;
712 TopoDS_Edge e;
714 if (c.radius <= 1e-9 || c.rminor <= 1e-9) return {};
715 e = BRepBuilderAPI_MakeEdge(make_elips(c)).Edge();
716 } else {
717
718
719 if (c.radius <= 1e-9) return {};
720 Vec3d c3 = plane.to_world(c.center);
721 gp_Pnt
center(c3.x(), c3.y(), c3.z());
722 gp_Dir n(plane.normal.x(), plane.normal.y(), plane.normal.z());
723 gp_Circ circ(gp_Ax2(
center, n), c.radius);
724 e = BRepBuilderAPI_MakeEdge(circ).Edge();
725 }
726 wm.Add(e);
727 } else {
728
729
730
731
732
733
734
735 struct Member { size_t v; int a; int b; };
736 std::vector<Vec2d> node_pt;
737 std::vector<int> node_deg;
738 auto node_id = [&](
const Vec2d& p) ->
int {
739 for (size_t i = 0; i < node_pt.size(); ++i)
740 if ((node_pt[i] - p).norm() <= tol) return int(i);
741 node_pt.push_back(p);
742 node_deg.push_back(0);
743 return int(node_pt.size()) - 1;
744 };
745 std::vector<Member> ms;
746 ms.reserve(loop.members.size());
747 for (size_t m : loop.members) {
749 if (!endpoints(*valid[m].e, p0, p1)) return {};
750 int a = node_id(p0), b = node_id(p1);
751 node_deg[a]++; node_deg[b]++;
752 ms.push_back({m, a, b});
753 }
754
755
756
757 std::vector<size_t> order;
758 order.reserve(ms.size());
759 std::vector<char> used(ms.size(), 0);
760 size_t start = 0;
761 for (size_t i = 0; i < ms.size(); ++i)
762 if (node_deg[ms[i].a] == 1 || node_deg[ms[i].b] == 1) { start = i; break; }
763 const int start_node = (node_deg[ms[start].a] == 1) ? ms[start].a
764 : (node_deg[ms[start].b] == 1) ? ms[start].b
765 : ms[start].a;
766 int open = start_node;
767 for (;;) {
768 size_t next = ms.size();
769 for (size_t k = 0; k < ms.size(); ++k) {
770 if (used[k]) continue;
771 if (ms[k].a == open || ms[k].b == open) { next = k; break; }
772 }
773 if (next == ms.size()) break;
774 order.push_back(next);
775 used[next] = 1;
776 open = (ms[next].a == open) ? ms[next].b : ms[next].a;
777 }
778 if (order.size() != ms.size()) return {};
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794 if (closed_only) {
795 bool has_free_end = false;
796 for (const Member& mm : ms)
797 if (node_deg[mm.a] == 1 || node_deg[mm.b] == 1) { has_free_end = true; break; }
798 if (has_free_end) continue;
799 }
800
801
802
803
804
805
806 std::vector<TopoDS_Vertex> verts(node_pt.size());
807 BRep_Builder B;
808 for (size_t i = 0; i < node_pt.size(); ++i) {
809 Vec3d w = plane.to_world(node_pt[i]);
810 verts[i] = BRepBuilderAPI_MakeVertex(gp_Pnt(w.x(), w.y(), w.z())).Vertex();
811 B.UpdateVertex(verts[i], std::max(tol, Precision::Confusion()));
812 }
813
814 for (size_t o : order) {
815 const Member& mm = ms[o];
816 const SketchEntity* e = valid[mm.v].e;
817 const TopoDS_Vertex& va = verts[mm.a];
818 const TopoDS_Vertex& vb = verts[mm.b];
820 wm.Add(BRepBuilderAPI_MakeEdge(va, vb).
Edge());
822 if (e->radius <= 1e-9 || e->rminor <= 1e-9) return {};
823 GC_MakeArcOfEllipse arc_maker(make_elips(*e), e->start_angle, e->end_angle, true);
824 if (!arc_maker.IsDone()) return {};
825 wm.Add(BRepBuilderAPI_MakeEdge(arc_maker.Value(), va, vb).Edge());
827 Vec3d p0 = plane.to_world(e->p0);
828 Vec3d p1 = plane.to_world(e->p1);
829 double mid_angle = (e->start_angle + e->end_angle) * 0.5;
830 Vec2d mid_2d(e->center.x() + e->radius * std::cos(mid_angle),
831 e->center.y() + e->radius * std::sin(mid_angle));
832 Vec3d mid_3d = plane.to_world(mid_2d);
833 gp_Pnt pa(p0.x(), p0.y(), p0.z());
834 gp_Pnt pm(mid_3d.x(), mid_3d.y(), mid_3d.z());
835 gp_Pnt pb(p1.x(), p1.y(), p1.z());
836 GC_MakeArcOfCircle arc_maker(pa, pm, pb);
837 if (!arc_maker.IsDone()) return {};
838 Handle(Geom_TrimmedCurve) curve = arc_maker.Value();
839 wm.Add(BRepBuilderAPI_MakeEdge(curve, va, vb).
Edge());
841 Handle(Geom_BSplineCurve) crv = make_bspline(*e);
842 if (crv.IsNull()) return {};
843 wm.Add(BRepBuilderAPI_MakeEdge(crv, va, vb).
Edge());
844 }
845 }
846 }
847 wm.Build();
848
849
850
851
852 if (!wm.IsDone()) return {};
853 const TopoDS_Wire wire = wm.Wire();
854 size_t edge_count = 0;
855 for (TopExp_Explorer ex(wire, TopAbs_EDGE); ex.More(); ex.Next()) ++edge_count;
856 if (edge_count != (loop.closed_single ? 1 : loop.members.size())) return {};
857 out.push_back(wire);
858 }
859 return out;
860}
@ Edge
Definition Measure.hpp:26
_Item< ExPolygon > Item
Definition Arrange.cpp:93
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
double sketch_join_tol()
Definition SketchEngine.cpp:80
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key)
Definition RaycastManager.cpp:298
std::vector< VI > Loop
Definition CutSurface.cpp:301