#include "cam_takim_ekseni_penceresi.hpp" #include #include #include #include "fiko/cam/cam_islem.hpp" #include "fiko/cam/cam_secim.hpp" #include "fiko/cam/cam_sistemi.hpp" #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/core/mat/vec.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/ui/bilesen.hpp" #include "fiko/ui/pencere_cerceve.hpp" #include "fiko/ui/tema.hpp" #include "imgui.h" #include "pencere_util.hpp" namespace fiko { namespace { using cam::CamOperasyon; using cam::CamSecimKip; using cam::CamSistemi; using cam::TakimYonu; // Renk dili — cam_operasyon_penceresi.cpp / cam_strateji_semasi.cpp ile aynı. constexpr ImU32 REN_X = IM_COL32(240, 80, 80, 255); // +X kırmızı constexpr ImU32 REN_Y = IM_COL32(90, 210, 110, 255); // +Y yeşil constexpr ImU32 REN_Z = IM_COL32(90, 150, 255, 255); // +Z mavi constexpr ImU32 REN_TAKIM = IM_COL32(255, 120, 200, 255); // takım sembolü (magenta) constexpr ImU32 REN_ZEMIN = IM_COL32(24, 26, 32, 255); constexpr ImU32 REN_CERCEVE = IM_COL32(70, 78, 92, 255); constexpr ImU32 REN_VURGU = IM_COL32(255, 255, 255, 90); constexpr ImU32 REN_ORIGIN = IM_COL32(220, 226, 234, 255); // Op-başına açık pencere + pin durumu (UI-only, kalıcı değil). Op penceresi kalıbı. std::unordered_map g_taAcik; std::unordered_map g_taPin; // İzometrik projeksiyon (cam_strateji_semasi.cpp Izo kalıbı — alokasyonsuz). struct Izo { ImVec2 merkez; float ex_x, ex_y, ey_x, ey_y, ez_x, ez_y; ImVec2 pr(float x, float y, float z) const { return {merkez.x + x * ex_x + y * ey_x + z * ez_x, merkez.y + x * ex_y + y * ey_y + z * ez_y}; } }; // Rol (hit-test): eksen okları + takım sembolü. enum class Rol { Yok, EksenX, EksenY, EksenZ, Takim }; bool daireIcinde(ImVec2 p, ImVec2 c, float r) { const float dx = p.x - c.x, dy = p.y - c.y; return dx * dx + dy * dy <= r * r; } // Ok ucu (koni) çiz: baş → uç yönünde küçük üçgen. void okUcu(ImDrawList* dl, ImVec2 bas, ImVec2 uc, ImU32 renk, float ka) { const float ang = std::atan2(uc.y - bas.y, uc.x - bas.x); dl->AddTriangleFilled(uc, {uc.x - ka * std::cos(ang - 0.5f), uc.y - ka * std::sin(ang - 0.5f)}, {uc.x - ka * std::cos(ang + 0.5f), uc.y - ka * std::sin(ang + 0.5f)}, renk); } // İnteraktif triad çizimi + rol tıklama dispatch. degisti: elle/yön değişince true. void triadCiz(CamSistemi& cam, CamOperasyon& op, ImVec2 boyut, bool& degisti) { ImGui::PushID((int)(op.kimlik * 32 + 5)); const ImVec2 p0 = ImGui::GetCursorScreenPos(); if (boyut.x < 40.0f) boyut.x = ImGui::GetContentRegionAvail().x; if (boyut.x < 40.0f) { ImGui::PopID(); return; } ImDrawList* dl = ImGui::GetWindowDrawList(); ImGuiIO& io = ImGui::GetIO(); const ImVec2 p1 = {p0.x + boyut.x, p0.y + boyut.y}; dl->AddRectFilled(p0, p1, REN_ZEMIN, 5.0f); dl->AddRect(p0, p1, REN_CERCEVE, 5.0f); ImGui::InvisibleButton("##triad", boyut); const bool hoverAlan = ImGui::IsItemHovered(); const ImVec2 fare = io.MousePos; const bool tik = ImGui::IsItemClicked(ImGuiMouseButton_Left); const float c = std::min(boyut.x, boyut.y) / 5.0f; // eksen uzunluk ölçeği Izo iz; iz.merkez = {p0.x + boyut.x * 0.5f, p0.y + boyut.y * 0.58f}; iz.ex_x = c; iz.ex_y = -c * 0.5f; // +X sağ-aşağı iz.ey_x = -c; iz.ey_y = -c * 0.5f; // +Y sol-aşağı iz.ez_x = 0.0f; iz.ez_y = -c * 0.9f; // +Z yukarı const ImVec2 o = iz.pr(0, 0, 0); // Eksen okları (birim uzunluk). struct Eksen { Rol rol; ImVec2 uc; ImU32 renk; const char* ad; }; const Eksen eksenler[3] = { {Rol::EksenX, iz.pr(1, 0, 0), REN_X, "X"}, {Rol::EksenY, iz.pr(0, 1, 0), REN_Y, "Y"}, {Rol::EksenZ, iz.pr(0, 0, 1), REN_Z, "Z"}, }; Rol hoverRol = Rol::Yok; for (const Eksen& e : eksenler) { dl->AddLine(o, e.uc, e.renk, 2.4f); okUcu(dl, o, e.uc, e.renk, 7.0f); dl->AddText({e.uc.x + 4, e.uc.y - 6}, e.renk, e.ad); if (hoverAlan && hoverRol == Rol::Yok && daireIcinde(fare, e.uc, 11.0f)) hoverRol = e.rol; } // Origin küre. dl->AddCircleFilled(o, 4.0f, REN_ORIGIN); // Mevcut takım yönündeki takım sembolü (koni + silindir), yön birim vektörü. Vec3d y = op.takimYonu.yon; if (y.uzunlukKare() < 1e-9) y = {0, 0, 1}; else y = y.birim(); const float L = 1.15f; // sembol uzunluğu (eksen birimi cinsinden) const ImVec2 tUc = iz.pr((float)y.x * L, (float)y.y * L, (float)y.z * L); const ImVec2 tOrta = iz.pr((float)y.x * L * 0.55f, (float)y.y * L * 0.55f, (float)y.z * L * 0.55f); // Silindir gövde (kalın çizgi) + koni uç (takım ucu origin'e -yön yönünde iner). dl->AddLine(tUc, tOrta, REN_TAKIM, 5.0f); okUcu(dl, tOrta, tUc, REN_TAKIM, 9.0f); const bool takimHover = hoverAlan && hoverRol == Rol::Yok && (daireIcinde(fare, tUc, 13.0f) || daireIcinde(fare, tOrta, 10.0f)); if (takimHover) hoverRol = Rol::Takim; char te[24]; std::snprintf(te, sizeof(te), "⊥ takım"); dl->AddText({tUc.x + 6, tUc.y + 2}, REN_TAKIM, te); // Hover vurgu halkası. if (hoverRol != Rol::Yok) dl->AddCircle(fare, 12.0f, REN_VURGU, 16, 2.0f); // Tıklama dispatch. auto gc = [] {}; if (tik && hoverRol != Rol::Yok) { switch (hoverRol) { case Rol::EksenX: op.takimYonu = {}; op.takimYonu.yon = {1, 0, 0}; op.takimYonu.kaynak = TakimYonu::Kaynak::Duzlem; degisti = true; break; case Rol::EksenY: op.takimYonu = {}; op.takimYonu.yon = {0, 1, 0}; op.takimYonu.kaynak = TakimYonu::Kaynak::Duzlem; degisti = true; break; case Rol::EksenZ: op.takimYonu = {}; op.takimYonu.yon = {0, 0, 1}; op.takimYonu.kaynak = TakimYonu::Kaynak::Duzlem; degisti = true; break; case Rol::Takim: // Takım sembolü tıkla → sahneden yüz seç (mevcut ToolAxis çekirdeği). cam.secim().baslat(op, CamSecimKip::ToolAxis, gc); break; default: break; } } ImGui::PopID(); } // Tek tool-axis penceresi. void takimEkseniPencereCiz(Cekirdek& cekirdek, Sahne& sahne, CamSistemi& cam, CamOperasyon& op) { (void)cekirdek; (void)sahne; using namespace fiko::ui; using u32 = fiko::u32; // ui::u32(ImVec4) ile tip cakismasini onler const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; bool& ustte = g_taPin[op.kimlik]; char baslik[192]; std::snprintf(baslik, sizeof(baslik), "🎯 Takım Ekseni · %s###ta_%u", op.ad.empty() ? cam::islemTipCatiaAdi(op.tip) : op.ad.c_str(), op.kimlik); bool acik = true; { Pencere p{baslik, &acik, {.boyut = {280, 0}, .pinDurum = &ustte}}; if (p) { TakimYonu& ty = op.takimYonu; const bool yuzeyBagli = ty.kaynak == TakimYonu::Kaynak::Yuzey; // ---- Üst rozet ---- if (yuzeyBagli) ImGui::TextColored(YESIL, "🔗 Yüzeye Bağlı (parametrik — Yüz #%u)", ty.yuzId); else ImGui::TextColored(SOLUK, "🔒 Sabit (%s)", cam::takimYonuKaynakAdi(ty.kaynak)); ImGui::TextColored(SOLUK, "⊥ (%.3f, %.3f, %.3f)", ty.yon.x, ty.yon.y, ty.yon.z); bool degisti = false; // ---- İnteraktif triad ---- ImGui::Spacing(); triadCiz(cam, op, {ImGui::GetContentRegionAvail().x, 190.0f}, degisti); ImGui::TextColored(SOLUK, "Ok tıkla → eksene sabitle · takım sembolü → sahneden yüz seç"); // ---- Sahneden seç (yüz normali) — mevcut ToolAxis çekirdeği ---- ImGui::SeparatorText("Sahneden"); { const bool aktif = cam.secim().aktifMi(op.kimlik, CamSecimKip::ToolAxis); if (aktif) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.08f, 0.42f, 0.55f, 1.0f}); if (ImGui::Button("🎯 Yüzeyden Takım Ekseni (yüz normali)", {-1, 0})) cam.secim().baslat(op, CamSecimKip::ToolAxis, [] {}); if (aktif) ImGui::PopStyleColor(); ImGui::SetItemTooltip( "Sahnede bir yüze tıkla → takım ekseni o yüzün normaline hizalanır (associatif)"); } // ---- IJK elle giriş (Custom; ref kopar) ---- ImGui::SeparatorText("Yön (IJK)"); { f64 ijk[3] = {ty.yon.x, ty.yon.y, ty.yon.z}; bool ijkDeg = false; ImGui::SetNextItemWidth(-1); if (ImGui::DragScalarN("##ijk", ImGuiDataType_Double, ijk, 3, 0.01f, nullptr, nullptr, "%.3f")) ijkDeg = true; if (ijkDeg) { Vec3d yeni{ijk[0], ijk[1], ijk[2]}; if (yeni.uzunlukKare() > 1e-9) { ty.yon = yeni.birim(); ty.kaynak = TakimYonu::Kaynak::Custom; ty.yuzId = 0; // elle giriş → associatif ref kopar degisti = true; } } if (ImGui::Button("⇅ Yönü Ters Çevir", {-1, 0})) { ty.yon = {-ty.yon.x, -ty.yon.y, -ty.yon.z}; if (ty.kaynak == TakimYonu::Kaynak::Z) ty.kaynak = TakimYonu::Kaynak::Custom; degisti = true; } } // ---- Sabit düzlem butonları ---- ImGui::SeparatorText("Sabit Eksen"); auto sabit = [&](const char* etiket, Vec3d yon) { if (ImGui::Button(etiket, {ImGui::GetContentRegionAvail().x / 3.0f - 4.0f, 0})) { ty = {}; ty.yon = yon; ty.kaynak = TakimYonu::Kaynak::Duzlem; degisti = true; } }; sabit("⊥ XY (Z)", {0, 0, 1}); ImGui::SameLine(); sabit("⊥ XZ (Y)", {0, 1, 0}); ImGui::SameLine(); sabit("⊥ YZ (X)", {1, 0, 0}); if (degisti) op.bayat = true; } } if (!acik) g_taAcik[op.kimlik] = false; } } // namespace void camTakimEkseniPencereAc(u32 opKimlik) { g_taAcik[opKimlik] = true; } void camTakimEkseniPencereleriCiz(Cekirdek& cekirdek, Sahne& sahne, cam::CamSistemi& cam) { for (auto it = g_taAcik.begin(); it != g_taAcik.end();) { if (!it->second) { it = g_taAcik.erase(it); continue; } CamOperasyon* op = cam.opBul(it->first); if (!op) { it = g_taAcik.erase(it); continue; } // op silindi → pencere de kapanır takimEkseniPencereCiz(cekirdek, sahne, cam, *op); ++it; } } } // namespace fiko