#include "olcum_penceresi.hpp" #include #include #include #include #include "fiko/ayar/ayar_sistemi.hpp" // global birim küsürat ayarı (Ayarlar → Birimler) #include "fiko/core/birim_bicim.hpp" #include "fiko/sahne/olcum_sistemi.hpp" #include "fiko/ui/pencere_cerceve.hpp" // ui::Pencere — merkezi pencere iskeleti #include "fiko/ui/pencere_util.hpp" #include "imgui.h" #include "uygulama_baglam.hpp" namespace fiko { namespace { constexpr u32 SURUKLE_CANLI = 0xFFFFFFFFu; // canlı (henüz kalıcı olmayan) ölçüm sürükleme kimliği } // namespace void olcumPenceresiCiz(UygulamaBaglam& b, bool& olcumUstte) { OlcumSistemi& olcum = b.olcum; auto& bilgiVer = b.bilgiVer; const f32 ekranG = ImGui::GetIO().DisplaySize.x; // ---- FikoYT Ölçüm penceresi (CATIA tarzı: Kumpas/Cetvel/Ayarlar) ---- if (olcum.acik) { // ui::Pencere iskeleti (pencere standardı): pin + yükseklik cap + global skin + // konum kalıcılığı merkezi. FirstUseEver sağ-üst açılış konumu birebir. ImGui::SetNextWindowPos({ekranG - 316, 92}, ImGuiCond_FirstUseEver); ui::Pencere pen{"FikoYT Ölçüm", &olcum.acik, {.boyut = {296, 0}, .pinDurum = &olcumUstte}}; if (pen) { // Mod sekmeleri (Kumpas tekli / Cetvel ikili / Ayarlar) const auto sekme = [&](const char* et, OlcumKip k, const char* ipucu) { const bool aktif = olcum.kip == k; if (aktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.13f, 0.50f, 0.85f, 1.0f}); if (ImGui::Button(et, {0, 0})) { olcum.kip = k; olcum.secimSifirla(); } if (aktif) ImGui::PopStyleColor(); if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", ipucu); }; sekme("⌖ Kumpas", OlcumKip::Kumpas, "Tekli öğe özellikleri (çap, alan, uzunluk, koordinat)"); ImGui::SameLine(); sekme("↔ Cetvel", OlcumKip::Cetvel, "İki öğe arası mesafe / açı (5 mod)"); ImGui::SameLine(); sekme("⛓ Zincir", OlcumKip::Zincir, "Ardışık noktalar arası zincir + canlı toplam"); ImGui::SameLine(); sekme("⚙", OlcumKip::Ayarlar, "Ayarlar"); ImGui::Separator(); const char* filtreAd[] = {"Her Şey", "Sadece Yüzey", "Sadece Çizgi", "Sadece Nokta", "✚ Nokta Koy (Yüzey)"}; constexpr int filtreSayi = 5; // Per-seçim mesafe modu adları (enum sırası: Akıllı,KısaDüz,EnKısa,Merkez,EnUzak,UzakDüz) const char* modAd[] = {"✦ Akıllı", "⊥ Kısa Düz", "↔ En Kısa", "⊙ Merkez", "⤢ En Uzak", "⇕ Uzak Düz"}; constexpr int modSayi = 6; if (olcum.kip == OlcumKip::Ayarlar) { ImGui::TextDisabled("Ölçüm Ayarları"); ImGui::Checkbox("Ölçümler Kalıcı Olsun (otomatik)", &olcum.kaliciVarsayilan); // ImGui::SetNextItemWidth(-1); int uzHane = birim::hane(birim::Birim::Uzunluk); // GLOBAL uzunluk küsüratı if (ImGui::SliderInt("Uzunluk Küsürat (mm)", &uzHane, 0, 8, "%d hane")) ayar::sistem().degerAta("birim.uzunluk_hane", ayar::dInt(uzHane)); // kalıcı + tazele ImGui::TextDisabled("Tüm birimlerin küsüratı: Ayarlar → Birimler"); int mm = (int)olcum.mod1; // ImGui::SetNextItemWidth(-1); if (ImGui::Combo("Varsayılan Mod (ikisi)", &mm, modAd, modSayi)) { olcum.mod1 = olcum.mod2 = (MesafeModu)mm; olcum.yenidenHesapla(); } ImGui::Separator(); ImGui::TextDisabled("Akıllı: geometriye göre otomatik seçer\n(silindir→merkez, düzlem→dik, diğer→en kısa)."); ImGui::TextDisabled("Kalıcı ölçümler ürün ağacı/geometri ile\nparametrik bağlı — çizim değişince güncellenir."); } else if (olcum.kip == OlcumKip::Zincir) { // ---- Ölçüm zinciri: ardışık nokta → canlı toplam ---- int f1 = (int)olcum.filtre1; // ImGui::SetNextItemWidth(-1); if (ImGui::Combo("Filtre:", &f1, filtreAd, filtreSayi)) olcum.filtre1 = (SecimFiltre)f1; ImGui::TextDisabled("3D'de ardışık öğe seç (yüz/kenar/nokta/gövde — Cetvel gibi).\nFiltre'den daralt; ✚ Nokta Koy ile yüzeyde serbest nokta.\nBackspace: son noktayı sil · Enter: bitir."); ImGui::Separator(); // Klavye kısayolları (pencere açık + Zincir kipi) if (ImGui::IsKeyPressed(ImGuiKey_Backspace)) olcum.zincirGeriAl(); if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) { if (olcum.zincirKalicilastir()) bilgiVer("Zincir kalıcı yapıldı"); } ImGui::TextColored({0.35f, 0.85f, 0.9f, 1.0f}, "Zincir (%zu nokta):", olcum.canliZincir.noktalar.size()); if (olcum.canliZincir.dunya.size() >= 2) { const size_t nz = olcum.canliZincir.dunya.size(); for (size_t i = 0; i < olcum.canliZincir.segment.size(); ++i) ImGui::Text(" %zu→%zu: %.*f mm", i + 1, (i + 1) % nz + 1, birim::hane(birim::Birim::Uzunluk), olcum.canliZincir.segment[i]); ImGui::TextColored({1.0f, 0.82f, 0.35f, 1.0f}, " %s", olcum.canliZincir.metin.c_str()); } else { ImGui::TextDisabled("En az 2 nokta seçin"); } bool kap = olcum.canliZincir.kapali; if (ImGui::Checkbox("Kapalı çevrim (son→ilk)", &kap)) olcum.zincirKapatToggle(); ImGui::Dummy({0, 2}); if (ImGui::Button("↶ Son Nokta")) olcum.zincirGeriAl(); ImGui::SameLine(); if (ImGui::Button("Sıfırla")) olcum.zincirSifirla(); const bool zk = olcum.canliZincir.noktalar.size() >= 2; if (!zk) ImGui::BeginDisabled(); ImGui::PushStyleColor(ImGuiCol_Button, {0.30f, 0.68f, 0.32f, 1.0f}); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, {0.34f, 0.76f, 0.36f, 1.0f}); if (ImGui::Button("📌 Zinciri Kalıcı Yap", {-1, 0})) { if (olcum.zincirKalicilastir()) bilgiVer("Zincir kalıcı yapıldı"); } ImGui::PopStyleColor(2); if (!zk) ImGui::EndDisabled(); } else { const bool cetvel = olcum.kip == OlcumKip::Cetvel; constexpr float etiketGenislik = 92.0f; // sol etiket sütunu (Combo etiketlerini sola almak için) // Seçim filtreleri int f1 = (int)olcum.filtre1; if (cetvel) { ImGui::TextUnformatted("Seçim 1:"); ImGui::SameLine(etiketGenislik); } ImGui::SetNextItemWidth(-1); if (ImGui::Combo(cetvel ? "##secim1" : "", &f1, filtreAd, filtreSayi)) olcum.filtre1 = (SecimFiltre)f1; if (cetvel) { int f2 = (int)olcum.filtre2; ImGui::TextUnformatted("Seçim 2:"); ImGui::SameLine(etiketGenislik); ImGui::SetNextItemWidth(-1); if (ImGui::Combo("##secim2", &f2, filtreAd, filtreSayi)) olcum.filtre2 = (SecimFiltre)f2; } // ---- Kumpas: referans eksen (koordinat bu çerçeveye göre; boşsa global sıfır) ---- if (!cetvel) { if (olcum.eksenSecModu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(olcum.eksenSecModu ? "🎯 Eksen seç…" : "🎯", {0, 0})) olcum.eksenSecModu = !olcum.eksenSecModu; if (olcum.eksenSecModu) ImGui::PopStyleColor(); ImGui::SameLine(); ImGui::TextDisabled("Eksen:"); ImGui::SameLine(); ImGui::TextColored({0.9f, 0.85f, 0.5f, 1.0f}, "%s", olcum.eksenAdi().c_str()); if (olcum.eksenRef.var) { ImGui::SameLine(); if (ImGui::SmallButton("✕##eksen")) olcum.eksenTemizle(); } // ImGui::TextDisabled("Seçili değilse koordinat global (0,0,0)'a göre."); } ImGui::Separator(); // ImGui::TextColored({0.35f, 0.85f, 0.9f, 1.0f}, "Seçimler:"); const auto refSatir = [&](const char* et, const OlcumRef& r) { ImGui::TextDisabled("%s", et); ImGui::SameLine(); if (!r.var) { ImGui::TextUnformatted("Seçilen Yok"); return; } ImGui::TextColored({0.9f, 0.85f, 0.5f, 1.0f}, "%s", r.tipAd.c_str()); if (!r.altTipAd.empty()) { ImGui::SameLine(); ImGui::TextDisabled("(%s)", r.altTipAd.c_str()); } }; refSatir("Seçim 1 Tipi:", olcum.ref1); if (cetvel) refSatir("Seçim 2 Tipi:", olcum.ref2); // Per-seçim mesafe modu (sadece Cetvel) — her seçim ayrı ayarlanır (CATIA/web). if (cetvel) { int md1 = (int)olcum.mod1; ImGui::TextUnformatted("Seçim 1 Modu"); ImGui::SameLine(etiketGenislik); ImGui::SetNextItemWidth(-1); if (ImGui::Combo("##secim1mod", &md1, modAd, modSayi)) { olcum.mod1 = (MesafeModu)md1; olcum.yenidenHesapla(); } int md2 = (int)olcum.mod2; ImGui::TextUnformatted("Seçim 2 Modu"); ImGui::SameLine(etiketGenislik); ImGui::SetNextItemWidth(-1); if (ImGui::Combo("##secim2mod", &md2, modAd, modSayi)) { olcum.mod2 = (MesafeModu)md2; olcum.yenidenHesapla(); } } ImGui::Separator(); ImGui::TextColored({0.35f, 0.85f, 0.9f, 1.0f}, "Sonuç:"); if (olcum.canliVar) { if (!olcum.canli.aciklama.empty()) ImGui::TextWrapped("%s", olcum.canli.aciklama.c_str()); std::string sonuc = olcum.canli.metin; for (char& ch : sonuc) if (ch == '\n') ch = ' '; ImGui::TextColored({1.0f, 0.82f, 0.35f, 1.0f}, " %s", sonuc.c_str()); } else { ImGui::TextDisabled(cetvel ? "3D'de iki öğe seçin" : "3D'de bir öğe seçin"); } // Kalıcılaştır ImGui::Dummy({0, 2}); const bool kalicilanabilir = olcum.canliVar; if (!kalicilanabilir) ImGui::BeginDisabled(); ImGui::PushStyleColor(ImGuiCol_Button, {0.30f, 0.68f, 0.32f, 1.0f}); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, {0.34f, 0.76f, 0.36f, 1.0f}); if (ImGui::Button("📌 Ölçüm Kalıcı Olsun", {-1, 0})) { if (olcum.kalicilastir()) { olcum.secimSifirla(); bilgiVer("Ölçüm kalıcı yapıldı"); } } ImGui::PopStyleColor(2); if (!kalicilanabilir) ImGui::EndDisabled(); ImGui::Checkbox("Ölçümler Kalıcı Olsun", &olcum.kaliciVarsayilan); } // Kalıcı ölçüm listesi (her modda görünür) if (!olcum.hepsi().empty()) { ImGui::Separator(); ImGui::TextDisabled("Kalıcı Ölçümler (%zu)", olcum.hepsi().size()); u32 silinecek = 0; for (const Olcum& oc : olcum.hepsi()) { ImGui::PushID((int)oc.kimlik); std::string tek = oc.metin; for (char& ch : tek) if (ch == '\n') ch = ' '; if (!oc.gecerli) ImGui::PushStyleColor(ImGuiCol_Text, {0.6f, 0.4f, 0.4f, 1.0f}); ImGui::Text("%s", tek.c_str()); if (!oc.gecerli) ImGui::PopStyleColor(); ImGui::SameLine(ImGui::GetWindowContentRegionMax().x - 18); if (ImGui::SmallButton("✕")) silinecek = oc.kimlik; ImGui::PopID(); } if (silinecek) olcum.sil(silinecek); if (ImGui::SmallButton("Tümünü Temizle")) olcum.temizle(); } // Kalıcı zincir listesi if (!olcum.zincirler().empty()) { ImGui::Separator(); ImGui::TextDisabled("Kalıcı Zincirler (%zu)", olcum.zincirler().size()); u32 silinecekZ = 0; for (const OlcumZincir& z : olcum.zincirler()) { ImGui::PushID((int)z.kimlik + 200000); if (!z.gecerli) ImGui::PushStyleColor(ImGuiCol_Text, {0.6f, 0.4f, 0.4f, 1.0f}); ImGui::Text("⛓ %s", z.metin.c_str()); if (!z.gecerli) ImGui::PopStyleColor(); ImGui::SameLine(ImGui::GetWindowContentRegionMax().x - 18); if (ImGui::SmallButton("✕")) silinecekZ = z.kimlik; ImGui::PopID(); } if (silinecekZ) olcum.zincirSil(silinecekZ); if (ImGui::SmallButton("Zincirleri Temizle")) olcum.zincirTemizle(); } } } } void olcumOverlayCiz(OlcumSistemi& olcum, const std::function& ekrana, const std::function& imlecVurus, ImDrawList* ciz, ImGuiIO& io, bool vpHover, f32 vpRectMinX, f32 vpRectMinY, u32& olcumSurukle, int& olcumSurukleMod, bool& kameraKullandi) { // ofsetYon'u a→b ekseni etrafında oc.aci kadar döndür (Rodrigues) — döndürme özelliği const auto ofsetEt = [](const Olcum& oc) -> Vec3f { if (std::abs(oc.aci) < 1e-5f) return oc.ofsetYon; Vec3f ax = (oc.b - oc.a); if (ax.uzunlukKare() < 1e-10f) return oc.ofsetYon; ax = ax.birim(); const f32 c = std::cos(oc.aci), s = std::sin(oc.aci); return oc.ofsetYon * c + ax.capraz(oc.ofsetYon) * s + ax * (ax.nokta(oc.ofsetYon)) * (1.0f - c); }; const auto cizOlcum = [&](Olcum& oc, bool onizleme) { if (!oc.gecerli) return; const ImU32 ana = onizleme ? IM_COL32(120, 220, 255, 235) : IM_COL32(255, 196, 64, 255); const ImU32 soluk = onizleme ? IM_COL32(120, 220, 255, 130) : IM_COL32(255, 196, 64, 150); const auto okCiz = [&](ImVec2 uc, ImVec2 hedef) { f32 dx = hedef.x - uc.x, dy = hedef.y - uc.y; const f32 L = std::sqrt(dx * dx + dy * dy); if (L < 1.0f) return; dx /= L; dy /= L; ciz->AddTriangleFilled(uc, ImVec2(uc.x + dx * 11 - dy * 4, uc.y + dy * 11 + dx * 4), ImVec2(uc.x + dx * 11 + dy * 4, uc.y + dy * 11 - dx * 4), ana); }; bool ustunde = false; const auto etiketCiz = [&](ImVec2 poz, const char* metin) { const ImVec2 ts = ImGui::CalcTextSize(metin); const ImVec2 rmin(poz.x - ts.x * 0.5f - 5, poz.y - ts.y * 0.5f - 3); const ImVec2 rmax(poz.x + ts.x * 0.5f + 5, poz.y + ts.y * 0.5f + 3); ustunde = vpHover && ImGui::IsMouseHoveringRect(rmin, rmax); ciz->AddRectFilled(rmin, rmax, IM_COL32(22, 26, 36, 225), 4.0f); ciz->AddRect(rmin, rmax, ustunde ? IM_COL32(120, 220, 255, 255) : soluk, 4.0f); ciz->AddText(ImVec2(rmin.x + 5, rmin.y + 3), IM_COL32(240, 240, 245, 255), metin); }; const auto artiCiz = [&](ImVec2 p) { ciz->AddLine(ImVec2(p.x - 5, p.y), ImVec2(p.x + 5, p.y), ana, 1.5f); ciz->AddLine(ImVec2(p.x, p.y - 5), ImVec2(p.x, p.y + 5), ana, 1.5f); }; if (oc.tur == OlcumTur::Mesafe || oc.tur == OlcumTur::Uzunluk || oc.tur == OlcumTur::Cap) { const Vec3f oy = ofsetEt(oc); // Her şahit çizgisinin İKİ ucu da bağımsız: geometri tarafı (taban) + ölçü tarafı (uzatma). const Vec3f ga3 = oc.a + oy * oc.taban1; // geometri ucu A const Vec3f gb3 = oc.b + oy * oc.taban2; // geometri ucu B const Vec3f oa3 = oc.a + oy * (oc.ofset + oc.uzatma1); // ölçü ucu A const Vec3f ob3 = oc.b + oy * (oc.ofset + oc.uzatma2); // ölçü ucu B ImVec2 ga, gb, oa, ob; if (!ekrana(ga3, ga) || !ekrana(gb3, gb) || !ekrana(oa3, oa) || !ekrana(ob3, ob)) return; ciz->AddLine(ga, oa, soluk, 1.0f); ciz->AddLine(gb, ob, soluk, 1.0f); ciz->AddLine(oa, ob, ana, 1.8f); okCiz(oa, ob); okCiz(ob, oa); const u32 sid = onizleme ? SURUKLE_CANLI : oc.kimlik; // oy'nin ekran-uzayı yönü → sürükleme deltasını ofset eksenine projekte et. const auto eksenSurukle = [&](const Vec3f& taban3, f32& hedef) { ImVec2 s0, s1; if (ekrana(taban3, s0) && ekrana(taban3 + oy, s1)) { const f32 vx = s1.x - s0.x, vy = s1.y - s0.y, L2 = vx * vx + vy * vy; if (L2 > 1e-6f) hedef += (io.MouseDelta.x * vx + io.MouseDelta.y * vy) / L2; } }; // Şahit uç tutamağı: sürükleyerek o ucu bağımsız uzat/kısalt. // mod 2=ölçü ucu A, 3=ölçü ucu B, 4=geometri ucu A, 5=geometri ucu B. const auto ucTutamak = [&](ImVec2 uc, const Vec3f& taban3, int mod, f32& uzatma) { const bool uzer = vpHover && ImGui::IsMouseHoveringRect( ImVec2(uc.x - 6, uc.y - 6), ImVec2(uc.x + 6, uc.y + 6)); ciz->AddCircleFilled(uc, 3.5f, uzer ? IM_COL32(120, 220, 255, 255) : soluk); if (uzer && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { olcumSurukle = sid; olcumSurukleMod = mod; } if (olcumSurukle == sid && olcumSurukleMod == mod) { kameraKullandi = true; if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) eksenSurukle(taban3, uzatma); else olcumSurukle = 0; } }; ucTutamak(oa, oc.a, 2, oc.uzatma1); ucTutamak(ob, oc.b, 3, oc.uzatma2); ucTutamak(ga, oc.a, 4, oc.taban1); ucTutamak(gb, oc.b, 5, oc.taban2); const Vec3f orta3 = (oa3 + ob3) * 0.5f; ImVec2 om; if (ekrana(orta3, om)) { om.y -= 12; etiketCiz(om, oc.metin.c_str()); // Etiket: taşı (sol=ofset) / döndür (sağ). Canlı önizleme de dahil (kimlik=CANLI). if (ustunde) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { olcumSurukle = sid; olcumSurukleMod = 0; } else if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { olcumSurukle = sid; olcumSurukleMod = 1; } } if (olcumSurukle == sid && (olcumSurukleMod == 0 || olcumSurukleMod == 1)) { kameraKullandi = true; const bool aktif = olcumSurukleMod == 0 ? ImGui::IsMouseDown(ImGuiMouseButton_Left) : ImGui::IsMouseDown(ImGuiMouseButton_Right); if (aktif && olcumSurukleMod == 0) eksenSurukle(orta3, oc.ofset); // ofset kaydır else if (aktif) oc.aci += io.MouseDelta.x * 0.01f; // döndür else olcumSurukle = 0; } } } else if (oc.tur == OlcumTur::Aci) { ImVec2 pc, pa, pb; if (!ekrana(oc.c, pc) || !ekrana(oc.a, pa) || !ekrana(oc.b, pb)) return; ciz->AddLine(pc, pa, soluk, 1.0f); ciz->AddLine(pc, pb, soluk, 1.0f); ImVec2 onceki; bool oncekiVar = false; for (const Vec3f& y : oc.yay) { ImVec2 s; if (!ekrana(y, s)) { oncekiVar = false; continue; } if (oncekiVar) ciz->AddLine(onceki, s, ana, 1.8f); onceki = s; oncekiVar = true; } const Vec3f eKon = oc.yay.empty() ? (oc.a + oc.b) * 0.5f : oc.yay[oc.yay.size() / 2]; ImVec2 em; if (ekrana(eKon, em)) { em.y -= 12; etiketCiz(em, oc.metin.c_str()); } } else if (oc.tur == OlcumTur::Yaricap) { ImVec2 pa, pb, pc; if (!ekrana(oc.a, pa) || !ekrana(oc.b, pb) || !ekrana(oc.c, pc)) return; ciz->AddLine(pa, pb, ana, 1.8f); artiCiz(pc); okCiz(pb, pa); ImVec2 em((pa.x + pb.x) * 0.5f, (pa.y + pb.y) * 0.5f - 12); etiketCiz(em, oc.metin.c_str()); } else { // Alan, Koordinat ImVec2 pa; if (!ekrana(oc.a, pa)) return; artiCiz(pa); ImVec2 em(pa.x + 16, pa.y - 16); ciz->AddLine(pa, ImVec2(em.x - 8, em.y + 8), soluk, 1.0f); etiketCiz(em, oc.metin.c_str()); } }; for (Olcum& oc : olcum.hepsi()) cizOlcum(oc, false); if (olcum.acik && olcum.canliVar) cizOlcum(olcum.canli, true); // ---- Ölçüm zincirleri: polyline + segment etiket + toplam + canlı lastik ---- const auto cizZincir = [&](const OlcumZincir& z, bool onizleme) { if (z.dunya.empty()) return; const ImU32 ana = onizleme ? IM_COL32(120, 220, 255, 235) : IM_COL32(255, 196, 64, 255); const ImU32 soluk = onizleme ? IM_COL32(120, 220, 255, 150) : IM_COL32(255, 196, 64, 150); std::vector pts; pts.reserve(z.dunya.size()); for (const Vec3f& w : z.dunya) { ImVec2 s; if (!ekrana(w, s)) return; // biri ekran dışı → çizme (tutarlı) pts.push_back(s); } const int n = (int)pts.size(); const int lim = z.kapali ? n : n - 1; for (int i = 0; i < lim && n >= 2; ++i) { const ImVec2 a = pts[i], b = pts[(i + 1) % n]; ciz->AddLine(a, b, ana, 2.0f); if (i < (int)z.segment.size()) { const ImVec2 mid((a.x + b.x) * 0.5f, (a.y + b.y) * 0.5f); char sb[32]; std::snprintf(sb, sizeof(sb), "%.*f", birim::hane(birim::Birim::Uzunluk), z.segment[i]); const ImVec2 ts = ImGui::CalcTextSize(sb); ciz->AddRectFilled({mid.x - ts.x * 0.5f - 3, mid.y - ts.y * 0.5f - 2}, {mid.x + ts.x * 0.5f + 3, mid.y + ts.y * 0.5f + 2}, IM_COL32(22, 26, 36, 220), 3.0f); ciz->AddText({mid.x - ts.x * 0.5f, mid.y - ts.y * 0.5f}, IM_COL32(235, 240, 245, 255), sb); } } for (int i = 0; i < n; ++i) { ciz->AddCircleFilled(pts[i], 4.0f, ana); ciz->AddCircle(pts[i], 4.0f, IM_COL32(255, 255, 255, 190), 12, 1.2f); } if (!z.metin.empty() && n >= 2) { ImVec2 tp = pts.back(); tp.y -= 18; tp.x += 10; const ImVec2 ts = ImGui::CalcTextSize(z.metin.c_str()); ciz->AddRectFilled({tp.x - 4, tp.y - 3}, {tp.x + ts.x + 4, tp.y + ts.y + 3}, IM_COL32(18, 22, 30, 236), 4.0f); ciz->AddRect({tp.x - 4, tp.y - 3}, {tp.x + ts.x + 4, tp.y + ts.y + 3}, soluk, 4.0f); ciz->AddText({tp.x, tp.y}, IM_COL32(255, 220, 130, 255), z.metin.c_str()); } }; for (const OlcumZincir& z : olcum.zincirler()) cizZincir(z, false); if (olcum.acik && olcum.kip == OlcumKip::Zincir) { cizZincir(olcum.canliZincir, true); // Canlı lastik bant: son nokta → imleç (yüzey noktası varsa oraya) if (vpHover && !olcum.canliZincir.dunya.empty()) { ImVec2 a; if (ekrana(olcum.canliZincir.dunya.back(), a)) ciz->AddLine(a, io.MousePos, IM_COL32(120, 220, 255, 140), 1.5f); } } // Seçili referansları vurgula (canlı ölçüm henüz tamamlanmadıysa 1. seçim görünsün) if (olcum.acik) { // Ölçülen öğe(ler) kalıcı highlight (yeni ölçüm gelene / pencere kapanana dek): // kenar polyline / yüz sınır konturu parlak çizilir + merkez işareti (nabızlı halka). const float nabiz = 0.5f + 0.5f * std::sin((float)ImGui::GetTime() * 4.0f); const auto refIsaret = [&](const OlcumRef& r) { if (!r.var) return; const ImU32 hl = IM_COL32(120, 220, 255, 235); const ImU32 hlKalin = IM_COL32(150, 235, 255, (int)(180 + 75 * nabiz)); for (const auto& lp : r.hlKontur) { ImVec2 onceki{}; bool var = false; for (const Vec3f& w : lp) { ImVec2 s; if (ekrana(w, s)) { if (var) ciz->AddLine(onceki, s, hlKalin, 2.6f); onceki = s; var = true; } else { var = false; } } } ImVec2 s; if (ekrana(r.merkez, s)) { ciz->AddCircleFilled(s, 5.0f, hl); ciz->AddCircle(s, 8.0f + 2.0f * nabiz, hlKalin, 20, 1.6f); } }; refIsaret(olcum.ref1); refIsaret(olcum.ref2); // "Nokta Koy" modu: fare altında geometriye izdüşen canlı nokta — tıklanınca // ölçülür. Fare gezdikçe imleci yüzeye projekte eder (canlı geri bildirim). if (vpHover && olcum.kip != OlcumKip::Ayarlar && olcum.aktifFiltre() == SecimFiltre::SerbestNokta) { const f32 mlx = io.MousePos.x - vpRectMinX, mly = io.MousePos.y - vpRectMinY; Sahne::IsinVurus vr; ImVec2 s; if (imlecVurus(mlx, mly, vr) && vr.govde && ekrana(vr.nokta, s)) { ciz->AddCircleFilled(s, 3.5f, IM_COL32(120, 220, 255, 210)); ciz->AddCircle(s, 7.0f, IM_COL32(120, 220, 255, 255), 0, 1.5f); ciz->AddLine(ImVec2(s.x - 9, s.y), ImVec2(s.x + 9, s.y), IM_COL32(120, 220, 255, 160), 1.0f); ciz->AddLine(ImVec2(s.x, s.y - 9), ImVec2(s.x, s.y + 9), IM_COL32(120, 220, 255, 160), 1.0f); } } } } } // namespace fiko