#include "fiko/cam/cam_secim.hpp" #include #include #include #include "fiko/cam/cam_sistemi.hpp" #include "fiko/cekirdek/olay.hpp" #include "fiko/geometri/brep.hpp" #include "fiko/sahne/sahne.hpp" namespace fiko::cam { const char* camSecimKipAdi(CamSecimKip k) { switch (k) { case CamSecimKip::Yok: return "Yok"; case CamSecimKip::Kontur: return "Kontur"; case CamSecimKip::Ada: return "Ada"; case CamSecimKip::Nokta: return "Nokta"; case CamSecimKip::Kenar: return "Kenar"; case CamSecimKip::DuzlemUst: return "Üst Z"; case CamSecimKip::DuzlemAlt: return "Alt Z"; case CamSecimKip::GuvenlikDuzlem: return "Güvenlik"; case CamSecimKip::ToolAxis: return "Takım Ekseni"; case CamSecimKip::Stok: return "Stok"; } return ""; } // --------------------------------------------------------------------------- // Saf yardımcılar (Sahne'siz test edilebilir). // --------------------------------------------------------------------------- int yuzdenKontur(const geometri::BrepGovde& brep, u32 yuzOrdinal, const Donusumd& donusum, CamGeometri& gc, bool adaModu, f64 sapma) { if (!brep.gecerliMi() || yuzOrdinal == 0) return 0; const auto yerel = brep.yuzKonturlari(yuzOrdinal, sapma); if (yerel.empty()) return 0; int eklenen = 0; for (size_t i = 0; i < yerel.size(); ++i) { const auto& halka = yerel[i]; if (halka.size() < 3) continue; std::vector xy; xy.reserve(halka.size()); for (const Vec3d& n : halka) { const Vec3d w = donusum.noktaUygula(n); xy.push_back({w.x, w.y}); // part-op eksen tanımsız → dünya XY (web identity) } // Ada modu: seçilen yüzün dış sınırı bir ada olur (cep içinde işlenmez). if (adaModu) { gc.adalar.push_back(std::move(xy)); } else { if (i == 0) gc.konturlar.push_back(std::move(xy)); // dış sınır else gc.adalar.push_back(std::move(xy)); // yüzün kendi delikleri = ada } ++eklenen; } if (eklenen > 0 && std::find(gc.yuzIdx.begin(), gc.yuzIdx.end(), yuzOrdinal) == gc.yuzIdx.end()) gc.yuzIdx.push_back(yuzOrdinal); return eklenen; } bool kenarlardanKontur(const std::vector>& kenarNoktalari, const Donusumd& donusum, CamGeometri& gc) { if (kenarNoktalari.empty()) return false; constexpr f64 TOL2 = 25.0; // (5mm)² // Kenar örneklerini dünyaya taşı (yerel → dünya). std::vector> kalan; kalan.reserve(kenarNoktalari.size()); for (const auto& kn : kenarNoktalari) { if (kn.size() < 2) continue; std::vector w; w.reserve(kn.size()); for (const Vec3d& p : kn) w.push_back(donusum.noktaUygula(p)); kalan.push_back(std::move(w)); } if (kalan.empty()) return false; // Uç-uca zincirle: ilk kenardan başla, uçları eşleşen kenarları ekle. std::vector zincir = std::move(kalan.front()); kalan.erase(kalan.begin()); bool ilerledi = true; while (ilerledi && !kalan.empty()) { ilerledi = false; const Vec3d bas = zincir.front(); const Vec3d son = zincir.back(); for (size_t i = 0; i < kalan.size(); ++i) { auto& e = kalan[i]; const Vec3d eb = e.front(), es = e.back(); if ((es - son).uzunlukKare() < TOL2) { // e sonda, ters ekle for (auto it = e.rbegin() + 1; it != e.rend(); ++it) zincir.push_back(*it); } else if ((eb - son).uzunlukKare() < TOL2) { for (size_t j = 1; j < e.size(); ++j) zincir.push_back(e[j]); } else if ((es - bas).uzunlukKare() < TOL2) { // e başta for (size_t j = e.size() - 1; j-- > 0;) zincir.insert(zincir.begin(), e[j]); } else if ((eb - bas).uzunlukKare() < TOL2) { for (auto it = e.begin() + 1; it != e.end(); ++it) zincir.insert(zincir.begin(), *it); } else { continue; } kalan.erase(kalan.begin() + (long)i); ilerledi = true; break; } } if (zincir.size() < 2) return false; std::vector xy; xy.reserve(zincir.size()); for (const Vec3d& p : zincir) xy.push_back({p.x, p.y}); gc.konturlar.clear(); gc.konturlar.push_back(std::move(xy)); return true; } // --------------------------------------------------------------------------- // CamSecimSistemi // --------------------------------------------------------------------------- CamSecimSistemi::CamSecimSistemi(Sahne& sahne, CamSistemi& cam, OlayGunlugu& olaylar) : sahne_(sahne), cam_(cam), olaylar_(olaylar) { // Associatif: kaynak geometri değişince *Ref'li op alanları yeniden çözülür. olaylar_.abone([this](const BrepDegisti& e) { associatifCoz(e.varlik); }); olaylar_.abone([this](const DonusumDegisti& e) { associatifCoz(e.varlik); }); } void CamSecimSistemi::baslat(CamOperasyon& op, CamSecimKip kip, std::function gc) { if (kip_ == kip && opKimlik_ == op.kimlik) { bitir(); return; } // toggle bitir(); // önceki modu temizle kip_ = kip; opKimlik_ = op.kimlik; popKimlik_ = 0; gc_ = std::move(gc); if (kip == CamSecimKip::Kenar) { secKenarOrd_.clear(); kenarCacheNok_.clear(); kenarGovde_ = 0; } hudGuncelle(); olaylar_.yayinla(CamSecimBasladi{op.kimlik, (u32)kip}, camSecimKipAdi(kip)); } void CamSecimSistemi::duzlemBaslat(CamOperasyon& op, CamSecimKip kip, std::function ayarla, std::function gc) { if (kip_ == kip && opKimlik_ == op.kimlik) { bitir(); return; } bitir(); kip_ = kip; opKimlik_ = op.kimlik; popKimlik_ = 0; duzlemAyarla_ = std::move(ayarla); gc_ = std::move(gc); hudGuncelle(); olaylar_.yayinla(CamSecimBasladi{op.kimlik, (u32)kip}, camSecimKipAdi(kip)); } void CamSecimSistemi::partOpBaslat(u32 popKimlik, CamSecimKip kip, std::function ayarlaGovde, std::function ayarlaVec, std::function gc) { if (kip_ == kip && popKimlik_ == popKimlik) { bitir(); return; } bitir(); kip_ = kip; opKimlik_ = 0; popKimlik_ = popKimlik; partGovdeAyarla_ = std::move(ayarlaGovde); partVecAyarla_ = std::move(ayarlaVec); gc_ = std::move(gc); hudGuncelle(); olaylar_.yayinla(CamSecimBasladi{popKimlik, (u32)kip}, camSecimKipAdi(kip)); } int CamSecimSistemi::beklenenVurguTur() const { switch (kip_) { case CamSecimKip::Kontur: case CamSecimKip::Ada: case CamSecimKip::DuzlemUst: case CamSecimKip::DuzlemAlt: case CamSecimKip::GuvenlikDuzlem: case CamSecimKip::ToolAxis: return 1; // yüz case CamSecimKip::Kenar: return 2; // kenar case CamSecimKip::Nokta: return 1; // yüz (serbest nokta ışın vuruşuyla alınır) case CamSecimKip::Stok: return 0; // gövde default: return 0; } } void CamSecimSistemi::tik(const SecimOge& vurgu, u32 vurguTur, const std::function& isinVur, bool ciftTik) { if (kip_ == CamSecimKip::Yok) return; (void)ciftTik; // ---- Part operation modları (gövde/nokta/normal) ---- if (popKimlik_) { if (kip_ == CamSecimKip::Stok) { // stok/fikstür kaynak gövde if (vurgu.govde && partGovdeAyarla_) { partGovdeAyarla_(vurgu.govde); if (gc_) gc_(); olaylar_.yayinla(CamSecimYapildi{popKimlik_, (u32)kip_}); } return; } if (kip_ == CamSecimKip::ToolAxis || kip_ == CamSecimKip::DuzlemUst) { // Eksen origin/yön: yüz merkez + normal (dünya). Vec3f nk{}, nm{}; if (isinVur && isinVur(nk, nm) && partVecAyarla_) { partVecAyarla_({nk.x, nk.y, nk.z}, {nm.x, nm.y, nm.z}); if (gc_) gc_(); olaylar_.yayinla(CamSecimYapildi{popKimlik_, (u32)kip_}); } return; } return; } CamOperasyon* op = cam_.opBul(opKimlik_); if (!op) { bitir(); return; } // ---- Nokta (delik merkezi): serbest dünya noktası ---- if (kip_ == CamSecimKip::Nokta) { Vec3f nk{}, nm{}; if (isinVur && isinVur(nk, nm)) { op->geometri.noktalar.push_back({(f64)nk.x, (f64)nk.y, (f64)nk.z, true, false}); op->bayat = true; if (gc_) gc_(); hudSayi_ = (int)op->geometri.noktalar.size(); hudGuncelle(); olaylar_.yayinla(CamSecimYapildi{op->kimlik, (u32)kip_}); } return; // Nokta modu açık kalır (ESC/tekrar-buton biter) } // Bundan sonrası bir yüz/kenar gerektirir. Dugum* d = vurgu.govde ? sahne_.bul(vurgu.govde) : nullptr; if (!d || !d->brep || !d->brep->gecerliMi()) return; // ---- Kenar: toggle + zincirle ---- if (kip_ == CamSecimKip::Kenar) { if (vurguTur != 2 || vurgu.alt == 0) return; if (kenarGovde_ && kenarGovde_ != vurgu.govde) { secKenarOrd_.clear(); kenarCacheNok_.clear(); } kenarGovde_ = vurgu.govde; op->geometri.kaynakGovde = vurgu.govde; auto it = std::find(secKenarOrd_.begin(), secKenarOrd_.end(), vurgu.alt); if (it != secKenarOrd_.end()) { const size_t idx = (size_t)(it - secKenarOrd_.begin()); secKenarOrd_.erase(it); kenarCacheNok_.erase(kenarCacheNok_.begin() + (long)idx); } else { auto nok = d->brep->kenarNoktalari(vurgu.alt); if (nok.size() < 2) return; secKenarOrd_.push_back(vurgu.alt); kenarCacheNok_.push_back(std::move(nok)); } kenarKonturuYenile(*op); op->bayat = true; if (gc_) gc_(); hudSayi_ = (int)secKenarOrd_.size(); hudGuncelle(); olaylar_.yayinla(CamSecimYapildi{op->kimlik, (u32)kip_}); return; // Kenar modu açık kalır } // Yüz gerekli modlar. if (vurguTur != 1 || vurgu.alt == 0) return; const u32 yuz = vurgu.alt; // ---- ToolAxis: yüz normali → takım yönü ---- if (kip_ == CamSecimKip::ToolAxis) { geometri::YuzBilgi yb; if (!d->brep->yuzBilgi(yuz, yb)) return; Vec3d n = d->donusum.yonelim.dondur(yb.normal); const f64 len = std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z); if (len < 1e-9) return; n = {n.x / len, n.y / len, n.z / len}; op->takimYonu.yon = n; op->takimYonu.kaynak = TakimYonu::Kaynak::Yuzey; op->takimYonu.yuzId = yuz; op->takimYonu.origin = d->donusum.noktaUygula(yb.merkez); op->geometri.kaynakGovde = vurgu.govde; op->bayat = true; if (gc_) gc_(); olaylar_.yayinla(CamSecimYapildi{op->kimlik, (u32)kip_}); bitir(); // tek tık → biter return; } // ---- Düzlem/kot modları: yüz Z + associatif faceId ---- if (kip_ == CamSecimKip::DuzlemUst || kip_ == CamSecimKip::DuzlemAlt || kip_ == CamSecimKip::GuvenlikDuzlem) { geometri::YuzBilgi yb; if (!d->brep->yuzBilgi(yuz, yb)) return; const f64 z = d->donusum.noktaUygula(yb.merkez).z; op->geometri.kaynakGovde = vurgu.govde; if (duzlemAyarla_) duzlemAyarla_(z, yuz); op->bayat = true; if (gc_) gc_(); olaylar_.yayinla(CamSecimYapildi{op->kimlik, (u32)kip_}); bitir(); // tek tık → biter return; } // ---- Kontur / Ada: yüz konturları ---- if (kip_ == CamSecimKip::Kontur || kip_ == CamSecimKip::Ada) { geometri::YuzBilgi yb; if (!d->brep->yuzBilgi(yuz, yb) || !yb.duzlemMi) { // Düzlemsel değil → sessiz reddet (HUD ile kullanıcı yönlendirilir). return; } op->geometri.kaynakGovde = vurgu.govde; const bool ada = (kip_ == CamSecimKip::Ada); const int n = yuzdenKontur(*d->brep, yuz, d->donusum, op->geometri, ada); if (n == 0) return; // İlk kontur seçiminde üst Z'yi yüz merkezine associatif bağla. if (!ada) { op->geometri.ustZ = d->donusum.noktaUygula(yb.merkez).z; op->geometri.ustZRef = yuz; } op->bayat = true; if (gc_) gc_(); hudSayi_ = (int)(ada ? op->geometri.adalar.size() : op->geometri.konturlar.size()); hudGuncelle(); olaylar_.yayinla(CamSecimYapildi{op->kimlik, (u32)kip_}); // Kontur → tek tık sonrası kapan; Ada → açık kalır (çoklu ada). if (!ada) bitir(); return; } } void CamSecimSistemi::kenarKonturuYenile(CamOperasyon& op) { Dugum* d = sahne_.bul(kenarGovde_); if (!d) return; op.geometri.konturlar.clear(); if (kenarCacheNok_.empty()) return; kenarlardanKontur(kenarCacheNok_, d->donusum, op.geometri); } void CamSecimSistemi::bitir() { if (kip_ == CamSecimKip::Yok) return; const u32 k = opKimlik_ ? opKimlik_ : popKimlik_; const CamSecimKip eski = kip_; kip_ = CamSecimKip::Yok; opKimlik_ = 0; popKimlik_ = 0; duzlemAyarla_ = nullptr; partGovdeAyarla_ = nullptr; partVecAyarla_ = nullptr; secKenarOrd_.clear(); kenarCacheNok_.clear(); kenarGovde_ = 0; hud_.clear(); hudSayi_ = 0; auto gc = std::move(gc_); gc_ = nullptr; if (gc) gc(); (void)eski; olaylar_.yayinla(CamSecimBitti{k}); } void CamSecimSistemi::hudGuncelle() { char buf[128]; if (kip_ == CamSecimKip::Yok) { hud_.clear(); return; } std::snprintf(buf, sizeof(buf), "%s seç · %d seçili · ESC=bitir", camSecimKipAdi(kip_), hudSayi_); hud_ = buf; } void CamSecimSistemi::associatifCoz(u32 govde) { Dugum* d = sahne_.bul(govde); for (CamOperasyon& op : cam_.operasyonlar()) { CamGeometri& g = op.geometri; if (g.kaynakGovde != govde) continue; // yalnız bu gövdeye bağlı op'lar bool degisti = false; if (d && d->brep && d->brep->gecerliMi()) { geometri::YuzBilgi yb; if (g.ustZRef && d->brep->yuzBilgi(g.ustZRef, yb)) { const f64 z = d->donusum.noktaUygula(yb.merkez).z; if (std::abs(z - g.ustZ) > 1e-9) { g.ustZ = z; degisti = true; } } if (g.altZRef && d->brep->yuzBilgi(g.altZRef, yb)) { const f64 z = d->donusum.noktaUygula(yb.merkez).z; if (std::abs(z - g.altZ) > 1e-9) { g.altZ = z; degisti = true; } } // Takım ekseni yüz referansı → normal yeniden çöz. if (op.takimYonu.kaynak == TakimYonu::Kaynak::Yuzey && op.takimYonu.yuzId && d->brep->yuzBilgi(op.takimYonu.yuzId, yb)) { Vec3d n = d->donusum.yonelim.dondur(yb.normal); const f64 len = std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z); if (len > 1e-9) { op.takimYonu.yon = {n.x / len, n.y / len, n.z / len}; op.takimYonu.origin = d->donusum.noktaUygula(yb.merkez); degisti = true; } } } if (degisti) op.bayat = true; } } } // namespace fiko::cam