#include "cam_makro_onizleme.hpp" #include #include #include #include #include "fiko/cam/cam_islem.hpp" namespace fiko { namespace { using cam::CamMakro; using cam::MakroAdim; using cam::MakroAdimTip; using cam::MakroHareket; using cam::MakroMod; constexpr ImU32 REN_ZEMIN = IM_COL32(24, 26, 32, 255); constexpr ImU32 REN_CERCEVE = IM_COL32(70, 78, 92, 255); constexpr ImU32 REN_GRID = IM_COL32(50, 56, 66, 120); constexpr ImU32 REN_APP = IM_COL32(52, 211, 153, 255); // yaklaşma yeşil constexpr ImU32 REN_RET = IM_COL32(239, 68, 68, 255); // geri çekme kırmızı constexpr ImU32 REN_DUGUM = IM_COL32(235, 240, 248, 255); constexpr ImU32 REN_DUGUM_S = IM_COL32(255, 210, 77, 255); // seçili sarı constexpr ImU32 REN_METIN = IM_COL32(210, 218, 228, 255); constexpr ImU32 REN_ETIKET = IM_COL32(16, 18, 24, 220); constexpr float DEG = 3.14159265358979f / 180.0f; // Yol düğümü: yerel 3B nokta + hangi adım/segment (sürükle için). struct YolNokta { float x, y, z; int adim; }; // Segment tipi → örneklenmiş noktalar ekle (spec 3.1). yon: +1 retract, -1 approach. // bas = mevcut uç; ilerledikçe güncellenir. void segmentEkle(std::vector& yol, float& bx, float& by, float& bz, int yon, MakroAdimTip tip, float mesafe, float aci, float yaricap, float hedefZ, int adim) { switch (tip) { case MakroAdimTip::Eksenel: { bz += yon * mesafe; yol.push_back({bx, by, bz, adim}); break; } case MakroAdimTip::Teget: { bx += mesafe; yol.push_back({bx, by, bz, adim}); break; } case MakroAdimTip::Rampa: { bx += mesafe; bz += yon * std::tan(aci * DEG) * mesafe; yol.push_back({bx, by, bz, adim}); break; } case MakroAdimTip::Helis: { const float R = std::max(0.1f, yaricap); const float ta = std::max(1.0f * DEG, aci * DEG); const float L = std::max(0.1f, mesafe); const float pitch = 2.0f * 3.14159265f * R * std::tan(ta); const int tur = std::max(1, (int)std::ceil(L / std::max(0.1f, pitch))); const int N = 18 * tur; const float cx = bx - R, cy = by; // sarmal merkezi for (int i = 1; i <= N; ++i) { const float t = (float)i / (float)N; const float a = t * (float)tur * 2.0f * 3.14159265f; yol.push_back({cx + std::cos(a) * R, cy + std::sin(a) * R, bz + yon * L * t, adim}); } bx = cx + std::cos((float)tur * 2.0f * 3.14159265f) * R; by = cy + std::sin((float)tur * 2.0f * 3.14159265f) * R; bz += yon * L; break; } case MakroAdimTip::Duzleme: { bz += yon * std::abs(hedefZ); yol.push_back({bx, by, bz, adim}); break; } } } // Hazır preset → tek segment tip eşleme (MakroHareket → MakroAdimTip). MakroAdimTip presetTip(MakroHareket h) { switch (h) { case MakroHareket::Dikine: case MakroHareket::OnDelik: return MakroAdimTip::Eksenel; case MakroHareket::Rampa: return MakroAdimTip::Rampa; case MakroHareket::Helis: return MakroAdimTip::Helis; case MakroHareket::TegetCizgi: return MakroAdimTip::Teget; case MakroHareket::Yay: return MakroAdimTip::Rampa; // yay ≈ rampa görsel default: return MakroAdimTip::Eksenel; } } // Adım etiket metni (web adimEtiketMetin 609-616). void etiketMetin(char* buf, size_t n, MakroAdimTip tip, float mesafe, float aci, float yaricap, float hedefZ) { switch (tip) { case MakroAdimTip::Eksenel: std::snprintf(buf, n, "↧ %.1f", mesafe); break; case MakroAdimTip::Teget: std::snprintf(buf, n, "→ %.1f", mesafe); break; case MakroAdimTip::Rampa: std::snprintf(buf, n, "%.1f·%.0f°", mesafe, aci); break; case MakroAdimTip::Helis: std::snprintf(buf, n, "R%.1f↻%.1f", yaricap, mesafe); break; case MakroAdimTip::Duzleme: std::snprintf(buf, n, "Z%.1f", hedefZ); break; } } // Aktif makronun adım dizisini (yön/mesafe/açı) toplar — Hazır tek adım, Custom N adım. struct AdimGoruntu { MakroAdimTip tip; float mesafe, aci, yaricap, hedefZ; MakroAdim* ptr; }; } // namespace void makroOnizlemeCiz(CamMakro& m, bool ret, ImVec2 boyut, bool& degisti) { ImGui::PushID(&m); const int yon = ret ? +1 : -1; // Adım listesini kur. std::vector adimlar; if (m.mod == MakroMod::Hazir) { adimlar.push_back({presetTip(m.hareketTip), (float)m.mesafe, (float)m.aci, (float)m.yaricap, 0.0f, nullptr}); } else { for (MakroAdim& a : m.adimlar) adimlar.push_back({a.tip, (float)a.mesafe, (float)a.aci, (float)a.yaricap, (float)a.hedefZ, &a}); } 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("##makroprev", boyut); const bool hoverAlan = ImGui::IsItemHovered(); const ImVec2 fare = io.MousePos; // Yol noktalarını üret (LOCAL, origin engagement — dizi origin'de biter). std::vector yol; yol.push_back({0, 0, 0, -1}); float bx = 0, by = 0, bz = 0; for (int i = 0; i < (int)adimlar.size(); ++i) { const AdimGoruntu& a = adimlar[(size_t)i]; segmentEkle(yol, bx, by, bz, yon, a.tip, a.mesafe, a.aci, a.yaricap, a.hedefZ, i); } // Toplam delta → başlangıcı -toplam'a al (origin'de bitsin). const float tx = bx, ty = by, tz = bz; for (YolNokta& p : yol) { p.x -= tx; p.y -= ty; p.z -= tz; } // İzometrik yan görünüm ölçekle (bbox → widget). float minx = 1e9f, maxx = -1e9f, minz = 1e9f, maxz = -1e9f; for (const YolNokta& p : yol) { minx = std::min(minx, p.x); maxx = std::max(maxx, p.x); minz = std::min(minz, p.z); maxz = std::max(maxz, p.z); } const float extx = std::max(maxx - minx, 2.0f), extz = std::max(maxz - minz, 2.0f); const float ky = boyut.x / (extx + 8.0f), kz = boyut.y / (extz + 8.0f); const float k = std::min(ky, kz) * 0.8f; const ImVec2 org = {p0.x + boyut.x * 0.5f, p0.y + boyut.y * 0.5f}; const float cx = (minx + maxx) * 0.5f, cz = (minz + maxz) * 0.5f; auto pr = [&](float x, float z) -> ImVec2 { // Yan görünüm: ekran-x ← X, ekran-y ← -Z (yukarı Z). return {org.x + (x - cx) * k, org.y - (z - cz) * k}; }; // Zemin grid (yatay çizgiler). const ImVec2 z0 = pr(minx - 2, 0); dl->AddLine({p0.x + 4, z0.y}, {p1.x - 4, z0.y}, REN_GRID, 1.0f); for (int gx = -2; gx <= 2; ++gx) { const ImVec2 gp = pr(cx + gx * extx * 0.25f, minz); dl->AddLine({gp.x, gp.y}, {gp.x, gp.y - 6}, REN_GRID, 1.0f); } // Yol polyline (alokasyonsuz: doğrudan AddLine döngüsü). const ImU32 renk = ret ? REN_RET : REN_APP; for (size_t i = 1; i < yol.size(); ++i) dl->AddLine(pr(yol[i - 1].x, yol[i - 1].z), pr(yol[i].x, yol[i].z), renk, 2.4f); // Son segment yönünde ok koni. if (yol.size() >= 2) { const ImVec2 pa = pr(yol[yol.size() - 2].x, yol[yol.size() - 2].z); const ImVec2 pb = pr(yol.back().x, yol.back().z); const float ang = std::atan2(pb.y - pa.y, pb.x - pa.x); const float ka = 6.0f; dl->AddTriangleFilled(pb, {pb.x - ka * std::cos(ang - 0.5f), pb.y - ka * std::sin(ang - 0.5f)}, {pb.x - ka * std::cos(ang + 0.5f), pb.y - ka * std::sin(ang + 0.5f)}, renk); } // Düğümler (her adım sonu) + etiket + tık/sürükle. static int s_seciliAdim = -1; static void* s_dragMakro = nullptr; static int s_dragAdim = -1; int nodeHover = -1; // Her adımın son yol-noktasını bul (adim indeksi eşleşen son nokta). for (int ai = 0; ai < (int)adimlar.size(); ++ai) { int sonIdx = -1; for (int j = (int)yol.size() - 1; j >= 0; --j) if (yol[(size_t)j].adim == ai) { sonIdx = j; break; } if (sonIdx < 0) continue; const YolNokta& yn = yol[(size_t)sonIdx]; const ImVec2 sp = pr(yn.x, yn.z); const bool sec = s_seciliAdim == ai; const bool nh = hoverAlan && (std::abs(fare.x - sp.x) < 8 && std::abs(fare.y - sp.y) < 8); if (nh) nodeHover = ai; dl->AddCircleFilled(sp, sec ? 6.0f : 4.0f, sec ? REN_DUGUM_S : REN_DUGUM); // Etiket. const AdimGoruntu& a = adimlar[(size_t)ai]; char eb[32]; etiketMetin(eb, sizeof(eb), a.tip, a.mesafe, a.aci, a.yaricap, a.hedefZ); const ImVec2 ts = ImGui::CalcTextSize(eb); const ImVec2 ep = {sp.x + 8, sp.y - ts.y * 0.5f}; dl->AddRectFilled({ep.x - 2, ep.y - 1}, {ep.x + ts.x + 2, ep.y + ts.y + 1}, REN_ETIKET, 2.0f); dl->AddText(ep, REN_METIN, eb); } // Tık → adım seç. if (hoverAlan && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) s_seciliAdim = nodeHover; // Sürükle → seçili düğümün ölçüsü (mesafe) canlı değişir (spec 3.3). if (ImGui::IsItemActive() && s_seciliAdim >= 0 && s_seciliAdim < (int)adimlar.size()) { if (s_dragMakro != &m) { s_dragMakro = &m; s_dragAdim = s_seciliAdim; } const float dWorld = io.MouseDelta.x / std::max(0.5f, k); // yatay kayma → mm AdimGoruntu& a = adimlar[(size_t)s_seciliAdim]; if (a.ptr) { // Custom adım a.ptr->mesafe = std::max(0.1, a.ptr->mesafe + (f64)dWorld); if (std::abs(io.MouseDelta.x) > 0.01f) degisti = true; } else { // Hazır: tek mesafe m.mesafe = std::max(0.1, m.mesafe + (f64)dWorld); if (std::abs(io.MouseDelta.x) > 0.01f) degisti = true; } } else if (s_dragMakro == &m && !ImGui::IsItemActive()) { s_dragMakro = nullptr; s_dragAdim = -1; } ImGui::PopID(); (void)s_dragAdim; } } // namespace fiko