// Teknik resim 2B ortho izdüşüm: OCCT HLR (gizli-çizgi kaldırma) ile B-Rep gövdesini // standart görünüme projeksiyon. Görünür/gizli keskin kenar + siluet → 2B polyline. #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 "fiko/geometri/brep.hpp" namespace fiko::geometri { namespace { // Projeksiyon ekseni: gp_Ax2(P, N, Vx) → N=bakış yönü (Z), Vx=sağ (X); izdüşüm X-Y düzlemine. gp_Ax2 gorunumEkseni(Gorunum g) { switch (g) { case Gorunum::On: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, -1, 0), gp_Dir(1, 0, 0)); case Gorunum::Arka: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0), gp_Dir(-1, 0, 0)); case Gorunum::Ust: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, -1), gp_Dir(1, 0, 0)); case Gorunum::Alt: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0)); case Gorunum::Sol: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0)); case Gorunum::Sag: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(-1, 0, 0), gp_Dir(0, 1, 0)); case Gorunum::Izometrik: default: return gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(1, 1, 1), gp_Dir(1, 0, -1)); } } // Projeksiyon kenar bileşiğini 2B polyline listesine örnekle (uniform sapma). std::vector> kenarlariPolyline(const TopoDS_Shape& s) { std::vector> sonuc; if (s.IsNull()) return sonuc; for (TopExp_Explorer e(s, TopAbs_EDGE); e.More(); e.Next()) { const TopoDS_Edge kenar = TopoDS::Edge(e.Current()); BRepAdaptor_Curve egri(kenar); GCPnts_QuasiUniformDeflection ornek(egri, 0.05); std::vector pl; if (ornek.IsDone()) { for (int i = 1; i <= ornek.NbPoints(); ++i) { const gp_Pnt p = ornek.Value(i); pl.push_back({p.X(), p.Y()}); // projeksiyon düzlemi X-Y } } if (pl.size() >= 2) sonuc.push_back(std::move(pl)); } return sonuc; } void ekle(std::vector>& hedef, std::vector> kaynak) { for (auto& pl : kaynak) hedef.push_back(std::move(pl)); } } // namespace Izdusum2D ortoIzdusum(const BrepGovde& g, Gorunum gorunum) { Izdusum2D r; if (!g.gecerliMi()) return r; try { Handle(HLRBRep_Algo) hlr = new HLRBRep_Algo(); hlr->Add(ic::sekil(g)); hlr->Projector(HLRAlgo_Projector(gorunumEkseni(gorunum))); hlr->Update(); hlr->Hide(); HLRBRep_HLRToShape sekle(hlr); // Görünür = keskin kenar + siluet (outline); gizli = keskin + siluet (kesikli çizim). ekle(r.gorunur, kenarlariPolyline(sekle.VCompound())); ekle(r.gorunur, kenarlariPolyline(sekle.OutLineVCompound())); ekle(r.gizli, kenarlariPolyline(sekle.HCompound())); ekle(r.gizli, kenarlariPolyline(sekle.OutLineHCompound())); r.gecerli = true; } catch (const Standard_Failure&) { return Izdusum2D{}; } return r; } GorunumEksen gorunumEksenleri(Gorunum gorunum) { const gp_Ax2 a = gorunumEkseni(gorunum); const gp_Pnt k = a.Location(); const gp_Dir dx = a.XDirection(), dy = a.YDirection(), dz = a.Direction(); return {{k.X(), k.Y(), k.Z()}, {dx.X(), dx.Y(), dx.Z()}, {dy.X(), dy.Y(), dy.Z()}, {dz.X(), dz.Y(), dz.Z()}}; } std::vector izdusumNoktalari(const BrepGovde& g, Gorunum gorunum) { std::vector sonuc; if (!g.gecerliMi()) return sonuc; const gp_Ax2 eksen = gorunumEkseni(gorunum); const gp_Pnt kok = eksen.Location(); const gp_Dir dx = eksen.XDirection(), dy = eksen.YDirection(); // 3B → görünüm düzlemi: HLR ile AYNI eksen takımı (ortoIzdusum ile hizalı kalır). const auto duzleme = [&](const gp_Pnt& p) { const gp_Vec v(kok, p); return Vec2d{v.X() * dx.X() + v.Y() * dx.Y() + v.Z() * dx.Z(), v.X() * dy.X() + v.Y() * dy.Y() + v.Z() * dy.Z()}; }; try { const TopoDS_Shape& s = ic::sekil(g); u32 ord = 0; TopTools_IndexedMapOfShape vmap; TopExp::MapShapes(s, TopAbs_VERTEX, vmap); for (int i = 1; i <= vmap.Extent(); ++i) { IzdusumNokta n; n.p = duzleme(BRep_Tool::Pnt(TopoDS::Vertex(vmap(i)))); n.tur = 0; n.ordinal = (u32)i; sonuc.push_back(n); } // Dairesel kenarların merkezi (delik/yuvarlatma ölçüsü buradan tutunur). ord = 0; for (TopExp_Explorer e(s, TopAbs_EDGE); e.More(); e.Next()) { ++ord; const TopoDS_Edge kenar = TopoDS::Edge(e.Current()); BRepAdaptor_Curve egri(kenar); if (egri.GetType() != GeomAbs_Circle) continue; IzdusumNokta n; n.p = duzleme(egri.Circle().Location()); n.tur = 1; n.ordinal = ord; sonuc.push_back(n); } } catch (const Standard_Failure&) { return {}; } return sonuc; } std::vector> kesitYuzKonturlari(const BrepGovde& g, Gorunum gorunum, Vec3d duzlemNokta, Vec3d duzlemNormal, f64 tolerans) { std::vector> sonuc; if (!g.gecerliMi()) return sonuc; const f64 nUz = std::sqrt(duzlemNormal.x * duzlemNormal.x + duzlemNormal.y * duzlemNormal.y + duzlemNormal.z * duzlemNormal.z); if (nUz < 1e-12) return sonuc; const gp_Dir hedefN(duzlemNormal.x / nUz, duzlemNormal.y / nUz, duzlemNormal.z / nUz); const gp_Pnt hedefP(duzlemNokta.x, duzlemNokta.y, duzlemNokta.z); const gp_Ax2 eksen = gorunumEkseni(gorunum); const gp_Pnt kok = eksen.Location(); const gp_Dir dx = eksen.XDirection(), dy = eksen.YDirection(); const auto duzleme = [&](const gp_Pnt& p) { const gp_Vec v(kok, p); return Vec2d{v.X() * dx.X() + v.Y() * dx.Y() + v.Z() * dx.Z(), v.X() * dy.X() + v.Y() * dy.Y() + v.Z() * dy.Z()}; }; try { for (TopExp_Explorer f(ic::sekil(g), TopAbs_FACE); f.More(); f.Next()) { const TopoDS_Face yuz = TopoDS::Face(f.Current()); BRepAdaptor_Surface sf(yuz); if (sf.GetType() != GeomAbs_Plane) continue; const gp_Pln pl = sf.Plane(); if (!pl.Axis().Direction().IsParallel(hedefN, 1e-4)) continue; // aynı doğrultu if (std::abs(pl.Distance(hedefP)) > tolerans * 100.0) continue; // AYNI düzlem for (TopExp_Explorer w(yuz, TopAbs_WIRE); w.More(); w.Next()) { std::vector kontur; for (BRepTools_WireExplorer we(TopoDS::Wire(w.Current()), yuz); we.More(); we.Next()) { BRepAdaptor_Curve egri(we.Current()); GCPnts_QuasiUniformDeflection ornek(egri, 0.05); if (!ornek.IsDone()) continue; const bool ters = we.Current().Orientation() == TopAbs_REVERSED; const int n = ornek.NbPoints(); for (int i = 1; i <= n; ++i) { // tel yönünde sıralı (kapalı kontur şart) const gp_Pnt p = ornek.Value(ters ? n - i + 1 : i); const Vec2d q = duzleme(p); if (!kontur.empty() && std::abs(kontur.back().x - q.x) < 1e-9 && std::abs(kontur.back().y - q.y) < 1e-9) continue; // ardışık tekrar noktayı at kontur.push_back(q); } } if (kontur.size() >= 3) sonuc.push_back(std::move(kontur)); } } } catch (const Standard_Failure&) { return {}; } return sonuc; } bool dxfKaydet(const BrepGovde& g, Gorunum gorunum, const std::string& yol) { const Izdusum2D iz = ortoIzdusum(g, gorunum); if (!iz.gecerli) return false; std::ofstream f(yol, std::ios::binary); if (!f) return false; f << "0\nSECTION\n2\nENTITIES\n"; // minimal DXF (R12 uyumlu ENTITIES bölümü) const auto yaz = [&](const std::vector>& gruplar, const char* katman) { for (const auto& pl : gruplar) for (size_t i = 0; i + 1 < pl.size(); ++i) f << "0\nLINE\n8\n" << katman << "\n" << "10\n" << pl[i].x << "\n20\n" << pl[i].y << "\n" << "11\n" << pl[i + 1].x << "\n21\n" << pl[i + 1].y << "\n"; }; yaz(iz.gorunur, "GORUNUR"); yaz(iz.gizli, "GIZLI"); f << "0\nENDSEC\n0\nEOF\n"; return true; } f64 izdusumAlani(const BrepGovde& g, Vec3d yon) { if (!g.gecerliMi()) return 0.0; const f64 uzun = std::sqrt(yon.nokta(yon)); if (uzun < 1e-12) return 0.0; const Vec3d n = yon * (1.0 / uzun); // birim bakış yönü const MeshVeri m = g.ucgenle({0.5f, 0.5f, 0.5f}); f64 toplam = 0.0; for (size_t i = 0; i + 2 < m.indeksler.size(); i += 3) { const auto& a = m.vertexler[m.indeksler[i]].konum; const auto& b = m.vertexler[m.indeksler[i + 1]].konum; const auto& c = m.vertexler[m.indeksler[i + 2]].konum; const Vec3d va{a[0], a[1], a[2]}, vb{b[0], b[1], b[2]}, vc{c[0], c[1], c[2]}; const Vec3d alanVek = (vb - va).capraz(vc - va); // 2× üçgen alan vektörü toplam += std::fabs(alanVek.nokta(n)); // izdüşen bileşen (mutlak) } // Kapalı katıda her siluet noktası 2 yüzeyle örtülür (ön+arka). alanVek=2×alan → ×0.25. return toplam * 0.25; } } // namespace fiko::geometri