#include "fiko/gsd/gsd_sistemi.hpp" #include "fiko/sketch/eskiz_segment.hpp" // merkezi eskiz→segment (çember/elips/yay) #include "fiko/sketch/nurbs_egri.hpp" // Spline NURBS render için #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/core/gunluk.hpp" #include "fiko/geometri/brep.hpp" #include "fiko/gsd/gsd_registry.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/sahne/sketch_nesne.hpp" namespace fiko::gsd { namespace { using geometri::BrepGovde; // Bir eskiz geometrisini 2B polyline segmentlerine cevir (yerel uv). // Eskiz→segment dönüşümü MERKEZİ (fiko/sketch/eskiz_segment.hpp): eskiden burada bir // İKİZ vardı ve çemberin yarıçapını nokta[0] mesafesinden hesapladığı için tam çember // içeren sketch'te hiç segment üretmiyordu (ölçüldü 07-21). Kopya kaldırıldı. using eskiz::Seg2B; using eskiz::geoSegmentle; // Segmentlerden TEK zincir cikar (uc-uca). kapali: bas~son ise true dondur. // Yuzey profili icin ilk zincir yeter (Dalga 1). Bos → false. bool zincirTek(std::vector seg, std::vector& zincir, bool& kapali) { 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; }; if (seg.empty()) return false; std::vector kullanildi(seg.size(), false); zincir = {seg[0].a, seg[0].b}; kullanildi[0] = true; bool buyudu = true; while (buyudu) { buyudu = false; const Vec2d son = zincir.back(); if (yakin(son, zincir.front()) && zincir.size() >= 3) break; for (size_t j = 0; j < seg.size(); ++j) { if (kullanildi[j]) continue; if (yakin(seg[j].a, son)) { zincir.push_back(seg[j].b); kullanildi[j] = true; buyudu = true; break; } if (yakin(seg[j].b, son)) { zincir.push_back(seg[j].a); kullanildi[j] = true; buyudu = true; break; } } } kapali = zincir.size() >= 4 && yakin(zincir.front(), zincir.back()); if (kapali) zincir.pop_back(); // ortuk kapali (son==ilk atilir) return zincir.size() >= 2; } // Aktif sketch profilini DUNYA-uzayi tek kontura cevir (yuzey feature girdisi). // Ayrica duzlem +Z normali (extrude yonu) + duzlem eksenleri (revolve icin) doner. bool sketchProfili(Cekirdek& cekirdek, Sahne& sahne, Varlik sketch, std::vector& kontur, bool& kapali, Vec3d& normal, Vec3d& eksenX, Vec3d& eksenY, Vec3d& duzlemMerkez) { kontur.clear(); auto* sk = dynamic_cast(cekirdek.nesne(sketch)); if (!sk) return false; const Dugum* dz = sahne.bul(sk->duzlem()); if (!dz) return false; const eskiz::EskizVeri& ev = sk->eskiz(); std::vector seg; for (const eskiz::Geometri& g : ev.geometriler()) { if (g.yapi) continue; geoSegmentle(ev, g, seg); } std::vector uv; if (!zincirTek(std::move(seg), uv, kapali)) return false; for (const Vec2d& p : uv) kontur.push_back(dz->donusum.noktaUygula({p.x, p.y, 0.0})); normal = dz->donusum.yonelim.dondur({0, 0, 1}); eksenX = dz->donusum.yonelim.dondur({1, 0, 0}); eksenY = dz->donusum.yonelim.dondur({0, 1, 0}); duzlemMerkez = dz->donusum.konum; return kontur.size() >= 2; } // Feature param haritasindan wireframe/yuzey B-rep uret (tip'e gore). BrepGovde uret(Cekirdek& cekirdek, Sahne& sahne, GsdFeature& f, std::string& hata) { const std::string& tip = f.tip(); if (tip == "nokta") { return geometri::nokta({f.p("px"), f.p("py"), f.p("pz")}); } if (tip == "cizgi") { const int mod = (int)(f.p("cizgiTip") + 0.5); const Vec3d a{f.p("ax"), f.p("ay"), f.p("az")}; if (mod == 0) { const Vec3d b{f.p("bx"), f.p("by"), f.p("bz")}; BrepGovde g = geometri::cizgiIkiNokta(a, b); if (!g.gecerliMi()) hata = "Başlangıç ve bitiş çakışık"; return g; } const Vec3d yon{f.p("dx"), f.p("dy"), f.p("dz")}; BrepGovde g = geometri::cizgiYonUzunluk(a, yon, f.p("uzunluk")); if (!g.gecerliMi()) hata = "Yön sıfır ya da uzunluk geçersiz"; return g; } if (tip == "cember") { const int mod = (int)(f.p("cemberTip") + 0.5); if (mod == 0) { const Vec3d m{f.p("cx"), f.p("cy"), f.p("cz")}; const Vec3d n{f.p("nx"), f.p("ny"), f.p("nz")}; BrepGovde g = geometri::cemberMerkezR(m, n, f.p("yaricap"), f.p("aci", 360.0)); if (!g.gecerliMi()) hata = "Yarıçap ya da normal geçersiz"; return g; } BrepGovde g = geometri::cemberUcNokta({f.p("p1x"), f.p("p1y"), f.p("p1z")}, {f.p("p2x"), f.p("p2y"), f.p("p2z")}, {f.p("p3x"), f.p("p3y"), f.p("p3z")}); if (!g.gecerliMi()) hata = "Üç nokta doğrusal ya da çakışık"; return g; } if (tip == "spline") { const int n = std::clamp((int)(f.p("nokta") + 0.5), 2, 8); std::vector pts; for (int i = 0; i < n; ++i) { const std::string b = "s" + std::to_string(i); pts.push_back({f.p(b + "x"), f.p(b + "y"), f.p(b + "z")}); } BrepGovde g = geometri::splineBSpline(pts); if (!g.gecerliMi()) hata = "Spline kurulamadı (noktaları kontrol edin)"; return g; } if (tip == "polyline") { const int n = std::clamp((int)(f.p("nokta") + 0.5), 2, 12); std::vector pts; for (int i = 0; i < n; ++i) { const std::string b = "s" + std::to_string(i); pts.push_back({f.p(b + "x"), f.p(b + "y"), f.p(b + "z")}); } BrepGovde g = geometri::polyline(pts, f.p("kapali") > 0.5); if (!g.gecerliMi()) hata = "Polyline kurulamadı (noktaları kontrol edin)"; return g; } if (tip == "helix") { const int e = (int)(f.p("eksen") + 0.5); const Vec3d eksen = (e == 1) ? Vec3d{1, 0, 0} : (e == 2) ? Vec3d{0, 1, 0} : Vec3d{0, 0, 1}; BrepGovde g = geometri::helix({f.p("cx"), f.p("cy"), f.p("cz")}, eksen, f.p("yaricap", 5.0), f.p("adim", 5.0), f.p("tur", 3.0), f.p("sol") < 0.5); if (!g.gecerliMi()) hata = "Helis kurulamadı (yarıçap/adım/tur pozitif olmalı)"; return g; } if (tip == "konik") { BrepGovde g = geometri::konik({f.p("p1x"), f.p("p1y"), f.p("p1z")}, {f.p("p2x"), f.p("p2y"), f.p("p2z")}, {f.p("p3x"), f.p("p3y"), f.p("p3z")}, f.p("rho", 0.5)); if (!g.gecerliMi()) hata = "Konik kurulamadı (noktalar çakışık/doğrusal)"; return g; } if (tip == "kose") { BrepGovde g = geometri::kose({f.p("u1x"), f.p("u1y"), f.p("u1z")}, {f.p("cx"), f.p("cy"), f.p("cz")}, {f.p("u2x"), f.p("u2y"), f.p("u2z")}, f.p("yaricap", 2.0)); if (!g.gecerliMi()) hata = "Köşe yayı kurulamadı (doğrular paralel/doğrusal)"; return g; } // ---- Iki-kaynak op (her iki kaynak dugumu gerekli) ---- if (tip == "kesisimEgri" || tip == "koprule" || tip == "supurmeYuzey" || tip == "loftYuzey" || tip == "yuzeyKirp" || tip == "loftKilavuz") { const Dugum* ka = sahne.bul(f.kaynak()); const Dugum* kb = sahne.bul(f.kaynak2()); if (!ka || !ka->brep || !ka->brep->gecerliMi() || !kb || !kb->brep || !kb->brep->gecerliMi()) { hata = "İki geçerli kaynak gerekli (iki öğe seçin)"; return {}; } if (tip == "loftYuzey") { // kaynak + kaynak2 + ekKaynaklar → sıralı kesit teli listesi (3+ kesit). std::vector kesitler{ka->brep.get(), kb->brep.get()}; for (Varlik e : f.ekKaynaklar()) if (const Dugum* de = sahne.bul(e); de && de->brep && de->brep->gecerliMi()) kesitler.push_back(de->brep.get()); BrepGovde g = geometri::loftYuzey(kesitler); if (!g.gecerliMi()) hata = "Loft oluşturulamadı (kesitler uyumsuz olabilir)"; return g; } if (tip == "yuzeyKirp") { BrepGovde g = geometri::yuzeyKirp(*ka->brep, *kb->brep); // kaynak=yüzey, kaynak2=kesici if (!g.gecerliMi()) hata = "Yüzey kırpma başarısız (kesişmiyor olabilir)"; return g; } if (tip == "loftKilavuz") { // kaynak = KILAVUZ, kaynak2 + ekKaynaklar = sıralı kesitler. std::vector kesitler{kb->brep.get()}; for (Varlik e : f.ekKaynaklar()) if (const Dugum* de = sahne.bul(e); de && de->brep && de->brep->gecerliMi()) kesitler.push_back(de->brep.get()); BrepGovde g = geometri::loftYuzeyKilavuz(kesitler, *ka->brep); if (!g.gecerliMi()) hata = "Kılavuzlu loft başarısız (≥2 kesit + kılavuz tel gerekli)"; return g; } if (tip == "koprule") { BrepGovde g = geometri::koprule(*ka->brep, *kb->brep); if (!g.gecerliMi()) hata = "Köprü yüzeyi kurulamadı (iki kenar/tel seçin)"; return g; } if (tip == "supurmeYuzey") { // kaynak = profil teli, kaynak2 = kılavuz yol teli → açık süpürme yüzeyi. BrepGovde g = geometri::supurmeYuzey(*ka->brep, *kb->brep); if (!g.gecerliMi()) hata = "Süpürme başarısız (profil + yol teli seçin)"; return g; } BrepGovde g = geometri::kesisimEgrisi(*ka->brep, *kb->brep); if (!g.gecerliMi()) hata = "Kesişim eğrisi yok (gövdeler kesişmiyor)"; return g; } // ---- Yuzey-uzeri op (kaynak GSD yuzey dugumu gerekli) ---- if (tip == "yuzeyOffset" || tip == "yuzeyExtrapolate" || tip == "yuzeyThicken" || tip == "sinir" || tip == "afin" || tip == "yuzeyCikart" || tip == "birlestir" || tip == "onar" || tip == "telExtrude" || tip == "kenarExtrude" || tip == "yuzeySisir" || tip == "yuzeyDuzelt" || tip == "yamaYuzey" || tip == "kenarKaydir") { const Dugum* kd = sahne.bul(f.kaynak()); if (!kd || !kd->brep || !kd->brep->gecerliMi()) { hata = "Kaynak geçersiz (bir yüzey/tel ya da katı yüz seçin)"; return {}; } const BrepGovde& kaynak = *kd->brep; if (tip == "yamaYuzey") { const int kn = (int)(f.p("kenarSayi", 0.0) + 0.5); if (kn > 0) { // KATI kenarlarından yama: k{i} ordinalleri kaynaktan kenarCikar ile tel'e → N-kenar. std::vector sahipli; for (int i = 0; i < kn; ++i) { const u32 ord = (u32)(f.p("k" + std::to_string(i), 0.0) + 0.5); geometri::BrepGovde t = geometri::kenarCikar(kaynak, ord); if (t.gecerliMi()) sahipli.push_back(std::move(t)); } std::vector ptr; ptr.reserve(sahipli.size()); for (const auto& t : sahipli) ptr.push_back(&t); BrepGovde g = geometri::yamaYuzey(ptr); if (!g.gecerliMi()) hata = "Yama oluşturulamadı (≥3 geçerli katı kenarı gerekli)"; return g; } // kaynak (kapalı tel ya da ilk kenar) + ekKaynaklar → N-kenar sınırdan yama. std::vector kenarlar{&kaynak}; for (Varlik e : f.ekKaynaklar()) if (const Dugum* de = sahne.bul(e); de && de->brep && de->brep->gecerliMi()) kenarlar.push_back(de->brep.get()); BrepGovde g = geometri::yamaYuzey(kenarlar); if (!g.gecerliMi()) hata = "Yama oluşturulamadı (≥3 sınır kenarı / kapalı sınır gerekli)"; return g; } if (tip == "yuzeyCikart") { const u32 ord = (u32)(f.p("yuzOrd", 1.0) + 0.5); BrepGovde g = geometri::yuzKopyala(kaynak, {ord}); if (!g.gecerliMi()) hata = "Yüz çıkarılamadı (yüz numarası geçersiz)"; return g; } if (tip == "sinir") { BrepGovde g = geometri::sinir(kaynak); if (!g.gecerliMi()) hata = "Yüzey sınırı çıkarılamadı"; return g; } if (tip == "birlestir") { BrepGovde g = geometri::birlestirEgriler(kaynak); if (!g.gecerliMi()) hata = "Eğriler birleştirilemedi (uçuca zincir gerekli)"; return g; } if (tip == "onar") { BrepGovde g = geometri::onar(kaynak, f.p("tol", 0.01)); if (!g.gecerliMi()) hata = "Onarılamadı"; return g; } if (tip == "yuzeySisir") { // Çok-hedef: hedefSayi>0 ise h{i}x/y/z + m{i} çiftleri; yoksa tek hedefX/Y/Z + miktar. std::vector> hedefler; const int hn = (int)(f.p("hedefSayi", 0.0) + 0.5); if (hn > 0) { for (int i = 0; i < hn; ++i) { const std::string k = std::to_string(i); hedefler.push_back({{f.p("h" + k + "x"), f.p("h" + k + "y"), f.p("h" + k + "z")}, f.p("m" + k, 0.0)}); } } else { hedefler.push_back({{f.p("hedefX"), f.p("hedefY"), f.p("hedefZ")}, f.p("miktar", 5.0)}); } // sinirKilit vars. AÇIK (Fikri 07-22: bağlı kenarlar bağlı kalsın); parametrik — // feature panelinden kapatılabilir (0 = eski serbest-sınır davranışı). BrepGovde g = geometri::yuzeySisirCok(kaynak, hedefler, f.p("yaricap", 20.0), f.p("sinirKilit", 1.0) > 0.5, (int)(f.p("kilitDerinlik", 1.0) + 0.5)); if (!g.gecerliMi()) hata = "Yüzey şişirilemedi"; return g; } if (tip == "yuzeyDuzelt") { BrepGovde g = geometri::yuzeyDuzelt(kaynak, f.p("miktar", 0.5), (int)(f.p("iterasyon", 3) + 0.5)); if (!g.gecerliMi()) hata = "Yüzey yumuşatılamadı"; return g; } if (tip == "kenarKaydir") { const Vec3d kn{f.p("knx"), f.p("kny"), f.p("knz")}; const Vec3d vc{f.p("vx"), f.p("vy"), f.p("vz")}; BrepGovde g = geometri::kenarKaydir(kaynak, kn, vc); if (!g.gecerliMi()) hata = "Kenar kaydırılamadı (bir yüzey kenarı seçin)"; return g; } if (tip == "telExtrude") { Vec3d yon{f.p("yonX"), f.p("yonY"), f.p("yonZ")}; if (yon.uzunluk() < 1e-9) { // yön verilmedi → tel'in düzlem normali Vec3d m, nn; if (geometri::telDuzlemNormal(kaynak, m, nn)) yon = nn; else { hata = "Extrude yönü belirlenemedi (düzlemsel tel gerekli)"; return {}; } } BrepGovde g = geometri::telSupur(kaynak, yon, f.p("mesafe", 10.0)); if (!g.gecerliMi()) hata = "Tel extrude başarısız"; return g; } if (tip == "kenarExtrude") { const u32 ord = (u32)(f.p("kenarOrd", 1.0) + 0.5); BrepGovde kenar = geometri::kenarCikar(kaynak, ord); if (!kenar.gecerliMi()) { hata = "Kenar bulunamadı"; return {}; } const Vec3d yon{f.p("yonX"), f.p("yonY"), f.p("yonZ")}; if (yon.uzunluk() < 1e-9) { hata = "Kenar uzatma yönü gerekli"; return {}; } BrepGovde g = geometri::telSupur(kenar, yon, f.p("mesafe", 10.0)); if (!g.gecerliMi()) hata = "Kenar uzatılamadı"; return g; } if (tip == "afin") { BrepGovde g = geometri::afin(kaynak, f.p("oranX", 1.0), f.p("oranY", 1.0), f.p("oranZ", 1.0)); if (!g.gecerliMi()) hata = "Afin dönüşüm başarısız (oranlar sıfır olmamalı)"; return g; } if (tip == "yuzeyOffset") { BrepGovde g = geometri::yuzeyOfset(kaynak, f.p("mesafe", 5.0)); if (!g.gecerliMi()) hata = "Yüzey offset oluşturulamadı"; return g; } if (tip == "yuzeyExtrapolate") { BrepGovde g = geometri::yuzeyUzat(kaynak, f.p("mesafe", 5.0)); if (!g.gecerliMi()) hata = "Yüzey uzatılamadı"; return g; } BrepGovde g = geometri::yuzeyKatilastir(kaynak, f.p("kalinlik", 2.0)); // thicken → katı if (!g.gecerliMi()) hata = "Yüzey kalınlaştırılamadı"; return g; } // ---- Yuzey (aktif sketch profili gerekli) ---- std::vector kontur; bool kapali = false; Vec3d normal, eksenX, eksenY, dzMerkez; if (!sketchProfili(cekirdek, sahne, f.sketch(), kontur, kapali, normal, eksenX, eksenY, dzMerkez)) { hata = "Geçerli bir sketch profili gerekli"; return {}; } if (tip == "yuzeyExtrude") { Vec3d yon = normal; if (f.p("tersYon") > 0.5) yon = {-yon.x, -yon.y, -yon.z}; const f64 mesafe = f.p("mesafe", 10.0); if (mesafe <= 1e-6) { hata = "Uzatma pozitif olmalı"; return {}; } BrepGovde g = geometri::yuzeyPrizma(kontur, kapali, yon, mesafe); if (!g.gecerliMi()) hata = "Yüzey oluşturulamadı"; return g; } if (tip == "yuzeyRevolve") { const int e = (int)(f.p("eksen") + 0.5); const Vec3d eksenYon = (e == 0) ? eksenX : (e == 1) ? eksenY : normal; const f64 aci = f.p("aci", 360.0); BrepGovde g = geometri::yuzeyDondur(kontur, kapali, dzMerkez, eksenYon, aci); if (!g.gecerliMi()) hata = "Dönel yüzey oluşturulamadı"; return g; } if (tip == "yuzeyFill") { if (!kapali) { hata = "Fill için kapalı profil gerekli"; return {}; } BrepGovde g = geometri::yuzeyFill(kontur); if (!g.gecerliMi()) hata = "Dolu yüzey oluşturulamadı"; return g; } hata = "Bilinmeyen GSD türü"; return {}; } } // namespace // Kaynağı DEĞİŞTİREN op mu? (sonuç = kaynağın dönüşmüş hâli → kaynak gizlenir). // Türeten op'lar (yuzeyCikart: kaynak KATI!, sinir/birlestir: tel türetir, kenar/tel // extrude: yeni strip ekler, 2-kaynak köprü/kesişim/loft/süpürme, yama) LİSTEDE DEĞİL. using eskiz::EskizVeri; using eskiz::Geometri; using eskiz::GeoTip; static bool kaynagiGizlenirMi(const std::string& tip) { return tip == "yuzeySisir" || tip == "yuzeyDuzelt" || tip == "kenarKaydir" || tip == "yuzeyExtrapolate" || tip == "onar" || tip == "afin" || tip == "yuzeyOffset" || tip == "yuzeyThicken" || tip == "yuzeyKirp"; } Varlik GsdSistemi::geometrikSetAl() { // Aktiflik/In Work tekliği Sahne'de (body VEYA set) — rotalama oraya delege. return sahne_.geometrikSetHedefAl(); } void GsdSistemi::yenidenInsa(GsdFeature& feat) { feat.hataAyarla(""); std::string hata; geometri::BrepGovde govde = uret(cekirdek_, sahne_, feat, hata); if (!govde.gecerliMi()) { feat.hataAyarla(hata.empty() ? "Geometri oluşturulamadı" : hata); return; } // Sonuc dugum tipi SONUC GEOMETRISINDEN belirlenir (tanim grubundan degil): yuzsuz // sonuc (edge/wire/vertex) → Tel; yuzlu → Yuzey. Boyle Boundary (yuzey→tel) / // Intersection (kati→tel) dogru dugum tipi + rengi alir. const bool tel = geometri::topolojiOzeti(govde).yuzSayi == 0; // Sonuc dugumu: yoksa olustur, varsa brep degistir + yeniden mesh/kenar. u32 dugumId = feat.sonucDugum(); if (!sahne_.bul(dugumId)) { const DugumTip dt = tel ? DugumTip::Tel : DugumTip::Yuzey; const Vec3f renk = tel ? Vec3f{0.98f, 0.80f, 0.08f} : Vec3f{0.20f, 0.75f, 0.85f}; dugumId = sahne_.gsdDugumEkle(dt, feat.ad().empty() ? feat.tip() : feat.ad(), geometrikSetAl(), renk); feat.sonucDugumAyarla(dugumId); } auto paylasilan = std::make_shared(std::move(govde)); if (!sahne_.gsdDugumGuncelle(dugumId, paylasilan)) { feat.hataAyarla("Görselleştirme başarısız"); return; } // Kaynağı DEĞİŞTİREN op başarıyla sonuç üretti → kaynak düğümü gizle (üst üste yüzey // yığılmasın). Türeten op'lar (cikart/sinir/birlestir/kenar-tel extrude/köprü/kesişim/ // loft/süpürme/yama) kaynağı KORUR. İptal/sil → iptalOncesi geri açar. if (kaynakGizleAktif && kaynagiGizlenirMi(feat.tip()) && feat.kaynak() != 0) if (Dugum* kd = sahne_.bul(feat.kaynak())) kd->gorunur = false; if (tel) cekirdek_.olaylar().yayinla(TelEklendi{feat.kimlik()}); else cekirdek_.olaylar().yayinla(YuzeyEklendi{feat.kimlik()}); } void GsdSistemi::iptalOncesi(GsdFeature& feat) { // Bu feature kaynağını gizlediyse geri görünür yap (taslak iptali + feature silme). if (kaynagiGizlenirMi(feat.tip()) && feat.kaynak() != 0) if (Dugum* kd = sahne_.bul(feat.kaynak())) kd->gorunur = true; } u32 GsdSistemi::gsdBaslat(const std::string& tip, Varlik aktifSketch, Varlik kaynak, Varlik kaynak2) { const gsd::FeatureTanim* td = gsdTanimBul(tip); if (!td) return 0; const bool tel = gsdTelMi(*td); const bool kaynakOp = gsdKaynakYuzeyMi(*td); const bool ikiKaynak = gsdIkiKaynakMi(*td); if (ikiKaynak) { if (kaynak == 0 || kaynak2 == 0) { gunluk::uyari("İki-kaynak op için iki gövde seçin"); return 0; } } else if (kaynakOp) { if (kaynak == 0) kaynak = sahne_.seciliGsdYuzey(); // seçili GSD yüzey düğümüne düş if (kaynak == 0) kaynak = sahne_.seciliGsdTel(); // ya da GSD tel (Concatenate) if (kaynak == 0) { gunluk::uyari("Yüzey/tel op için bir GSD öğesi seçin"); return 0; } } else if (!tel) { if (aktifSketch == 0) aktifSketch = sahne_.seciliSketch(); // seçili sketch'e düş if (aktifSketch == 0) { gunluk::uyari("Yüzey için aktif veya seçili sketch gerekli"); return 0; } } const Varlik v = cekirdek_.dunya().olustur(); auto feat = std::make_unique(v, this, tip); feat->adAyarlaDirekt(td->ad); if (ikiKaynak) { feat->kaynakAyarla(kaynak); feat->kaynak2Ayarla(kaynak2); } else if (kaynakOp) feat->kaynakAyarla(kaynak); else if (!tel) feat->sketchAyarla(aktifSketch); for (const gsd::FeatureParam& p : td->parametreler) { if (p.tip == parca::ParamTip::SahneNokta) { // taban → x/y/z ayrı anahtar feat->pAyarla(p.anahtar + "x", p.varsayilan); feat->pAyarla(p.anahtar + "y", p.minVeya); feat->pAyarla(p.anahtar + "z", p.maksVeya); } else { feat->pAyarla(p.anahtar, p.varsayilan); } } GsdFeature* ref = feat.get(); cekirdek_.nesneEkle(std::move(feat)); cekirdek_.gorunumAta(std::make_unique(v, this, td->simge, tel)); featureler_.push_back(v); taslak_ = v; yenidenInsa(*ref); // taslak onizleme cekirdek_.olaylar().yayinla(FeatureEklendi{v}, td->ad.c_str()); return v; } void GsdSistemi::gsdEkKaynaklarAyarla(u32 feat, std::vector ek) { if (GsdFeature* f = bul(feat)) { f->ekKaynaklarAyarla(std::move(ek)); yenidenInsa(*f); // tüm kaynaklarla yeniden hesap } } // ---- GPU Spline/NURBS Render (Fast Glow Effect) ---- // Spline/NURBS render kuyruguna eklendi olayi (GPU glow efekti icin). struct SplineRenderEklendi { std::vector> segmentler; fiko::Vec3f renk; f32 yogunluk; static constexpr OlayTuru tur() { return OlayTuru::Diger; } }; // De Boor-Cox basis function (inline, NURBS evaluation) static f64 basisFn(int i, int p, f64 t, const std::vector& knot) { if (p == 0) return (t >= knot[(size_t)i] && t < knot[(size_t)(i+1)]) ? 1.0 : 0.0; f64 d1 = 0.0, d2 = 0.0; if (knot[(size_t)(i+p)] - knot[(size_t)i] > 1e-15f) d1 = (t - knot[(size_t)i]) / (knot[(size_t)(i+p)] - knot[(size_t)i]); if (knot[(size_t)(i+p+1)] - knot[(size_t)(i+1)] > 1e-15f) d2 = (knot[(size_t)(i+p+1)] - t) / (knot[(size_t)(i+p+1)] - knot[(size_t)(i+1)]); return d1 * basisFn(i, p-1, t, knot) + d2 * basisFn(i+1, p-1, t, knot); } // GPU-optimized Spline polyline generation (subdivide by t) // Returns segments: each element is {previous_point, current_point} static std::vector> gsdSplinePolyline(const EskizVeri& ev, const Geometri& g) { std::vector> pts; if (g.tip != GeoTip::Spline) return pts; bool isNurbs = !g.knot.empty() && !g.weight.empty(); std::vector ctrl; // Extract control points if (isNurbs) { ctrl.push_back({ev.noktaX(g.kimlik, 0), ev.noktaY(g.kimlik, 0)}); for (const auto& ek : g.ekNoktalar) { ctrl.push_back({ev.px(ek.ix), ev.px(ek.iy)}); } if (g.b.gecerli()) { ctrl.push_back({ev.noktaX(g.kimlik, 1), ev.noktaY(g.kimlik, 1)}); } } else { // Catmull-Rom padding ctrl.push_back({ev.noktaX(g.kimlik, 0), ev.noktaY(g.kimlik, 0)}); ctrl.push_back({ev.noktaX(g.kimlik, 0), ev.noktaY(g.kimlik, 0)}); for (const auto& ek : g.ekNoktalar) { ctrl.push_back({ev.px(ek.ix), ev.px(ek.iy)}); } if (g.b.gecerli()) { ctrl.push_back({ev.noktaX(g.kimlik, 1), ev.noktaY(g.kimlik, 1)}); ctrl.push_back({ev.noktaX(g.kimlik, 1), ev.noktaY(g.kimlik, 1)}); } else { fiko::Vec2d last = ctrl.back(); ctrl.push_back(last); ctrl.push_back(last); } } if (!isNurbs && ctrl.size() < 4) return pts; if (ctrl.size() < (isNurbs ? 2 : 4)) return pts; // Generate polyline with GPU-optimized subdivision constexpr int ns = 16; // Subdivision steps per segment (balanced: quality vs perf) const auto cr = [](const fiko::Vec2d& p0, const fiko::Vec2d& p1, const fiko::Vec2d& p2, const fiko::Vec2d& p3, f64 t) -> fiko::Vec2d { const f64 t2 = t*t, t3 = t2*t; return {0.5*(2.0*p1.x + (-p0.x+p2.x)*t + (2.0*p0.x-5.0*p1.x+4.0*p2.x-p3.x)*t2 + (-p0.x+3.0*p1.x-3.0*p2.x+p3.x)*t3), 0.5*(2.0*p1.y + (-p0.y+p2.y)*t + (2.0*p0.y-5.0*p1.y+4.0*p2.y-p3.y)*t2 + (-p0.y+3.0*p1.y-3.0*p2.y+p3.y)*t3)}; }; if (isNurbs) { int p = std::min(3, (int)ctrl.size() - 1); int totalAdim = std::max((int)ctrl.size() * 10, 40); // Initial point at t=0 fiko::Vec2d startPt = ctrl[0]; f64 t0 = 0.0; auto it0 = std::lower_bound(g.knot.begin(), g.knot.end(), t0, [](f64 k, f64 v){ return k < v - 1e-20; }); int idx0 = (int)(it0 - g.knot.begin()) - 1; if (idx0 < p) idx0 = p; f64 sx0 = 0, sy0 = 0, sw0 = 0; for (int j = 0; j <= p; ++j) { int ci = idx0 - p + j; if (ci >= 0 && ci < (int)ctrl.size()) { f64 b = basisFn(ci, p, t0, g.knot); f64 bw = b * g.weight[(size_t)ci]; sx0 += bw * ctrl[(size_t)ci].x; sy0 += bw * ctrl[(size_t)ci].y; sw0 += bw; } } startPt = (sw0 > 1e-30f) ? fiko::Vec2d(sx0/sw0, sy0/sw0) : ctrl[0]; fiko::Vec2d onceki = startPt; for (int i = 1; i <= totalAdim; ++i) { f64 t = (f64)i / (f64)totalAdim; auto it = std::lower_bound(g.knot.begin(), g.knot.end(), t, [](f64 k, f64 v){ return k < v - 1e-20; }); int idx = (int)(it - g.knot.begin()) - 1; if (t > g.knot.back() * 0.9999) idx = (int)ctrl.size() - p - 1; if (idx < p) idx = p; if (idx > (int)ctrl.size() - p - 1) idx = (int)ctrl.size() - p - 1; f64 sx = 0, sy = 0, sw = 0; for (int j = 0; j <= p; ++j) { int ci = idx - p + j; if (ci >= 0 && ci < (int)ctrl.size()) { f64 b = basisFn(ci, p, t, g.knot); f64 bw = b * g.weight[(size_t)ci]; sx += bw * ctrl[(size_t)ci].x; sy += bw * ctrl[(size_t)ci].y; sw += bw; } } fiko::Vec2d pn = (sw > 1e-30f) ? fiko::Vec2d(sx/sw, sy/sw) : ctrl[0]; pts.push_back({onceki, pn}); onceki = pn; } } else { // Catmull-Rom: smooth interpolation fiko::Vec2d onceki = ctrl[1]; for (std::size_t i = 0; i + 3 < ctrl.size(); ++i) { for (int s = 1; s <= ns; ++s) { const fiko::Vec2d pp = cr(ctrl[i], ctrl[i+1], ctrl[i+2], ctrl[i+3], (f64)s/(f64)ns); pts.push_back({onceki, pp}); onceki = pp; } } } return pts; } // Render Spline/NURBS with GPU glow effect void GsdSistemi::renderSplineGlow(const EskizVeri& ev) { const std::vector& geometriler = ev.geometriler(); // Batch process all Spline geometries for (const Geometri& g : geometriler) { if (g.tip != GeoTip::Spline || g.yapi) continue; const auto pts = gsdSplinePolyline(ev, g); if (pts.size() < 2) continue; // Calculate average intensity (based on control point count) f32 intensity = 0.7f + (f32)pts.size() * 0.02f; // Dynamic glow based on complexity intensity = std::clamp(intensity, 0.5f, 1.0f); // Push to render queue (teal glow: 0.0, 0.9, 1.0) // Note: Actual rendering happens in render pipeline via Vulkan compute cekirdek_.olaylar().yayinla(SplineRenderEklendi{ pts, Vec3f{0.0f, 0.9f, 1.0f}, // Teal glow color intensity }); } } } // namespace fiko::gsd