#include "hover_karti.hpp" #include "fiko/core/birim_bicim.hpp" // global birim küsüratı (Ayarlar → Birimler) #include #include #include "fiko/core/gunluk.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/ui/hover_bilgi.hpp" #include "imgui.h" namespace fiko { int& hoverGecikmeMs() { static int ms = 500; return ms; } void hoverBilgiKartCiz(Sahne& sahne, girdi::SahneHoverProbu& hoverProbu, bool hoverBilgiAcik, bool vpHover, int kare) { if (!hoverBilgiAcik || !vpHover) return; const girdi::HoverBilgi& hb = hoverProbu.simdiki(); static char b0[48], b1[48], b2[48], b3[48], bBaslik[64]; // KASMA ÖNLEMİ: yuzBilgi/kenarBilgi = OCCT ordinal-tarama + GProp integrali // (yoğun üçgenli/B-spline yüzeyde ms mertebesi). Hedef (gövde+alt+tür+brep) // DEĞİŞMEDİKÇE kart içeriği önbellekten kullanılır — kare-başı sorgu YOK. static ui::HoverIcerik hic; // önbellekli içerik (static tamponlara işaret eder) static u32 onGovde = ~0u, onAlt = ~0u; // önbellek anahtarı static girdi::HedefTur onTur = girdi::HedefTur::Hic; static const void* onBrep = nullptr; static std::chrono::steady_clock::time_point hedefZamani{}; // hedefin son değişim anı (debounce) static bool sorgulandi = false; // gecikme sonrası içerik dolduruldu mu static f64 hkToplamUs = 0; static u32 hkYenile = 0; // [perf] örneklem Dugum* hd = hb.govdeId ? sahne.bul(hb.govdeId) : nullptr; const void* brepPtr = hd ? (const void*)hd->brep.get() : nullptr; const bool hedefDegisti = hb.govdeId != onGovde || hb.altId != onAlt || hb.tur != onTur || brepPtr != onBrep; const auto simdi = std::chrono::steady_clock::now(); if (hedefDegisti) { // DEBOUNCE: hedef değişti → sayacı sıfırla, İÇERİĞE DOKUNMA (eski kart // fade-out'la kaybolsun) ve OCCT sorgusunu gecikme dolana dek ERTELE — // imleç hızlı gezerken hiç ağır sorgu yapılmaz. onGovde = hb.govdeId; onAlt = hb.altId; onTur = hb.tur; onBrep = brepPtr; hedefZamani = simdi; sorgulandi = false; } const bool hedefGecerli = hb.govdeId != 0 && hb.tur != girdi::HedefTur::Hic && hd; const f64 gecenMs = std::chrono::duration(simdi - hedefZamani).count(); const bool gecikmeDoldu = gecenMs >= (f64)hoverGecikmeMs(); if (hedefGecerli && gecikmeDoldu && !sorgulandi) { // Gecikme doldu → içeriği ŞİMDİ (bir kez) sorgula ve önbelleğe al. const auto hkT0 = simdi; sorgulandi = true; hic.temizle(); if (hd) { std::snprintf(bBaslik, sizeof(bBaslik), "%s", hd->ad.empty() ? "Gövde" : hd->ad.c_str()); hic.baslik = bBaslik; const auto* brep = hd->brep.get(); // BLOKLAMAYAN sorgu: yalnız önbellek okunur. Soğuksa arka plan hesabı tetiklenir ve // sorgulandi=false bırakılır → kart, bilgi hazır olana dek sonraki karelerde (ucuz // önbellek bakışıyla) yeniden dener. "Ucuz" sanılan BRepAdaptor/D1 bile dev B-spline // yüzde 1.4 s ölçüldü — hover yolunda artık HİÇ OCCT çağrısı yok. if (hb.tur == girdi::HedefTur::Yuz && brep && hb.altId) { geometri::YuzBilgi yb; if (!brep->yuzBilgiOnbellekteMi(hb.altId)) { geometri::yuzBilgiArkaPlanIste(hd->brep, hb.altId); sorgulandi = false; // hazır olunca doldur } else if (brep->yuzBilgiHizli(hb.altId, yb)) { hic.tur = ui::HoverTur::Yuz; std::snprintf(b0, sizeof(b0), "%s", yb.duzlemMi ? "Düzlem" : yb.silindirMi ? "Silindir" : yb.kureMi ? "Küre" : "Yüzey"); hic.satirEkle("Tip", b0); if (yb.silindirMi || yb.kureMi) { std::snprintf(b2, sizeof(b2), "%.*f mm", birim::hane(birim::Birim::Uzunluk), yb.yaricap); hic.satirEkle("Yarıçap", b2); } } } else if (hb.tur == girdi::HedefTur::Kenar && brep && hb.altId) { geometri::KenarBilgi kb2; if (!brep->kenarBilgiOnbellekteMi(hb.altId)) { geometri::kenarBilgiArkaPlanIste(hd->brep, hb.altId); sorgulandi = false; // hazır olunca doldur } else if (brep->kenarBilgiHizli(hb.altId, kb2)) { hic.tur = ui::HoverTur::Kenar; std::snprintf(b0, sizeof(b0), "%s", kb2.cemberMi ? "Çember/Yay" : kb2.dogruMu ? "Doğru" : "Eğri"); hic.satirEkle("Tip", b0); std::snprintf(b1, sizeof(b1), "%.*f mm", birim::hane(birim::Birim::Uzunluk), kb2.uzunluk); hic.satirEkle("Uzunluk", b1); if (kb2.cemberMi) { std::snprintf(b2, sizeof(b2), "%.*f mm", birim::hane(birim::Birim::Uzunluk), kb2.yaricap); hic.satirEkle("Yarıçap", b2); } } } else if (hb.tur == girdi::HedefTur::Nokta && brep && hb.altId) { Vec3d k; if (brep->noktaKonum(hb.altId, k)) { hic.tur = ui::HoverTur::Nokta; std::snprintf(b0, sizeof(b0), "%.*f", birim::hane(birim::Birim::Koordinat), k.x); hic.satirEkle("X", b0); std::snprintf(b1, sizeof(b1), "%.*f", birim::hane(birim::Birim::Koordinat), k.y); hic.satirEkle("Y", b1); std::snprintf(b2, sizeof(b2), "%.*f", birim::hane(birim::Birim::Koordinat), k.z); hic.satirEkle("Z", b2); } } else if (hb.tur == girdi::HedefTur::Govde) { hic.tur = ui::HoverTur::Govde; std::snprintf(b1, sizeof(b1), "%.*f mm³", birim::hane(birim::Birim::Hacim), hd->hacim); hic.satirEkle("Hacim", b1); std::snprintf(b3, sizeof(b3), "%.*f mm²", birim::hane(birim::Birim::Alan), hd->alan); hic.satirEkle("Alan", b3); } } hkToplamUs += std::chrono::duration( std::chrono::steady_clock::now() - hkT0).count(); ++hkYenile; } // gecikme doldu → sorgu if (kare % 600 == 0 && hkYenile > 0) { gunluk::bilgi("[perf] hover kart: {} gecikmeli sorgu, ort {:.0f} µs (imleç gezerken sorgu YOK)", hkYenile, hkToplamUs / hkYenile); hkToplamUs = 0; hkYenile = 0; } // acik: gecikme dolmuş + geçerli hedef + içerik var. false verilse bile HER KARE // çağrılır → fade-out animasyonu (hedef değişince/boşluğa gelince) işlensin. const bool acik = hedefGecerli && gecikmeDoldu && sorgulandi && hic.tur != ui::HoverTur::Yok; ui::hoverBilgiCiz("sahne_hover", ImGui::GetMousePos(), acik, hic); } } // namespace fiko