#include "fark_tur.hpp" #include #include #include "fiko/analiz/analiz_sistemi.hpp" #include "fiko/render/orbit_kamera.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/ui/tema.hpp" namespace fiko { FarkTurDurum& farkTur() { static FarkTurDurum d; return d; } f64& farkTurSaniye() { static f64 s = 4.0; // AyarSistemi "fark.tur_sure" return s; } int& farkIsaretciAzami() { static int n = 15; // AyarSistemi "fark.isaretci_azami" return n; } void farkTurBaslat(u32 analizKimlik, f32 zaman) { FarkTurDurum& t = farkTur(); t.analiz = analizKimlik; t.idx = -1; // genel bakışla açılış (sinematik giriş) t.adimBaslangic = zaman; t.otomatik = true; t.sonBakisIdx = -2; } void farkTurDurdur() { FarkTurDurum& t = farkTur(); t.analiz = 0; t.idx = -1; } namespace { // Aktif (açık + hazır) ilk Fark analizi — işaretçi tur kapalıyken de bunu izler. analiz::AnalizNesnesi* aktifFark(analiz::AnalizSistemi& an) { for (u32 k : an.hepsi()) { analiz::AnalizNesnesi* a = an.bul(k); if (a && a->tip() == analiz::AnalizTip::Fark && a->aktif && a->sonuc.hazir) return a; } return nullptr; } // Maks-sapma işaretçisi: nabızlı çift halka + değer etiketi (CAD ölçüm estetiği). void isaretciCiz(ImDrawList* ciz, const ImVec2& e, f32 zaman, f32 deger, ImU32 renk) { const f32 nabiz = 0.5f + 0.5f * std::sin(zaman * 4.0f); ciz->AddCircle(e, 9.0f + nabiz * 5.0f, renk, 0, 2.2f); ciz->AddCircleFilled(e, 3.5f, renk); ciz->AddCircle(e, 16.0f + nabiz * 8.0f, (renk & 0x00FFFFFF) | ((ImU32)(90 - nabiz * 60) << 24), 0, 1.2f); char m[48]; std::snprintf(m, sizeof(m), "▼ maks %.3f mm", deger); const ImVec2 ts = ImGui::CalcTextSize(m); const ImVec2 p0{e.x + 14.0f, e.y - ts.y - 12.0f}; ciz->AddRectFilled({p0.x - 5, p0.y - 3}, {p0.x + ts.x + 5, p0.y + ts.y + 3}, IM_COL32(12, 16, 24, 215), 4.0f); ciz->AddRect({p0.x - 5, p0.y - 3}, {p0.x + ts.x + 5, p0.y + ts.y + 3}, renk, 4.0f, 0, 1.0f); ciz->AddText(p0, IM_COL32(240, 244, 250, 255), m); ciz->AddLine({e.x + 3, e.y - 3}, {p0.x - 2, p0.y + ts.y + 3}, renk, 1.0f); } } // namespace void farkTurCiz(analiz::AnalizSistemi& an, Sahne& sahne, OrbitKamera& kamera, f32 zaman, ImDrawList* ciz, const std::function& ekrana, f32 vpMinX, f32 vpMinY, f32 vpBoyX, f32 vpBoyY) { (void)sahne; FarkTurDurum& t = farkTur(); const ImVec4 vurgu = ui::tema().vurgu; const ImU32 vurguU = ImGui::ColorConvertFloat4ToU32(vurgu); // ---- Maks-sapma işaretçisi (tur bağımsız: aktif Fark analizi görünürken hep) ---- analiz::AnalizNesnesi* af = aktifFark(an); if (af && t.isaretci && af->farkMaks > 0.0f) { ImVec2 e; if (ekrana(af->farkMaksNokta, e) && e.x >= vpMinX && e.x <= vpMinX + vpBoyX && e.y >= vpMinY && e.y <= vpMinY + vpBoyY) isaretciCiz(ciz, e, zaman, af->farkMaks, IM_COL32(255, 92, 92, 255)); } // ---- Kalıcı NUMARALI bölge işaretçileri (tur aktif DEĞİLKEN): panel bölge listesiyle // korelasyon — her değişim bölgesi 3D'de numaralı rozet (mavi=eklenen, kırmızı=silinen). // En çok 15 bölge (ekran karışmasın); tur açıkken kendi işaretçisi çizer (bu blok atlanır). if (af && t.isaretci && !t.analiz && !af->farkBolgeler.empty()) { const int nb = std::min((int)af->farkBolgeler.size(), std::max(farkIsaretciAzami(), 0)); for (int i = 0; i < nb; ++i) { const FarkBolge& b = af->farkBolgeler[i]; ImVec2 e; if (!ekrana(b.merkez, e) || e.x < vpMinX || e.x > vpMinX + vpBoyX || e.y < vpMinY || e.y > vpMinY + vpBoyY) continue; const ImU32 rk = b.eklenen ? IM_COL32(64, 150, 235, 235) : IM_COL32(230, 80, 96, 235); ciz->AddCircleFilled(e, 8.0f, IM_COL32(16, 20, 28, 220)); ciz->AddCircle(e, 8.0f, rk, 0, 1.6f); char num[8]; std::snprintf(num, sizeof(num), "%d", i + 1); const ImVec2 ts = ImGui::CalcTextSize(num); ciz->AddText({e.x - ts.x * 0.5f, e.y - ts.y * 0.5f}, IM_COL32(235, 240, 248, 255), num); } } // ---- Sinematik tur ---- if (!t.analiz) return; analiz::AnalizNesnesi* a = an.bul(t.analiz); if (!a || a->tip() != analiz::AnalizTip::Fark || !a->sonuc.hazir || a->farkBolgeler.empty()) { farkTurDurdur(); return; } const auto& bolgeler = a->farkBolgeler; const int n = (int)bolgeler.size(); t.idx = std::min(t.idx, n - 1); // Kamera hedefi: genel bakış (-1) = tüm bölgeleri kapsayan küre; bölge = merkez + // yarıçap × pay. Her kare set etmek güvenli — OrbitKamera yumuşatması hedefe uçar. if (t.idx < 0) { Vec3f mn{3e30f, 3e30f, 3e30f}, mx{-3e30f, -3e30f, -3e30f}; for (const FarkBolge& b : bolgeler) { mn.x = std::min(mn.x, b.merkez.x - b.yaricap); mx.x = std::max(mx.x, b.merkez.x + b.yaricap); mn.y = std::min(mn.y, b.merkez.y - b.yaricap); mx.y = std::max(mx.y, b.merkez.y + b.yaricap); mn.z = std::min(mn.z, b.merkez.z - b.yaricap); mx.z = std::max(mx.z, b.merkez.z + b.yaricap); } kamera.sigdir((mn + mx) * 0.5f, std::max((mx - mn).uzunluk() * 0.5f, 1e-3f) * 1.15f); } else { const FarkBolge& b = bolgeler[t.idx]; kamera.sigdir(b.merkez, b.yaricap * 2.2f); // Bakış yönü (adım başına BİR kez — kullanıcı bekleme sırasında orbit edebilsin): // bölgeyi model merkezinden dışarı yönden cepheden gör (sinematik kadraj). if (t.bakisDondur && t.sonBakisIdx != t.idx) { t.sonBakisIdx = t.idx; if (Dugum* hd = sahne.bul(a->hedefGovde)) { const Vec3f ym = (hd->yerelSinir.asgari + hd->yerelSinir.azami) * 0.5f; const Vec3d mw = hd->donusum.noktaUygula({(f64)ym.x, (f64)ym.y, (f64)ym.z}); const Vec3f disari = b.merkez - Vec3f{(f32)mw.x, (f32)mw.y, (f32)mw.z}; if (disari.uzunlukKare() > 1e-6f) kamera.bakisGit(disari.birim()); } } // Aktif bölge merkez işaretçisi (yeşil=eklenen, kırmızı=silinen). ImVec2 e; if (ekrana(b.merkez, e)) isaretciCiz(ciz, e, zaman, b.maksSapma, b.eklenen ? IM_COL32(64, 220, 128, 255) : IM_COL32(255, 92, 92, 255)); } // Otomatik ilerleme: süre dolunca sıradaki bölge; son bölgeden sonra tur biter. const f32 gecen = zaman - t.adimBaslangic; const f32 sure = (f32)std::max(farkTurSaniye(), 1.0); if (t.otomatik && gecen >= sure) { if (t.idx + 1 >= n) { farkTurDurdur(); return; } ++t.idx; t.adimBaslangic = zaman; } // ---- Anlatım paneli (alt-orta, yarı saydam; ilerleme + kontroller) ---- const f32 panoW = std::min(460.0f, vpBoyX - 24.0f); ImGui::SetNextWindowPos({vpMinX + vpBoyX * 0.5f, vpMinY + vpBoyY - 16.0f}, ImGuiCond_Always, {0.5f, 1.0f}); ImGui::SetNextWindowSize({panoW, 0}); ImGui::SetNextWindowBgAlpha(0.82f); if (ImGui::Begin("##farkTurAnlatim", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { if (t.idx < 0) { ImGui::TextColored(vurgu, "⇄ CAD Fark Turu"); ImGui::TextUnformatted("Genel bakış — değişim bölgeleri kadraja alınıyor..."); ImGui::Text("%d bölge bulundu (maks sapmaya göre sıralı)", n); // Özet: eklenen/silinen dağılımı + en büyük sapma (bölgeler zaten sıralı → [0]). int ekle = 0; for (const FarkBolge& fb : bolgeler) if (fb.eklenen) ++ekle; ImGui::TextColored(ImVec4(0.35f, 0.85f, 0.5f, 1.0f), "● %d eklenen", ekle); ImGui::SameLine(); ImGui::TextColored(ImVec4(1.0f, 0.42f, 0.42f, 1.0f), " ● %d silinen", n - ekle); ImGui::SameLine(); ImGui::TextDisabled(" · en büyük %.3f mm", bolgeler[0].maksSapma); } else { const FarkBolge& b = bolgeler[t.idx]; ImGui::TextColored(vurgu, "⇄ Bölge %d / %d", t.idx + 1, n); ImGui::SameLine(); ImGui::TextColored(b.eklenen ? ImVec4(0.35f, 0.85f, 0.5f, 1.0f) : ImVec4(1.0f, 0.42f, 0.42f, 1.0f), b.eklenen ? "● EKLENEN" : "● SİLİNEN"); ImGui::SameLine(); ImGui::TextDisabled("· %s", bolgeTipAdi(b)); // tip sezgisi (delik/çıkıntı/kenar) ImGui::Text("Maks sapma: %.3f mm · %u vertex · yarıçap %.1f mm", b.maksSapma, b.vertexSayi, b.yaricap); } ImGui::ProgressBar(std::clamp(gecen / sure, 0.0f, 1.0f), {-1.0f, 4.0f}, ""); // Kontroller: önceki/oynat-duraklat/sonraki/kapat. if (ImGui::SmallButton("⏮##ftIlk")) { t.idx = -1; t.adimBaslangic = zaman; } ImGui::SameLine(); if (ImGui::SmallButton("◀##ftGeri") && t.idx > -1) { --t.idx; t.adimBaslangic = zaman; } ImGui::SameLine(); if (ImGui::SmallButton(t.otomatik ? "⏸##ftDur" : "▶##ftOyna")) t.otomatik = !t.otomatik; ImGui::SameLine(); if (ImGui::SmallButton("▶▶##ftIleri")) { if (t.idx + 1 < n) { ++t.idx; t.adimBaslangic = zaman; } else farkTurDurdur(); } ImGui::SameLine(); if (ImGui::SmallButton("✕##ftKapat")) farkTurDurdur(); ImGui::SameLine(); ImGui::TextDisabled("%.0f sn/bölge", farkTurSaniye()); } ImGui::End(); } } // namespace fiko