#include "fiko/geometri/poligon_ofset.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace fiko::geometri { namespace { constexpr f64 SAPMA = 0.01; // egri (yay) dogrusallastirma sapmasi (mm) // XY poligonundan kapali OCCT wire (Z=0 duzleminde). <3 nokta → bos. TopoDS_Wire wireYap(const Poligon& p) { if (p.size() < 3) return {}; BRepBuilderAPI_MakePolygon mp; for (const Vec2d& n : p) mp.Add(gp_Pnt(n.x, n.y, 0.0)); mp.Close(); return mp.IsDone() ? mp.Wire() : TopoDS_Wire{}; } // Wire'i dogrusallastirilmis kapali XY poligonuna cevir (son != ilk). Poligon wireCevir(const TopoDS_Wire& w) { Poligon out; for (BRepTools_WireExplorer ex(w); ex.More(); ex.Next()) { BRepAdaptor_Curve c(ex.Current()); GCPnts_QuasiUniformDeflection ornek(c, SAPMA); if (!ornek.IsDone()) continue; const bool ters = ex.Current().Orientation() == TopAbs_REVERSED; const int n = ornek.NbPoints(); // Son noktayi atla (bir sonraki kenarin ilkiyle cakisir). for (int k = 1; k < n; ++k) { const int idx = ters ? n - k + 1 : k; const gp_Pnt g = ornek.Value(idx); out.push_back({g.X(), g.Y()}); } } return out; } // Poligon isaretli alani (shoelace). Pozitif = CCW. f64 isaretliAlan(const Poligon& p) { f64 a = 0; for (size_t i = 0; i < p.size(); ++i) { const Vec2d& u = p[i]; const Vec2d& v = p[(i + 1) % p.size()]; a += u.x * v.y - v.x * u.y; } return a * 0.5; } // Shape icindeki tum wire'lari 2D poligonlara cikar (>=3 nokta). // Sonuc [0] = en buyuk alanli (dis sinir), digerleri delik konvansiyonunda siralanir. PoligonKumesi wirelariCevir(const TopoDS_Shape& s) { PoligonKumesi out; for (TopExp_Explorer ex(s, TopAbs_WIRE); ex.More(); ex.Next()) { Poligon p = wireCevir(TopoDS::Wire(ex.Current())); if (p.size() >= 3) out.push_back(std::move(p)); } if (out.size() > 1) { // en buyuk mutlak alan basa (dis sinir konvansiyonu) size_t enB = 0; f64 enA = std::abs(isaretliAlan(out[0])); for (size_t i = 1; i < out.size(); ++i) { const f64 a = std::abs(isaretliAlan(out[i])); if (a > enA) { enA = a; enB = i; } } std::swap(out[0], out[enB]); } return out; } // Poligon kumesinden planar face(ler) (ilk = dis, sonrakiler delik wire olarak). TopoDS_Face faceYap(const PoligonKumesi& konturlar) { if (konturlar.empty()) return {}; const TopoDS_Wire dis = wireYap(konturlar[0]); if (dis.IsNull()) return {}; BRepBuilderAPI_MakeFace mf(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), dis); for (size_t i = 1; i < konturlar.size(); ++i) { const TopoDS_Wire ic = wireYap(konturlar[i]); if (!ic.IsNull()) mf.Add(ic); } return mf.IsDone() ? mf.Face() : TopoDS_Face{}; } } // namespace PoligonKumesi poligonOfset(const PoligonKumesi& konturlar, f64 delta) { PoligonKumesi out; if (konturlar.empty()) return out; if (std::abs(delta) < 1e-9) return konturlar; try { // Tek kontur → duz wire ofseti (profil telafisi). Cok kontur → bolge (dis+delik) // face ofseti: dis sinir delta kadar, delikler ters yonde buyur/kucul (dogru). if (konturlar.size() == 1) { const TopoDS_Wire w = wireYap(konturlar[0]); if (w.IsNull()) return out; BRepOffsetAPI_MakeOffset off(w, GeomAbs_Arc); off.Perform(delta); if (!off.IsDone()) return out; return wirelariCevir(off.Shape()); } const TopoDS_Face f = faceYap(konturlar); if (f.IsNull()) return out; BRepOffsetAPI_MakeOffset off(f, GeomAbs_Arc); off.Perform(delta); if (!off.IsDone()) return out; return wirelariCevir(off.Shape()); } catch (const Standard_Failure&) { return {}; } } PoligonKumesi poligonFark(const PoligonKumesi& a, const PoligonKumesi& b) { try { const TopoDS_Face fa = faceYap(a); const TopoDS_Face fb = faceYap(b); if (fa.IsNull()) return {}; if (fb.IsNull()) return wirelariCevir(fa); BRepAlgoAPI_Cut cut(fa, fb); if (!cut.IsDone()) return wirelariCevir(fa); return wirelariCevir(cut.Shape()); } catch (const Standard_Failure&) { return {}; } } PoligonKumesi poligonBirlesim(const PoligonKumesi& a) { if (a.size() <= 1) return a; try { TopoDS_Shape acc = faceYap({a[0]}); if (acc.IsNull()) return a; for (size_t i = 1; i < a.size(); ++i) { const TopoDS_Face f = faceYap({a[i]}); if (f.IsNull()) continue; BRepAlgoAPI_Fuse fuse(acc, f); if (fuse.IsDone()) acc = fuse.Shape(); } PoligonKumesi out = wirelariCevir(acc); return out.empty() ? a : out; } catch (const Standard_Failure&) { return a; } } } // namespace fiko::geometri