#include "fiko/sahne/sketch_nesne.hpp" #include #include #include #include #include "fiko/cekirdek/olay.hpp" namespace fiko { u32 kenar3DSketchGecir(eskiz::EskizVeri& ev, const geometri::BrepGovde& g, u32 kenarOrdinal, const Donusumd& govdeDonusum, const Donusumd& duzlemDonusum, bool yapi) { geometri::KenarBilgi kb; if (!g.gecerliMi() || !g.kenarBilgi(kenarOrdinal, kb)) return 0; const Donusumd duzlemTers = duzlemDonusum.ters(); // Gövde-yerel → dünya → sketch düzlem uzayı; z atılır (düzleme dik izdüşüm). const auto uv = [&](Vec3d yerel) -> Vec2d { const Vec3d d = duzlemTers.noktaUygula(govdeDonusum.noktaUygula(yerel)); return {d.x, d.y}; }; u32 kimlik = 0; if (kb.dogruMu) { const Vec2d a = uv(kb.bas), b = uv(kb.son); kimlik = ev.cizgiEkle(a.x, a.y, b.x, b.y); } else if (kb.cemberMi && kb.yaricap > 1e-9) { // Kapalı çember + normali düzleme PARALEL → gerçek daire (yarıçap izdüşümde // korunur). Yay veya eğik çember → spline yoluna düşer (izdüşümü elips olur; // GeoTip'te elips-yay eşlemesi MVP dışı — spline sadık yaklaşım). const bool kapali = (kb.bas - kb.son).uzunlukKare() < 1e-12; const Vec3d dunyaN = govdeDonusum.yonelim.dondur(kb.normal); const Vec3d duzlemN = duzlemDonusum.yonelim.dondur({0, 0, 1}); const f64 nl = std::sqrt(dunyaN.uzunlukKare() * duzlemN.uzunlukKare()); const bool paralel = nl > 1e-12 && std::abs(dunyaN.nokta(duzlemN)) / nl > 0.99999; if (kapali && paralel) { const Vec2d m = uv(kb.merkez); kimlik = ev.daireEkle(m.x, m.y, kb.yaricap); } } if (kimlik == 0) { // spline yolu: polyline örneklemesi geçiş noktası olur const std::vector poly = g.kenarNoktalari(kenarOrdinal); if (poly.size() < 2) return 0; std::vector> gecis; gecis.reserve(poly.size()); for (const Vec3d& p : poly) { const Vec2d q = uv(p); gecis.emplace_back(q.x, q.y); } kimlik = ev.splineEkle(gecis); } if (kimlik && yapi) ev.yapiAyarla(kimlik, true); return kimlik; } std::vector arakesit3DSketchGecir(eskiz::EskizVeri& ev, const geometri::BrepGovde& g, const Donusumd& govdeDonusum, const Donusumd& duzlemDonusum, bool yapi) { std::vector sonuc; if (!g.gecerliMi()) return sonuc; // Sketch düzlemini GÖVDE-YEREL uzaya taşı (brepKesit yerel çalışır — kesit // sistemi kalıbı), sonuç polyline'ları dünya → düzlem UV'ye (kesit tam düzlem // üzerinde olduğundan z≈0, izdüşüm kayıpsız). const Donusumd govdeTers = govdeDonusum.ters(); const Donusumd duzlemTers = duzlemDonusum.ters(); const Vec3d yerelNokta = govdeTers.noktaUygula(duzlemDonusum.konum); const Vec3d yerelNormal = govdeTers.yonelim.dondur(duzlemDonusum.yonelim.dondur({0, 0, 1})); const auto egriler = geometri::brepKesit(g, yerelNokta, yerelNormal, 0.05); for (const auto& poly : egriler) { if (poly.size() < 2) continue; std::vector> gecis; gecis.reserve(poly.size()); for (const Vec3d& p : poly) { const Vec3d d = duzlemTers.noktaUygula(govdeDonusum.noktaUygula(p)); gecis.emplace_back(d.x, d.y); } const u32 k = ev.splineEkle(gecis); if (!k) continue; if (yapi) ev.yapiAyarla(k, true); sonuc.push_back(k); } return sonuc; } // Sketch → 2D kapalı profil konturları (ham u,v). sketchProfilleri'nin 2D portu — d3() dünya // transform YOK; ProfilEgri2d üretir (wrap/emboss hedef yüzeyin UV'sine eşler). bool sketchKontur2d(const eskiz::EskizVeri& ev, std::vector& konturlar) { using GT = eskiz::GeoTip; using PT = geometri::ProfilEgri2d::Tip; konturlar.clear(); struct AcikEgri { Vec2d bas, son; geometri::ProfilEgri2d egri; }; std::vector acik; for (const eskiz::Geometri& g : ev.geometriler()) { if (g.yapi || g.tip == GT::Nokta) continue; // Spline wrap/emboss MVP DIŞI (ProfilEgri2d'de spline tipi yok): atla — aşağıdaki // daire yolu px(g.ir=-1) taşması yapardı. Spline'lı sketch'te wrap kalan konturlarla // çalışır; spline desteği ProfilEgri2d genişleyince eklenir. if (g.tip == GT::Spline) continue; if (g.tip == GT::Cizgi) { const Vec2d a{ev.noktaX(g.kimlik, 0), ev.noktaY(g.kimlik, 0)}; const Vec2d b{ev.noktaX(g.kimlik, 1), ev.noktaY(g.kimlik, 1)}; geometri::ProfilEgri2d e; e.tip = PT::Cizgi; e.p0 = a; e.p1 = b; acik.push_back({a, b, e}); continue; } const f64 cx = ev.noktaX(g.kimlik, 2), cy = ev.noktaY(g.kimlik, 2); const bool elips = g.tip == GT::Elips; const f64 ra = ev.px(g.ir); const f64 rb = elips ? ev.px(g.ir2) : ra; if (ra < 1e-9 || rb < 1e-9) continue; const f64 rot = elips ? ev.px(g.iaci) : 0.0; const bool yayVar = (g.ib1 >= 0 && g.ib2 >= 0); const f64 a0 = yayVar ? ev.px(g.ib1) : 0.0; const f64 a1 = yayVar ? ev.px(g.ib2) : 2.0 * std::numbers::pi; geometri::ProfilEgri2d e; e.merkez = {cx, cy}; e.yaricap = ra; e.kucukYaricap = rb; e.aci0 = a0; e.aci1 = a1; e.rot = rot; const auto uc = [&](int i) { return Vec2d{ev.noktaX(g.kimlik, i), ev.noktaY(g.kimlik, i)}; }; if (elips) { e.tip = PT::Elips; if (yayVar) { const Vec2d q0 = uc(0), q1 = uc(1); e.p0 = q0; e.p1 = q1; acik.push_back({q0, q1, e}); } else konturlar.push_back({e}); // tam elips (kapalı tek eğri) } else if (yayVar) { // Yay — GERÇEK uç noktalar (zincir & solver-güncel) e.tip = PT::Yay; const Vec2d q0 = uc(0), q1 = uc(1); e.p0 = q0; e.p1 = q1; acik.push_back({q0, q1, e}); } else { // Çember (tam) e.tip = PT::Cember; konturlar.push_back({e}); } } // Açık eğrileri uç-uca zincirle → kapalı ProfilKontur2d (sketchProfilleri ile AYNI mantık). constexpr f64 tol = 1e-4; const auto yakin = [&](const Vec2d& p, const Vec2d& q) { return std::hypot(p.x - q.x, p.y - q.y) < tol; }; std::vector kull(acik.size(), false); for (size_t i = 0; i < acik.size(); ++i) { if (kull[i]) continue; geometri::ProfilKontur2d kontur{acik[i].egri}; Vec2d bas = acik[i].bas, son = acik[i].son; kull[i] = true; bool buyudu = true; while (buyudu && !yakin(son, bas)) { buyudu = false; for (size_t j = 0; j < acik.size(); ++j) { if (kull[j]) continue; if (yakin(acik[j].bas, son)) { kontur.push_back(acik[j].egri); son = acik[j].son; kull[j] = true; buyudu = true; break; } if (yakin(acik[j].son, son)) { kontur.push_back(acik[j].egri); son = acik[j].bas; kull[j] = true; buyudu = true; break; } } } if (yakin(son, bas)) konturlar.push_back(std::move(kontur)); } return !konturlar.empty(); } // ---- SketchNesnesi ---- void SketchNesnesi::hesapla(Dunya&, OlayGunlugu& gunluk) { // Duzlem/parametre degisince recompute: kisit cozucuyu calistir. eskiz::Solver::Sonuc s = eskiz_.coz(); gunluk.yayinla(SketchCozuldu{kimlik_, static_cast(s.dof)}); } std::string SketchNesnesi::ad() const { const Dugum* d = dugum(); return d ? d->ad : std::string(); } void SketchNesnesi::adAyarla(const std::string& yeni) { if (Dugum* d = dugum()) d->ad = yeni; } OzellikSeti SketchNesnesi::ozellikler(Dunya& dunya) { OzellikSeti s; const Varlik k = kimlik_; const Varlik dz = duzlem_; // Bağlı düzlem adı (salt okunur — parametrik referans) Ozellik duzlem = Ozellik::metin( "Düzlem", [&dunya, dz]() -> std::string { if (NesneKok* kok = dunya.bul(dz); kok && *kok) return (*kok)->ad(); return std::string(); }, nullptr); duzlem.saltOkunur = true; s.push_back(std::move(duzlem)); // Görünür (Bayrak) s.push_back(Ozellik::bayrak( "Görünür", [&dunya, k] { Dugum* d = dunya.bul(k); return d ? d->gorunur : false; }, [&dunya, k](bool g) { if (Dugum* d = dunya.bul(k)) d->gorunur = g; })); return s; } // ---- SketchGorunum ---- bool SketchGorunum::gorunur() const { const Dugum* d = dugum(); return d ? d->gorunur : false; } void SketchGorunum::gorunurAyarla(bool g) { if (Dugum* d = dugum()) d->gorunur = g; } Vec3f SketchGorunum::agacRengi() const { const Dugum* d = dugum(); return d ? d->renk : Vec3f{0.9f, 0.9f, 0.35f}; } namespace { // Eskiz verisine ulaş (SketchNesnesi görünür-olmayan kökten; ucuz — vektör boyu okur). const eskiz::EskizVeri* eskizVeri(Dunya& dunya, Varlik kimlik) { NesneKok* nk = dunya.bul(kimlik); auto* sn = (nk && *nk) ? dynamic_cast(nk->get()) : nullptr; return sn ? &sn->eskiz() : nullptr; } } // namespace // CATIA ağaç etiketi: geometri/kısıt tip adları + ikon glifi (ürün ağacı alt-öğeleri // + sketch UI etiketleri — sketch_nesne.hpp'de bildirildi, dış bağlantı). const char* geoTipAd(eskiz::GeoTip t) { switch (t) { case eskiz::GeoTip::Nokta: return "Point"; case eskiz::GeoTip::Cizgi: return "Line"; case eskiz::GeoTip::Daire: return "Circle"; case eskiz::GeoTip::Yay: return "Arc"; case eskiz::GeoTip::Elips: return "Ellipse"; case eskiz::GeoTip::Spline: return "Spline"; } return "Geometry"; } const char* geoTipGlif(eskiz::GeoTip t) { switch (t) { case eskiz::GeoTip::Nokta: return "•"; case eskiz::GeoTip::Cizgi: return "╱"; case eskiz::GeoTip::Daire: return "◯"; case eskiz::GeoTip::Yay: return "⌒"; case eskiz::GeoTip::Elips: return "⬭"; case eskiz::GeoTip::Spline: return "∿"; } return "▪"; } const char* kisitTipAd(eskiz::KisitTip t) { switch (t) { case eskiz::KisitTip::Cakisik: return "Coincidence"; case eskiz::KisitTip::NoktaUzerinde:return "On Curve"; case eskiz::KisitTip::Yatay: return "Horizontal"; case eskiz::KisitTip::Dikey: return "Vertical"; case eskiz::KisitTip::Paralel: return "Parallelism"; case eskiz::KisitTip::Dik: return "Perpendicularity"; case eskiz::KisitTip::Tegel: return "Tangency"; case eskiz::KisitTip::Esit: return "Equality"; case eskiz::KisitTip::Simetrik: return "Symmetry"; case eskiz::KisitTip::Mesafe: return "Distance"; case eskiz::KisitTip::YatayMesafe: return "Horizontal Distance"; case eskiz::KisitTip::DikeyMesafe: return "Vertical Distance"; case eskiz::KisitTip::Yaricap: return "Radius"; case eskiz::KisitTip::Cap: return "Diameter"; case eskiz::KisitTip::Aci: return "Angle"; case eskiz::KisitTip::Sabit: return "Fix"; case eskiz::KisitTip::Semimajor: return "Major Radius"; case eskiz::KisitTip::Semiminor: return "Minor Radius"; case eskiz::KisitTip::Midpoint: return "Midpoint"; } return "Constraint"; } const char* kisitTipGlif(eskiz::KisitTip t) { switch (t) { case eskiz::KisitTip::Cakisik: return "⊙"; case eskiz::KisitTip::NoktaUzerinde:return "⊙"; case eskiz::KisitTip::Yatay: return "─"; case eskiz::KisitTip::Dikey: return "│"; case eskiz::KisitTip::Paralel: return "∥"; case eskiz::KisitTip::Dik: return "⊥"; case eskiz::KisitTip::Tegel: return "◠"; case eskiz::KisitTip::Esit: return "="; case eskiz::KisitTip::Simetrik: return "⧉"; case eskiz::KisitTip::Mesafe: return "↔"; case eskiz::KisitTip::YatayMesafe: return "↔"; case eskiz::KisitTip::DikeyMesafe: return "↕"; case eskiz::KisitTip::Yaricap: return "⌀"; case eskiz::KisitTip::Cap: return "⌀"; case eskiz::KisitTip::Aci: return "∠"; case eskiz::KisitTip::Sabit: return "⚓"; case eskiz::KisitTip::Semimajor: return "⌀"; case eskiz::KisitTip::Semiminor: return "⌀"; case eskiz::KisitTip::Midpoint: return "⋈"; } return "▪"; } std::string SketchGorunum::agacMiniBilgi(Dunya& dunya) const { const eskiz::EskizVeri* e = eskizVeri(dunya, kimlik_); if (!e || e->bos()) return {}; return std::to_string(e->geoSayisi()) + " geo · " + std::to_string(e->kisitSayisi()) + " kısıt"; } void SketchGorunum::agacRozetleri(Dunya& dunya, std::vector& out) const { const eskiz::EskizVeri* e = eskizVeri(dunya, kimlik_); if (!e || e->bos()) return; AgacRozet r; const int dof = e->dof(); if (dof <= 0) { r.metin = "✓"; r.renk = agacRenk(64, 210, 110); } // çözüldü (yeşil) else { r.metin = "DOF " + std::to_string(dof); r.renk = agacRenk(255, 180, 60); } // serbest (turuncu) out.push_back(std::move(r)); } void SketchGorunum::agacSanalCocuklar(Dunya& dunya, std::vector& out) const { const eskiz::EskizVeri* e = eskizVeri(dunya, kimlik_); if (!e) return; const Varlik disamb = kimlik_; // aynı etiketli düğüm farklı sketch'te çakışmasın const auto dugum = [disamb](const char* etiket, const char* glif, Arketip a, SketchOge oge = SketchOge::Yok, u32 ogeK = 0) { AgacDugum d; d.etiket = etiket; d.simge = glif; d.arketip = a; d.camKimlik = disamb; d.sketchOge = oge; d.sketchOgeKimlik = ogeK; return d; }; // ---- AbsoluteAxis (Origin + H/V yön) ---- AgacDugum eksen = dugum("AbsoluteAxis", "✛", Arketip::Grup); eksen.cocuklar.push_back(dugum("Origin", "⊙", Arketip::Datum, SketchOge::Origin)); eksen.cocuklar.push_back(dugum("HDirection", "→", Arketip::Datum, SketchOge::HYon)); eksen.cocuklar.push_back(dugum("VDirection", "↑", Arketip::Datum, SketchOge::VYon)); out.push_back(std::move(eksen)); // ---- Geometry (her eskiz öğesi: Point.N / Line.N / Circle.N / Arc.N / Ellipse.N) ---- AgacDugum geo = dugum("Geometry", "✎", Arketip::Grup); for (const eskiz::Geometri& g : e->geometriler()) { char buf[48]; std::snprintf(buf, sizeof buf, "%s.%u", geoTipAd(g.tip), g.kimlik); // Construction (yapı) geometri → soluk (Datum stili); gerçek profil → normal. geo.cocuklar.push_back(dugum(buf, geoTipGlif(g.tip), g.yapi ? Arketip::Datum : Arketip::Genel, SketchOge::Geometri, g.kimlik)); } out.push_back(std::move(geo)); // ---- Constraints (Parallelism.N / Tangency.N / Radius.N ...) ---- AgacDugum kis = dugum("Constraints", "◱", Arketip::Grup); for (const eskiz::Kisit& k : e->kisitlar()) { char buf[48]; std::snprintf(buf, sizeof buf, "%s.%u", kisitTipAd(k.tip), k.kimlik); kis.cocuklar.push_back(dugum(buf, kisitTipGlif(k.tip), Arketip::Genel, SketchOge::Kisit, k.kimlik)); } out.push_back(std::move(kis)); } } // namespace fiko