#include "brep_ic.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // şişir: zaten-NURBS yüzeyde geometri paylaşımını kır (derin kopya) #include #include #include #include #include #include #include #include // şişir zinciri: sarılı yüzeyde taban aç #include #include #include #include #include // şişirmede bayat 3B kenar eğrisini düşür (pcurve'den yeniden kurulur) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fiko/core/gunluk.hpp" namespace fiko::geometri { using ic::dir; using ic::pnt; using ic::sar; using ic::uzunlukVec; // ---- GSD Wireframe (gercek OCCT B-Rep) --------------------------------- namespace { // Profil noktalarindan wire kur (kapali → son-ilk baglanir). <2 nokta → IsNull. TopoDS_Wire profilWire(const std::vector& kontur, bool kapali) { if (kontur.size() < 2) return {}; BRepBuilderAPI_MakePolygon poli; for (const Vec3d& p : kontur) poli.Add(pnt(p)); if (kapali && kontur.size() >= 3) poli.Close(); if (!poli.IsDone()) return {}; return poli.Wire(); } } // namespace BrepGovde nokta(Vec3d konum) { try { return sar(BRepBuilderAPI_MakeVertex(pnt(konum)).Vertex()); } catch (const Standard_Failure& h) { gunluk::hata("Nokta hatasi: {}", h.what()); return {}; } } BrepGovde cizgiIkiNokta(Vec3d p1, Vec3d p2) { if (uzunlukVec({p2.x - p1.x, p2.y - p1.y, p2.z - p1.z}) < 1e-9) return {}; try { return sar(BRepBuilderAPI_MakeEdge(pnt(p1), pnt(p2)).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Cizgi hatasi: {}", h.what()); return {}; } } BrepGovde cizgiYonUzunluk(Vec3d baslangic, Vec3d yon, f64 uzunluk) { const f64 n = uzunlukVec(yon); if (n < 1e-12 || uzunluk <= 1e-9) return {}; const Vec3d son{baslangic.x + yon.x / n * uzunluk, baslangic.y + yon.y / n * uzunluk, baslangic.z + yon.z / n * uzunluk}; return cizgiIkiNokta(baslangic, son); } BrepGovde cemberMerkezR(Vec3d merkez, Vec3d normal, f64 yaricap, f64 aciDerece) { if (yaricap <= 1e-9 || uzunlukVec(normal) < 1e-12) return {}; try { const gp_Ax2 eksen(pnt(merkez), dir(normal)); const gp_Circ cember(eksen, yaricap); if (aciDerece >= 359.999) return sar(BRepBuilderAPI_MakeEdge(cember).Edge()); // Yay: 0 → aci (radyan). GC_MakeArcOfCircle parametrik. const f64 aci = aciDerece * std::numbers::pi / 180.0; GC_MakeArcOfCircle yayYap(cember, 0.0, aci, true); if (!yayYap.IsDone()) return {}; return sar(BRepBuilderAPI_MakeEdge(yayYap.Value()).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Cember hatasi: {}", h.what()); return {}; } } BrepGovde cemberUcNokta(Vec3d p1, Vec3d p2, Vec3d p3) { try { GC_MakeCircle cemberYap(pnt(p1), pnt(p2), pnt(p3)); if (!cemberYap.IsDone()) { gunluk::uyari("Cember: 3 nokta dogrusal/cakisik"); return {}; } return sar(BRepBuilderAPI_MakeEdge(cemberYap.Value()->Circ()).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Cember (3 nokta) hatasi: {}", h.what()); return {}; } } BrepGovde splineBSpline(const std::vector& noktalar) { if (noktalar.size() < 2) return {}; try { TColgp_Array1OfPnt dizi(1, (int)noktalar.size()); for (size_t i = 0; i < noktalar.size(); ++i) dizi.SetValue((int)i + 1, pnt(noktalar[i])); GeomAPI_PointsToBSpline yap(dizi); if (!yap.IsDone()) { gunluk::uyari("Spline kurulamadi"); return {}; } const Handle(Geom_Curve) egri = yap.Curve(); // BSpline → Geom_Curve return sar(BRepBuilderAPI_MakeEdge(egri).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Spline hatasi: {}", h.what()); return {}; } } BrepGovde polyline(const std::vector& noktalar, bool kapali) { if (noktalar.size() < 2) return {}; try { const TopoDS_Wire wire = profilWire(noktalar, kapali); if (wire.IsNull()) return {}; return sar(wire); } catch (const Standard_Failure& h) { gunluk::hata("Polyline hatasi: {}", h.what()); return {}; } } BrepGovde helix(Vec3d merkez, Vec3d eksen, f64 yaricap, f64 adim, f64 tur, bool saga) { if (yaricap <= 1e-9 || adim <= 1e-9 || tur <= 1e-9 || uzunlukVec(eksen) < 1e-12) return {}; try { // Silindir yuzeyi uzerinde parametrik dogru: u=aci (rad), v=eksen boyu. Bir turda // u 2pi, v adim ilerler → helis. Geom2d_Line yon = (2pi, adim); param uzunlugu // birim-yon oldugundan tur-basi arc-uzunlugu sqrt((2pi)^2+adim^2). const gp_Ax3 eksenSis(pnt(merkez), dir(eksen)); Handle(Geom_CylindricalSurface) sil = new Geom_CylindricalSurface(eksenSis, yaricap); const f64 dU = saga ? 2.0 * std::numbers::pi : -2.0 * std::numbers::pi; const gp_Dir2d yon2d(dU, adim); const Geom2d_Line* h2 = new Geom2d_Line(gp_Ax2d(gp_Pnt2d(0.0, 0.0), yon2d)); Handle(Geom2d_Line) cizgi2d = h2; const f64 turUzunluk = std::sqrt(dU * dU + adim * adim); Handle(Geom2d_TrimmedCurve) seg = new Geom2d_TrimmedCurve(cizgi2d, 0.0, tur * turUzunluk); TopoDS_Edge kenar = BRepBuilderAPI_MakeEdge(seg, sil).Edge(); BRepLib::BuildCurves3d(kenar); // 2d param egriden gercek 3d egri kur (olcum/mesh icin) if (kenar.IsNull()) { gunluk::uyari("Helis kurulamadi"); return {}; } return sar(kenar); } catch (const Standard_Failure& h) { gunluk::hata("Helis hatasi: {}", h.what()); return {}; } } BrepGovde konik(Vec3d p1, Vec3d p2, Vec3d p3, f64 rho) { rho = std::clamp(rho, 0.02, 0.98); if (p1.mesafe(p2) < 1e-9 || p2.mesafe(p3) < 1e-9 || p1.mesafe(p3) < 1e-9) return {}; try { TColgp_Array1OfPnt kutup(1, 3); kutup.SetValue(1, pnt(p1)); kutup.SetValue(2, pnt(p2)); // omuz/tepe kutbu → rasyonel agirlik gerginligi kutup.SetValue(3, pnt(p3)); TColStd_Array1OfReal agirlik(1, 3); const f64 w = rho / (1.0 - rho); // rho=0.5 → w=1 (parabol); <0.5 elips; >0.5 hiperbol agirlik.SetValue(1, 1.0); agirlik.SetValue(2, w); agirlik.SetValue(3, 1.0); Handle(Geom_BezierCurve) egri = new Geom_BezierCurve(kutup, agirlik); return sar(BRepBuilderAPI_MakeEdge(egri).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Konik hatasi: {}", h.what()); return {}; } } BrepGovde kose(Vec3d u1, Vec3d c, Vec3d u2, f64 yaricap) { if (yaricap <= 1e-9) return {}; const Vec3d d1 = (u1 - c).birim(), d2 = (u2 - c).birim(); if (d1.uzunlukKare() < 0.5 || d2.uzunlukKare() < 0.5) return {}; const f64 kosinus = std::clamp(d1.nokta(d2), -1.0, 1.0); const f64 aci = std::acos(kosinus); if (aci < 1e-3 || aci > std::numbers::pi - 1e-3) return {}; // paralel/dogrusal → yay yok const f64 yari = aci * 0.5; const f64 tanjMesafe = yaricap / std::tan(yari); const Vec3d t1 = c + d1 * tanjMesafe, t2 = c + d2 * tanjMesafe; // teget noktalari const Vec3d aciortay = (d1 + d2).birim(); if (aciortay.uzunlukKare() < 0.5) return {}; const Vec3d merkez = c + aciortay * (yaricap / std::sin(yari)); const Vec3d yayOrta = merkez - aciortay * yaricap; // yayin koseye en yakin noktasi try { GC_MakeArcOfCircle yay(pnt(t1), pnt(yayOrta), pnt(t2)); if (!yay.IsDone()) return {}; return sar(BRepBuilderAPI_MakeEdge(yay.Value()).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Kose hatasi: {}", h.what()); return {}; } } // ---- GSD Temel Yuzey (acik shell) -------------------------------------- BrepGovde yuzeyPrizma(const std::vector& kontur, bool kapali, Vec3d yon, f64 mesafe) { if (kontur.size() < 2 || mesafe <= 1e-9) return {}; const f64 n = uzunlukVec(yon); if (n < 1e-12) return {}; yon = {yon.x / n, yon.y / n, yon.z / n}; try { const TopoDS_Wire wire = profilWire(kontur, kapali); if (wire.IsNull()) return {}; const gp_Vec itki(yon.x * mesafe, yon.y * mesafe, yon.z * mesafe); BRepPrimAPI_MakePrism supur(wire, itki); // wire → ruled shell (acik yuzey) supur.Build(); if (!supur.IsDone()) { gunluk::uyari("Yuzey extrude basarisiz"); return {}; } return sar(supur.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Yuzey extrude hatasi: {}", h.what()); return {}; } } BrepGovde yuzeyDondur(const std::vector& kontur, bool kapali, Vec3d eksenNokta, Vec3d eksenYon, f64 aciDerece) { if (kontur.size() < 2 || aciDerece <= 1e-6 || uzunlukVec(eksenYon) < 1e-12) return {}; try { const TopoDS_Wire wire = profilWire(kontur, kapali); if (wire.IsNull()) return {}; const gp_Ax1 eksen(pnt(eksenNokta), dir(eksenYon)); const f64 aci = aciDerece * std::numbers::pi / 180.0; BRepPrimAPI_MakeRevol donel(wire, eksen, aci); donel.Build(); if (!donel.IsDone()) { gunluk::uyari("Yuzey revolve basarisiz"); return {}; } return sar(donel.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Yuzey revolve hatasi: {}", h.what()); return {}; } } BrepGovde yuzeyFill(const std::vector& kontur) { if (kontur.size() < 3) return {}; try { const TopoDS_Wire wire = profilWire(kontur, true); // kapali profil if (wire.IsNull()) return {}; BRepBuilderAPI_MakeFace duzYuz(wire, true); // Only=true → yalnizca duzlemsel dene if (duzYuz.IsDone()) return sar(duzYuz.Face()); // Duzlemsel degil → N-kenarli yama (egri/burukmuş profil). BRepFill_Filling dolgu; for (TopExp_Explorer ex(wire, TopAbs_EDGE); ex.More(); ex.Next()) dolgu.Add(TopoDS::Edge(ex.Current()), GeomAbs_C0); dolgu.Build(); if (!dolgu.IsDone()) { gunluk::uyari("Yuzey fill basarisiz"); return {}; } return sar(dolgu.Face()); } catch (const Standard_Failure& h) { gunluk::hata("Yuzey fill hatasi: {}", h.what()); return {}; } } // Tanım yuzeySisirCok üstünde — pole-oynatan op'ların ortak NURBS+derin-kopya girişi. static TopoDS_Shape nurbsBagimsizKopya(const TopoDS_Face& yuz); BrepGovde yuzeyUzat(const BrepGovde& yuzey, f64 mesafe) { if (!yuzey.gecerliMi() || mesafe <= 1e-9) return {}; try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) { gunluk::uyari("Uzatilacak yuz yok"); return {}; } // NurbsConvert: yuzun SINIRLI (trimmed) NURBS yuzeyini verir. BRep_Tool::Surface // dogrudan cagirsa duzlem/silindir SONSUZ doner → GeomConvert reddeder. // nurbsBagimsizKopya: zaten-NURBS'te convert atlanır + derin kopya (zincir op güvenliği). const TopoDS_Shape nk = nurbsBagimsizKopya(TopoDS::Face(ex.Current())); TopExp_Explorer nex(nk, TopAbs_FACE); if (!nex.More()) return {}; Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(nex.Current())); Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf); if (bs.IsNull()) bs = GeomConvert::SurfaceToBSplineSurface(surf); if (bs.IsNull()) { gunluk::uyari("Yuzey B-spline'a cevrilemedi"); return {}; } // 4 yonde (U/V × once/sonra) dogal sinir boyunca uzat. C1 sureklilik korunur. Handle(Geom_BoundedSurface) sinirli = bs; GeomLib::ExtendSurfByLength(sinirli, mesafe, 1, Standard_True, Standard_True); GeomLib::ExtendSurfByLength(sinirli, mesafe, 1, Standard_True, Standard_False); GeomLib::ExtendSurfByLength(sinirli, mesafe, 1, Standard_False, Standard_True); GeomLib::ExtendSurfByLength(sinirli, mesafe, 1, Standard_False, Standard_False); if (sinirli.IsNull()) return {}; BRepBuilderAPI_MakeFace yeniYuz(sinirli, Precision::Confusion()); if (!yeniYuz.IsDone()) { gunluk::uyari("Uzatilmis yuzey kurulamadi"); return {}; } return sar(yeniYuz.Face()); } catch (const Standard_Failure& h) { gunluk::hata("Yuzey uzatma hatasi: {}", h.what()); return {}; } } BrepGovde sinir(const BrepGovde& yuzey) { if (!yuzey.gecerliMi()) return {}; try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) { gunluk::uyari("Sinir icin yuz yok"); return {}; } const TopoDS_Wire w = BRepTools::OuterWire(TopoDS::Face(ex.Current())); if (w.IsNull()) return {}; return sar(w); } catch (const Standard_Failure& h) { gunluk::hata("Sinir hatasi: {}", h.what()); return {}; } } namespace { // Bir govdenin TUM kenarlarindan tek wire kur (koprule kesit girdisi). TopoDS_Wire telWire(const BrepGovde& g) { BRepBuilderAPI_MakeWire wy; int n = 0; for (TopExp_Explorer ex(ic::sekil(g), TopAbs_EDGE); ex.More(); ex.Next()) { wy.Add(TopoDS::Edge(ex.Current())); ++n; } if (n == 0 || !wy.IsDone()) return {}; return wy.Wire(); } } // namespace BrepGovde koprule(const BrepGovde& a, const BrepGovde& b) { if (!a.gecerliMi() || !b.gecerliMi()) return {}; try { const TopoDS_Wire wa = telWire(a), wb = telWire(b); if (wa.IsNull() || wb.IsNull()) return {}; BRepOffsetAPI_ThruSections gen(Standard_False); // isSolid=false → açık shell köprü gen.AddWire(wa); gen.AddWire(wb); gen.Build(); if (!gen.IsDone()) { gunluk::uyari("Köprüleme başarısız"); return {}; } return sar(gen.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Köprüleme hatasi: {}", h.what()); return {}; } } BrepGovde loftYuzey(const std::vector& kesitler) { if (kesitler.size() < 2) return {}; try { BRepOffsetAPI_ThruSections gen(Standard_False); // isSolid=false → açık çok-kesitli shell int n = 0; for (const BrepGovde* kp : kesitler) { if (!kp || !kp->gecerliMi()) continue; const TopoDS_Wire w = telWire(*kp); // ham tel geometrisi (çember/spline korunur) if (w.IsNull()) continue; gen.AddWire(w); ++n; } if (n < 2) { gunluk::uyari("Loft için ≥2 geçerli kesit gerekli"); return {}; } gen.Build(); if (!gen.IsDone()) { gunluk::uyari("Loft başarısız (kesitler uyumsuz olabilir)"); return {}; } return sar(gen.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Loft hatasi: {}", h.what()); return {}; } } BrepGovde loftYuzeyKilavuz(const std::vector& kesitler, const BrepGovde& kilavuz) { if (kesitler.size() < 2 || !kilavuz.gecerliMi()) return {}; try { const TopoDS_Wire omurga = telWire(kilavuz); if (omurga.IsNull()) return {}; BRepOffsetAPI_MakePipeShell boru(omurga); // spine boyunca çok-kesit süpürme (CATIA loft+spine) int n = 0; for (const BrepGovde* kp : kesitler) { if (!kp || !kp->gecerliMi()) continue; const TopoDS_Wire w = telWire(*kp); if (w.IsNull()) continue; boru.Add(w); // kesitler dünya konumlarında (kılavuz üstünde/yakınında olmalı) ++n; } if (n < 2) { gunluk::uyari("Kılavuzlu loft için ≥2 geçerli kesit gerekli"); return {}; } boru.Build(); if (!boru.IsDone()) { gunluk::uyari("Kılavuzlu loft başarısız (kesit/kılavuz uyumsuz)"); return {}; } return sar(boru.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Kilavuzlu loft hatasi: {}", h.what()); return {}; } } BrepGovde yuzeyKirp(const BrepGovde& yuzey, const BrepGovde& kesici) { if (!yuzey.gecerliMi() || !kesici.gecerliMi()) return {}; try { BRepAlgoAPI_Splitter bol; // yüzeyi kesici (yüzey/eğri) ile parçalara böl TopTools_ListOfShape arg, tool; arg.Append(ic::sekil(yuzey)); tool.Append(ic::sekil(kesici)); bol.SetArguments(arg); bol.SetTools(tool); bol.Build(); if (!bol.IsDone() || bol.Shape().IsNull()) { gunluk::uyari("Yüzey kırpma başarısız"); return {}; } return sar(bol.Shape()); // tüm parçalar compound (istenmeyen parça sonra silinir) } catch (const Standard_Failure& h) { gunluk::hata("Yüzey kırpma hatasi: {}", h.what()); return {}; } } BrepGovde yamaYuzey(const std::vector& kenarlar) { if (kenarlar.empty()) return {}; try { BRepFill_Filling dolgu; // N-kenarlı sınırdan pürüzsüz yama yüzey (G0) int n = 0; for (const BrepGovde* kb : kenarlar) { if (!kb || !kb->gecerliMi()) continue; for (TopExp_Explorer ex(ic::sekil(*kb), TopAbs_EDGE); ex.More(); ex.Next()) { dolgu.Add(TopoDS::Edge(ex.Current()), GeomAbs_C0); ++n; } } if (n < 3) { gunluk::uyari("Yama için ≥3 sınır kenarı gerekli"); return {}; } dolgu.Build(); if (!dolgu.IsDone()) { gunluk::uyari("Yama başarısız (sınır kapalı/düzlemsel mi?)"); return {}; } return sar(dolgu.Face()); } catch (const Standard_Failure& h) { gunluk::hata("Yama hatasi: {}", h.what()); return {}; } } bool yuzeyOrneklemGrid(const BrepGovde& yuzey, int nu, int nv, std::vector& noktalar) { noktalar.clear(); if (!yuzey.gecerliMi() || nu < 2 || nv < 2) return false; try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) return false; const TopoDS_Face yuz = TopoDS::Face(ex.Current()); Handle(Geom_Surface) s = BRep_Tool::Surface(yuz); if (s.IsNull()) return false; Standard_Real u0, u1, v0, v1; BRepTools::UVBounds(yuz, u0, u1, v0, v1); // yüzün gerçek (trimmed) parametre kutusu if (u1 - u0 < 1e-9 || v1 - v0 < 1e-9) return false; noktalar.reserve((size_t)nu * nv); for (int j = 0; j < nv; ++j) { const f64 v = v0 + (v1 - v0) * (f64)j / (nv - 1); for (int i = 0; i < nu; ++i) { const f64 u = u0 + (u1 - u0) * (f64)i / (nu - 1); const gp_Pnt p = s->Value(u, v); noktalar.push_back({p.X(), p.Y(), p.Z()}); } } return true; } catch (const Standard_Failure& h) { gunluk::hata("Yüzey grid örneklem hatasi: {}", h.what()); noktalar.clear(); return false; } } BrepGovde kesisimEgrisi(const BrepGovde& a, const BrepGovde& b) { if (!a.gecerliMi() || !b.gecerliMi()) return {}; try { BRepAlgoAPI_Section kesit(ic::sekil(a), ic::sekil(b), Standard_False); kesit.Approximation(Standard_True); // pürüzsüz B-spline kenar (facetsiz) kesit.Build(); if (!kesit.IsDone()) { gunluk::uyari("Kesisim hesaplanamadi"); return {}; } const TopoDS_Shape sonuc = kesit.Shape(); TopExp_Explorer ex(sonuc, TopAbs_EDGE); if (!ex.More()) return {}; // kesismiyor → bos → gecersiz return sar(sonuc); } catch (const Standard_Failure& h) { gunluk::hata("Kesisim egrisi hatasi: {}", h.what()); return {}; } } BrepGovde supurmeYuzey(const std::vector& profil, bool profilKapali, const std::vector& yol) { if (profil.size() < 2 || yol.size() < 2) return {}; try { const TopoDS_Wire profWire = profilWire(profil, profilKapali); const TopoDS_Wire yolWire = profilWire(yol, false); // kilavuz her zaman acik yol if (profWire.IsNull() || yolWire.IsNull()) return {}; BRepOffsetAPI_MakePipe boru(yolWire, profWire); // profil WIRE → shell (kati degil) boru.Build(); if (!boru.IsDone()) { gunluk::uyari("Supurme yuzeyi basarisiz"); return {}; } return sar(boru.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Supurme yuzeyi hatasi: {}", h.what()); return {}; } } BrepGovde supurmeYuzey(const BrepGovde& profil, const BrepGovde& yol) { if (!profil.gecerliMi() || !yol.gecerliMi()) return {}; const TopoDS_Wire profWire = telWire(profil); // mevcut yardımcı (koprule ile ortak) const TopoDS_Wire yolWire = telWire(yol); if (profWire.IsNull() || yolWire.IsNull()) return {}; try { BRepOffsetAPI_MakePipe boru(yolWire, profWire); // profil WIRE → shell (kati degil) boru.Build(); if (!boru.IsDone()) { gunluk::uyari("Supurme yuzeyi basarisiz (tel)"); return {}; } return sar(boru.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Supurme yuzeyi (tel) hatasi: {}", h.what()); return {}; } } BrepGovde birlestirEgriler(const BrepGovde& tel) { if (!tel.gecerliMi()) return {}; try { GeomConvert_CompCurveToBSplineCurve birlesik; int n = 0; for (TopExp_Explorer ex(ic::sekil(tel), TopAbs_EDGE); ex.More(); ex.Next()) { f64 ilk = 0, son = 0; Handle(Geom_Curve) egri = BRep_Tool::Curve(TopoDS::Edge(ex.Current()), ilk, son); if (egri.IsNull()) continue; Handle(Geom_TrimmedCurve) kirp = new Geom_TrimmedCurve(egri, ilk, son); birlesik.Add(kirp, Precision::Confusion()); ++n; } if (n == 0) { gunluk::uyari("Birlestirilecek kenar yok"); return {}; } Handle(Geom_BSplineCurve) bs = birlesik.BSplineCurve(); if (bs.IsNull()) { gunluk::uyari("Egriler birlestirilemedi (zincir ucuca degil?)"); return {}; } return sar(BRepBuilderAPI_MakeEdge(bs).Edge()); } catch (const Standard_Failure& h) { gunluk::hata("Egri birlestirme hatasi: {}", h.what()); return {}; } } BrepGovde onar(const BrepGovde& govde, f64 tol) { if (!govde.gecerliMi()) return {}; try { ShapeFix_Shape duzelt(ic::sekil(govde)); duzelt.SetPrecision(tol); duzelt.SetMaxTolerance(tol * 100.0); duzelt.Perform(); const TopoDS_Shape sonuc = duzelt.Shape(); if (sonuc.IsNull()) return {}; return sar(sonuc); } catch (const Standard_Failure& h) { gunluk::hata("Onar hatasi: {}", h.what()); return {}; } } BrepGovde telSupur(const BrepGovde& tel, Vec3d yon, f64 mesafe) { if (!tel.gecerliMi() || mesafe <= 1e-9) return {}; const f64 n = uzunlukVec(yon); if (n < 1e-12) return {}; yon = {yon.x / n, yon.y / n, yon.z / n}; try { const gp_Vec itki(yon.x * mesafe, yon.y * mesafe, yon.z * mesafe); BRepPrimAPI_MakePrism supur(ic::sekil(tel), itki); // ham tel (edge/wire) → ruled shell supur.Build(); if (!supur.IsDone()) { gunluk::uyari("Tel supurme basarisiz"); return {}; } return sar(supur.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Tel supurme hatasi: {}", h.what()); return {}; } } bool telDuzlemNormal(const BrepGovde& tel, Vec3d& merkez, Vec3d& normal) { if (!tel.gecerliMi()) return false; std::vector nok; const int ke = topolojiOzeti(tel).kenarSayi; for (int e = 1; e <= ke; ++e) { const std::vector ep = tel.kenarNoktalari((u32)e); for (const Vec3d& p : ep) nok.push_back(p); } if (nok.size() < 3) return false; Vec3d c{}; for (const Vec3d& p : nok) c = c + p; c = c / (f64)nok.size(); // Newell yontemi: kapali/acik poligonun saglam duzlem normali (dejenere kenarlara dayanikli). Vec3d nn{}; for (size_t i = 0; i < nok.size(); ++i) { const Vec3d& a = nok[i]; const Vec3d& b = nok[(i + 1) % nok.size()]; nn.x += (a.y - b.y) * (a.z + b.z); nn.y += (a.z - b.z) * (a.x + b.x); nn.z += (a.x - b.x) * (a.y + b.y); } if (uzunlukVec(nn) < 1e-9) return false; // dogrusal → normal belirsiz merkez = c; normal = nn.birim(); return true; } // Yüzü NURBS temsilli BAĞIMSIZ kopyaya getirir (pole-oynatan GSD op'larının ortak girişi). // 1) Yüzey ZATEN B-spline ise NurbsConvert ATLANIR — NurbsConvert zaten-NURBS yüzde yüzeyi // NULL bırakıyor (zincir şişir/reshape çökmesinin köküydü; hata "resource deadlock" // kılığında GeomConvert(NULL)'dan geliyordu). 2) Her durumda DERİN kopya: pole mutasyonu // girdi gövdesinin geometrisine sızmaz (paylaşılan TShape → bellek bozulması tuzağı). static TopoDS_Shape nurbsBagimsizKopya(const TopoDS_Face& yuz) { TopoDS_Shape kaynak = yuz; Handle(Geom_Surface) g = BRep_Tool::Surface(yuz); Handle(Geom_Surface) taban = g; if (Handle(Geom_RectangularTrimmedSurface) rt = Handle(Geom_RectangularTrimmedSurface)::DownCast(g); !rt.IsNull()) taban = rt->BasisSurface(); if (Handle(Geom_BSplineSurface)::DownCast(taban).IsNull()) kaynak = BRepBuilderAPI_NurbsConvert(yuz).Shape(); return BRepBuilderAPI_Copy(kaynak, /*copyGeom*/ Standard_True).Shape(); } BrepGovde yuzeySisirCok(const BrepGovde& yuzey, const std::vector>& hedefler, f64 yaricap, bool sinirKilit, int kilitDerinlik) { if (!yuzey.gecerliMi() || yaricap <= 1e-9 || hedefler.empty()) return {}; bool anlamli = false; // en az bir hedefin anlamlı miktarı olmalı for (const auto& h : hedefler) if (std::abs(h.second) >= 1e-9) { anlamli = true; break; } if (!anlamli) return {}; YuzBilgi yb; if (!yuzey.yuzBilgi(1, yb, /*alanHesapla=*/false)) return {}; // yalnız normal gerekli (alan pahalı) Vec3d n = yb.normal; const f64 nl = uzunlukVec(n); if (nl < 1e-12) return {}; n = {n.x / nl, n.y / nl, n.z / nl}; // şişirme yönü = yüzey normali try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) return {}; const TopoDS_Shape nkopya = nurbsBagimsizKopya(TopoDS::Face(ex.Current())); TopExp_Explorer nex(nkopya, TopAbs_FACE); if (!nex.More()) return {}; Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(nex.Current())); // Sarılı (RectangularTrimmed) yüzeyde taban B-spline'ı aç — GeomConvert gereksizleşir. if (Handle(Geom_RectangularTrimmedSurface) rt = Handle(Geom_RectangularTrimmedSurface)::DownCast(surf); !rt.IsNull()) surf = rt->BasisSurface(); Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf); if (bs.IsNull()) bs = GeomConvert::SurfaceToBSplineSurface(surf); if (bs.IsNull()) return {}; // Zenginleştir: düz yüz 2×2 pole'la gelir → pürüzsüz kubbe için derece + knot ekle. if (bs->UDegree() < 3 || bs->VDegree() < 3) bs->IncreaseDegree(3, 3); f64 u0, u1, v0, v1; bs->Bounds(u0, u1, v0, v1); const int bol = 8; // UV bölünme → yeterli kontrol noktası (kubbe çözünürlüğü) const f64 tolp = Precision::PConfusion(); for (int i = 1; i < bol; ++i) { const f64 up = u0 + (u1 - u0) * i / bol, vp = v0 + (v1 - v0) * i / bol; try { bs->InsertUKnot(up, 1, tolp); } catch (const Standard_Failure&) {} try { bs->InsertVKnot(vp, 1, tolp); } catch (const Standard_Failure&) {} } const int nu = bs->NbUPoles(), nv = bs->NbVPoles(); const int upd = bs->UDegree(), vpd = bs->VDegree(); // PER-POLE LOKAL NORMAL: her pole kendi Greville-UV yüzey normali boyunca kaydırılır (tek global // normal DEĞİL). Düz yüzde tüm lokal normaller = global → eski davranış birebir; ÇOK EĞRİ yüzeyde // (tekrar-şişirilen kubbe) şişirme yüzeyi izler. Normaller ÖNCE (deforme etmeden) hesaplanır + // global n ile hizalanır (dot<0 → çevir) → tutarlı işaret, düz yüzde regresyonsuz. std::vector poleN((size_t)nu * nv, n); if (upd >= 1 && vpd >= 1) { TColStd_Array1OfReal uks(1, nu + upd + 1), vks(1, nv + vpd + 1); bs->UKnotSequence(uks); bs->VKnotSequence(vks); std::vector gu(nu + 1), gv(nv + 1); for (int i = 1; i <= nu; ++i) { f64 s2 = 0; for (int k = 1; k <= upd; ++k) s2 += uks(i + k); gu[i] = s2 / upd; } for (int j = 1; j <= nv; ++j) { f64 s2 = 0; for (int k = 1; k <= vpd; ++k) s2 += vks(j + k); gv[j] = s2 / vpd; } for (int iu = 1; iu <= nu; ++iu) for (int iv = 1; iv <= nv; ++iv) { gp_Pnt pp; gp_Vec du, dv; bs->D1(gu[iu], gv[iv], pp, du, dv); gp_Vec nn = du.Crossed(dv); if (nn.Magnitude() > 1e-12) { nn.Normalize(); Vec3d ln{nn.X(), nn.Y(), nn.Z()}; if (ln.x * n.x + ln.y * n.y + ln.z * n.z < 0.0) ln = {-ln.x, -ln.y, -ln.z}; // global ile hizala poleN[(size_t)(iu - 1) * nv + (iv - 1)] = ln; } } } // Her pole'a TÜM hedeflerin falloff katkılarını topla → çoklu tepe/çukur tek yüzeyde. // sinirKilit: GÖRÜNÜR sınıra (trim tel örnekleri) kd×yerel-aralık içindeki pole SABİT. // Eski UV-DİKDÖRTGEN halkası kilidi kırpılmış/fill yüzeyde YANLIŞ halkayı kilitliyordu: // görünür çember kenarından geçen pole'lar KISMEN kilitlenince etek diş diş taraklanıyordu // (Fikri ekranı). Dikdörtgen (kırpılmamış) yüzeyde sınır=UV halkası → davranış eskiyle aynı. const int kd = sinirKilit ? std::clamp(kilitDerinlik, 1, 2) : 0; std::vector sinirNok; if (kd > 0) { const auto ozk = topolojiOzeti(yuzey); for (int e = 1; e <= ozk.kenarSayi; ++e) for (const Vec3d& sp : yuzey.kenarNoktalari((u32)e)) sinirNok.push_back(sp); } const auto sinirdaMi = [&](int iu, int iv, const Vec3d& p) -> bool { if (kd <= 0 || sinirNok.empty()) return false; f64 aralik = 0.0; // yerel pole aralığı: 4-komşu ortalaması (grid ölçeğinden bağımsız eşik) int ns = 0; const auto komsu = [&](int ju, int jv) { if (ju < 1 || ju > nu || jv < 1 || jv > nv) return; const gp_Pnt q = bs->Pole(ju, jv); aralik += uzunlukVec({q.X() - p.x, q.Y() - p.y, q.Z() - p.z}); ++ns; }; komsu(iu - 1, iv); komsu(iu + 1, iv); komsu(iu, iv - 1); komsu(iu, iv + 1); if (!ns) return false; const f64 esik = (aralik / ns) * kd * 0.99; // 0.99: tam bir-aralık komşu halka dışarıda kalsın f64 enYakin2 = 1e300; for (const Vec3d& sp : sinirNok) { const Vec3d f2{p.x - sp.x, p.y - sp.y, p.z - sp.z}; const f64 d2 = f2.x * f2.x + f2.y * f2.y + f2.z * f2.z; if (d2 < enYakin2) enYakin2 = d2; } return enYakin2 < esik * esik; }; for (int iu = 1; iu <= nu; ++iu) for (int iv = 1; iv <= nv; ++iv) { const gp_Pnt P = bs->Pole(iu, iv); const Vec3d p{P.X(), P.Y(), P.Z()}; if (sinirdaMi(iu, iv, p)) continue; f64 acc = 0.0; for (const auto& [hedef, miktar] : hedefler) { const f64 d = uzunlukVec({p.x - hedef.x, p.y - hedef.y, p.z - hedef.z}); if (d >= yaricap) continue; const f64 x = d / yaricap; acc += miktar * (1.0 - x * x) * (1.0 - x * x); // pürüzsüz falloff (tepe=1, kenar=0) } if (std::abs(acc) < 1e-12) continue; const Vec3d& ln = poleN[(size_t)(iu - 1) * nv + (iv - 1)]; bs->SetPole(iu, iv, gp_Pnt(p.x + ln.x * acc, p.y + ln.y * acc, p.z + ln.z * acc)); } // KIRPMA KORUNUR (Fikri 07-22: "dairesel yüzey şişince KAREYE dönüşüyor"): MakeFace(bs) // yüzeyi UV dikdörtgeninden SIFIRDAN kurup trim tellerini atıyordu. Pole kaydırma UV // parametrizasyonunu değiştirmez → orijinal tel/pcurve'ler aynen geçerli; yüzey yerinde // güncellenir. Sınır kilitsiz deformda 3B kenar eğrileri bayatlar → ShapeFix pcurve'den tazeler. TopoDS_Face nf = TopoDS::Face(nex.Current()); BRep_Builder bb; bb.UpdateFace(nf, bs, TopLoc_Location(), BRep_Tool::Tolerance(nf)); // 3B kenar eğrileri ESKİ yüzeye ait (bayat) → düşür, pcurve'lerden deforme yüzey // üzerinde yeniden kur (ShapeFix tek başına eğriyi tazelemiyor, tolerans şişiriyordu — // kilitsiz şişirmede kenar yerinde kalmış görünüyordu). ShapeBuild_Edge sbe; for (TopExp_Explorer ee(nf, TopAbs_EDGE); ee.More(); ee.Next()) sbe.RemoveCurve3d(TopoDS::Edge(ee.Current())); BRepLib::BuildCurves3d(nf); // ESKİ üçgenleme yüz üstünde taşınıyor → render bayat (düz) mesh'i çiziyordu // ("kenarlar şekilleniyor, yüzey aynı kalıyor"). Temizle → deforme yüzey yeniden mesh'lenir. BRepTools::Clean(nf); ShapeFix_Shape sfx(nf); sfx.Perform(); const TopoDS_Shape ns = sfx.Shape(); BrepGovde sg; if (!ns.IsNull()) sg = sar(ns); // şişir sonucu AÇIK yüzey — doluMu (katı) değil geçerlilik if (!sg.gecerliMi()) sg = sar(nf); // fix düşerse ham güncellenmiş yüz (geometri doğru) return sg; } catch (const Standard_Failure& h) { gunluk::hata("Yuzey sisirme hatasi: {}", h.what()); return {}; } } BrepGovde yuzeySisir(const BrepGovde& yuzey, Vec3d hedefNokta, f64 yaricap, f64 miktar) { return yuzeySisirCok(yuzey, {{hedefNokta, miktar}}, yaricap); // tek-hedef = çok-hedef özel hali } BrepGovde kenarKaydir(const BrepGovde& yuzey, Vec3d kenarNokta, Vec3d vec) { if (!yuzey.gecerliMi() || uzunlukVec(vec) < 1e-9) return {}; try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) return {}; // nurbsBagimsizKopya: zaten-NURBS'te convert atlanır + derin kopya (zincir op güvenliği). const TopoDS_Shape nk = nurbsBagimsizKopya(TopoDS::Face(ex.Current())); TopExp_Explorer nex(nk, TopAbs_FACE); if (!nex.More()) return {}; Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(nex.Current())); Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf); if (bs.IsNull()) bs = GeomConvert::SurfaceToBSplineSurface(surf); if (bs.IsNull()) return {}; if (bs->UDegree() < 3 || bs->VDegree() < 3) bs->IncreaseDegree(3, 3); f64 u0, u1, v0, v1; bs->Bounds(u0, u1, v0, v1); const int bol = 6; // pürüzsüz reshape için ek kontrol noktası const f64 tolp = Precision::PConfusion(); for (int i = 1; i < bol; ++i) { const f64 up = u0 + (u1 - u0) * i / bol, vp = v0 + (v1 - v0) * i / bol; try { bs->InsertUKnot(up, 1, tolp); } catch (const Standard_Failure&) {} try { bs->InsertVKnot(vp, 1, tolp); } catch (const Standard_Failure&) {} } const int nu = bs->NbUPoles(), nv = bs->NbVPoles(); if (nu < 2 || nv < 2) return {}; // Hangi sınır (U0/U1/V0/V1) kenarNokta'ya en yakın → o pole sırası/sütunu taşınır. const gp_Pnt kn(kenarNokta.x, kenarNokta.y, kenarNokta.z); const f64 um = (u0 + u1) * 0.5, vm = (v0 + v1) * 0.5; const f64 dU0 = bs->Value(u0, vm).SquareDistance(kn), dU1 = bs->Value(u1, vm).SquareDistance(kn); const f64 dV0 = bs->Value(um, v0).SquareDistance(kn), dV1 = bs->Value(um, v1).SquareDistance(kn); int hangi = 0; f64 best = dU0; // 0=U0 1=U1 2=V0 3=V1 if (dU1 < best) { best = dU1; hangi = 1; } if (dV0 < best) { best = dV0; hangi = 2; } if (dV1 < best) { best = dV1; hangi = 3; } // Seçili sınır poleleri TAM, karşı sınıra doğru smoothstep ile 0'a (kenar taşınır, karşı sabit). for (int iu = 1; iu <= nu; ++iu) for (int iv = 1; iv <= nv; ++iv) { f64 w = hangi == 0 ? (f64)(nu - iu) / (nu - 1) : hangi == 1 ? (f64)(iu - 1) / (nu - 1) : hangi == 2 ? (f64)(nv - iv) / (nv - 1) : (f64)(iv - 1) / (nv - 1); if (w <= 1e-9) continue; w = w * w * (3.0 - 2.0 * w); // smoothstep (pürüzsüz geçiş) const gp_Pnt P = bs->Pole(iu, iv); bs->SetPole(iu, iv, gp_Pnt(P.X() + vec.x * w, P.Y() + vec.y * w, P.Z() + vec.z * w)); } BRepBuilderAPI_MakeFace yeni(bs, Precision::Confusion()); if (!yeni.IsDone()) { gunluk::uyari("Kenar kaydırma yüzeyi kurulamadı"); return {}; } return sar(yeni.Face()); } catch (const Standard_Failure& h) { gunluk::hata("Kenar kaydirma hatasi: {}", h.what()); return {}; } } BrepGovde yuzeyDuzelt(const BrepGovde& yuzey, f64 miktar, int iterasyon) { if (!yuzey.gecerliMi() || iterasyon < 1) return {}; miktar = std::clamp(miktar, 0.0, 1.0); try { TopExp_Explorer ex(ic::sekil(yuzey), TopAbs_FACE); if (!ex.More()) return {}; // nurbsBagimsizKopya: zaten-NURBS'te convert atlanır + derin kopya (zincir op güvenliği). const TopoDS_Shape nk = nurbsBagimsizKopya(TopoDS::Face(ex.Current())); TopExp_Explorer nex(nk, TopAbs_FACE); if (!nex.More()) return {}; Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(nex.Current())); Handle(Geom_BSplineSurface) bs = Handle(Geom_BSplineSurface)::DownCast(surf); if (bs.IsNull()) bs = GeomConvert::SurfaceToBSplineSurface(surf); if (bs.IsNull()) return {}; const int nu = bs->NbUPoles(), nv = bs->NbVPoles(); if (nu < 3 || nv < 3) return sar(nk); // iç pole yok → yumuşatılamaz (no-op) for (int it = 0; it < iterasyon; ++it) { std::vector yeni; // Jacobi: eski değerlerden hesapla, toptan yaz yeni.reserve((nu - 2) * (nv - 2)); for (int iu = 2; iu < nu; ++iu) for (int iv = 2; iv < nv; ++iv) { const gp_Pnt P = bs->Pole(iu, iv); const gp_Pnt L = bs->Pole(iu - 1, iv), R = bs->Pole(iu + 1, iv); const gp_Pnt D = bs->Pole(iu, iv - 1), U = bs->Pole(iu, iv + 1); const f64 ax = (L.X() + R.X() + D.X() + U.X()) * 0.25; const f64 ay = (L.Y() + R.Y() + D.Y() + U.Y()) * 0.25; const f64 az = (L.Z() + R.Z() + D.Z() + U.Z()) * 0.25; yeni.emplace_back(P.X() + (ax - P.X()) * miktar, P.Y() + (ay - P.Y()) * miktar, P.Z() + (az - P.Z()) * miktar); } size_t k = 0; for (int iu = 2; iu < nu; ++iu) for (int iv = 2; iv < nv; ++iv) bs->SetPole(iu, iv, yeni[k++]); } BRepBuilderAPI_MakeFace yf(bs, Precision::Confusion()); if (!yf.IsDone()) { gunluk::uyari("Düzeltme yüzeyi kurulamadı"); return {}; } return sar(yf.Face()); } catch (const Standard_Failure& h) { gunluk::hata("Yuzey duzeltme hatasi: {}", h.what()); return {}; } } BrepGovde kenarCikar(const BrepGovde& govde, u32 kenarOrdinal) { if (!govde.gecerliMi() || kenarOrdinal < 1) return {}; try { u32 i = 0; for (TopExp_Explorer ex(ic::sekil(govde), TopAbs_EDGE); ex.More(); ex.Next()) if (++i == kenarOrdinal) return sar(ex.Current()); // TopExp sirasi = secim ordinali return {}; } catch (const Standard_Failure& h) { gunluk::hata("Kenar cikarma hatasi: {}", h.what()); return {}; } } BrepGovde afin(const BrepGovde& hedef, f64 oranX, f64 oranY, f64 oranZ) { if (!hedef.gecerliMi() || std::abs(oranX) < 1e-6 || std::abs(oranY) < 1e-6 || std::abs(oranZ) < 1e-6) return {}; try { gp_GTrsf gt; // kosegen olcek (eksen-bagimsiz); diger terimler 0 → kayma/kirpma yok gt.SetValue(1, 1, oranX); gt.SetValue(2, 2, oranY); gt.SetValue(3, 3, oranZ); BRepBuilderAPI_GTransform donusum(ic::sekil(hedef), gt, Standard_True); donusum.Build(); if (!donusum.IsDone()) { gunluk::uyari("Afin donusum basarisiz"); return {}; } return sar(donusum.Shape()); } catch (const Standard_Failure& h) { gunluk::hata("Afin donusum hatasi: {}", h.what()); return {}; } } } // namespace fiko::geometri