#include "sahne_overlay.hpp" #include #include #include #include #include "fiko/render/orbit_kamera.hpp" #include "fiko/render/referans_olcek.hpp" #include "fiko/sahne/alan_secim.hpp" #include "fiko/sahne/sahne.hpp" namespace fiko { void sahneRefTrapOverlayCiz(Sahne& sahne, OrbitKamera& kamera, AlanSecim& alan, ImDrawList* ciz, ImGuiIO& io, f32 vpRectMinX, f32 vpRectMinY, f32 vpBoyutX, f32 vpBoyutY, f32 sonEnBoy) { const Mat4f olcVp = kamera.izdusum(sonEnBoy) * kamera.gorunum(); // ---- Referans eksen etiketleri (x/y/z) + orijin noktası (CATIA tarzı) ---- // Etiketler + merkez, eksen ÇİZGİLERİYLE aynı düğüm dönüşümünden türetilir // (pusula ile taşıma tek grup olarak taşır). Çizgiler render'da dugumMvp = // referansGorselMvp(vp, d.matris(), pivot, ...) ile çizilir; etiket/merkez // AYNI kompozit matrisle projekte edilir → çizgi/yazı/merkez birlikte hareket. { const ImU32 refRenk = IM_COL32(205, 208, 216, 255); const f32 kamMesafe = kamera.mesafe(); // Kompozit MVP ile yerel noktayı ekrana projekte et (ekrana()'nın matris // versiyonu; h.w kontrolü + viewport-yerel piksel). const auto ekranaMvp = [&](const Mat4f& mvp, const Vec3f& p, ImVec2& s) -> bool { const Vec4f h = mvp * Vec4f{p.x, p.y, p.z, 1.0f}; if (h.w <= 1e-4f) return false; s.x = vpRectMinX + (h.x / h.w * 0.5f + 0.5f) * vpBoyutX; s.y = vpRectMinY + (h.y / h.w * 0.5f + 0.5f) * vpBoyutY; return true; }; // TEK Eksen Sistemi düğümünden x/y/z etiketleri + orijin noktası. Eksen // renkleriyle eşleşen etiket rengi (X kırmızı / Y yeşil / Z mavi). for (auto& d : sahne.dugumler()) { if (d.tip != DugumTip::EksenSistemi || !sahne.agacGorunur(d.kimlik)) continue; // Çizgilerle birebir aynı ekran-sabit kompozit (pivot = düğüm dünya konumu). const Vec3f pivot{(f32)d.donusum.konum.x, (f32)d.donusum.konum.y, (f32)d.donusum.konum.z}; const Mat4f mvp = referansGorselMvp(olcVp, d.matris(), pivot, kamMesafe, REFERANS_ORAN_EKSEN, d.gorselOran); struct ET { Vec3f yon; const char* et; ImU32 renk; }; const ET etler[3] = { {{1, 0, 0}, "x", IM_COL32(235, 70, 72, 255)}, {{0, 1, 0}, "y", IM_COL32(78, 210, 92, 255)}, {{0, 0, 1}, "z", IM_COL32(84, 135, 250, 255)}}; for (const ET& e : etler) { ImVec2 s; // yerel uç: yön · (EKS_L 5.0 + pay); ölçek MVP'ye gömülü. if (ekranaMvp(mvp, e.yon * 5.55f, s)) ciz->AddText({s.x + 3, s.y - 7}, e.renk, e.et); } ImVec2 orij; // yerel origin (0,0,0) → düğüm konumuna gider. if (ekranaMvp(mvp, Vec3f{0, 0, 0}, orij)) ciz->AddCircleFilled(orij, 2.8f, refRenk); } } // ---- Alan seçimi (trap) overlay: CATIA görsel dili (tipe göre stil) ---- // Nokta listeleri viewport-yerel (lx/ly) → mutlak ekran için vpRectMin ekle. if (alan.aktifMi()) { const bool kesen = alan.kesenMi(); const bool dis = alan.tip == TrapTip::DisRadikdortgen || alan.tip == TrapTip::DisKesen; // Renk: içinde=mavi, kesen=yeşil, dış=kırmızı, fırça=turuncu. ImU32 kenarRenk = dis ? IM_COL32(235, 90, 90, 235) : kesen ? IM_COL32(90, 220, 130, 235) : IM_COL32(120, 190, 255, 235); if (alan.tip == TrapTip::FircaIzi) kenarRenk = IM_COL32(255, 165, 60, 240); const ImU32 dolguRenk = dis ? IM_COL32(235, 90, 90, 26) : kesen ? IM_COL32(90, 220, 130, 26) : IM_COL32(120, 190, 255, 26); const auto mut = [&](const Vec2f& p) { return ImVec2(vpRectMinX + p.x, vpRectMinY + p.y); }; // Kesikli kenar (kesen/dış modları): elle segment; içinde = düz. const bool kesikli = kesen; auto kesikliDikdortgen = [&](ImVec2 a, ImVec2 b) { const ImVec2 kose[4] = {{a.x, a.y}, {b.x, a.y}, {b.x, b.y}, {a.x, b.y}}; for (int i = 0; i < 4; ++i) { const ImVec2 p0 = kose[i], p1 = kose[(i + 1) % 4]; const f32 uz = std::sqrt((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y)); const int seg = std::max(1, (int)(uz / 8.0f)); for (int s = 0; s < seg; s += 2) { const f32 t0 = (f32)s / seg, t1 = (f32)std::min(s + 1, seg) / seg; ciz->AddLine({p0.x + (p1.x - p0.x) * t0, p0.y + (p1.y - p0.y) * t0}, {p0.x + (p1.x - p0.x) * t1, p0.y + (p1.y - p0.y) * t1}, kenarRenk, 1.4f); } } }; if (alan.tip == TrapTip::FircaIzi) { const auto& iz = alan.iz(); for (std::size_t i = 1; i < iz.size(); ++i) ciz->AddLine(mut(iz[i - 1]), mut(iz[i]), kenarRenk, 4.0f); } else if (alan.poligonKipMi()) { const auto& iz = alan.iz(); std::vector pts; pts.reserve(iz.size() + 1); for (const Vec2f& p : iz) pts.push_back(mut(p)); if (pts.size() >= 2) { // Kapanış ön-izlemesi: son köşe → imleç. pts.push_back(ImVec2(io.MousePos.x, io.MousePos.y)); ciz->AddPolyline(pts.data(), (int)pts.size(), kenarRenk, 0, 1.6f); ciz->AddLine(pts.back(), pts.front(), kenarRenk, 1.0f); } for (const Vec2f& p : iz) ciz->AddCircleFilled(mut(p), 3.0f, kenarRenk); } else { const ImVec2 a = mut(alan.bas()), b = mut(alan.son()); const ImVec2 asg{std::min(a.x, b.x), std::min(a.y, b.y)}; const ImVec2 azm{std::max(a.x, b.x), std::max(a.y, b.y)}; ciz->AddRectFilled(asg, azm, dolguRenk); if (kesikli) kesikliDikdortgen(asg, azm); else ciz->AddRect(asg, azm, kenarRenk, 0.0f, 0, 1.4f); } // Canlı aday sayısı HUD (imleç yakını). const Mat4f trapVp = kamera.izdusum(sonEnBoy) * kamera.gorunum(); const u32 aday = alan.adaySayisi(trapVp, {0.0f, 0.0f}, {vpBoyutX, vpBoyutY}); char hud[64]; const char* trapKipAd = sahne.kip() == SecimKip::Yuz ? "yüz" : sahne.kip() == SecimKip::Kenar ? "kenar" : sahne.kip() == SecimKip::Nokta ? "nokta" : "gövde"; std::snprintf(hud, sizeof(hud), "%u %s", aday, trapKipAd); ciz->AddText({io.MousePos.x + 14, io.MousePos.y + 4}, kenarRenk, hud); } } } // namespace fiko