#pragma once // CATIA 3B Compass — navigasyon (köşe) + manipülatör (parça/yüzey). // Kırmızı base'i yüzeye bırak → o yüzeye hizalanır (konum + normal). Köşedeyken // seçili obje varsa köşe eksenlerinden sürükleyerek de taşınır. #include #include #include #include #include "fiko/render/orbit_kamera.hpp" #include "fiko/sahne/sahne.hpp" #include "imgui.h" namespace fiko { struct PusulaDurum { bool bagli = false; u32 govde = 0; bool baseSurukle = false; int tutamac = -1; // -1; 0-2 eksen; 3-5 düzlem; 6-8 yay // Yüzey çerçevesi (obje-yerel): yüzeye yapışınca dolar bool yuzeyKip = false; Vec3f yerelOrigin{}, yerelX{1, 0, 0}, yerelY{0, 1, 0}, yerelZ{0, 0, 1}; // Compass'ın dünya çerçevesi (serbest modda kaynak; bağlı+seçili modda objeden türetilir) Vec3f sOrigin{}, sX{1, 0, 0}, sY{0, 1, 0}, sZ{0, 0, 1}; // Sürükleme başlangıcı (dünya çerçevesi sabitlenir) Vec3f dragAnchor{}, dragAx[3]; bool dragObj = false; // sürükleme objeyi mi (true) yoksa yalnız compass'ı mı (false) Vec3d baslangicKonum; Quatd baslangicYonelim; Vec3f bSOrigin{}, bSX{}, bSY{}, bSZ{}; // serbest sürükleme başlangıç çerçevesi f32 t0 = 0; Vec3f baslangicHit{}; std::string bilgi; // Köşe compass'ı sürükle → görünüş döndür bool koseDondur = false; int koseDondurGor = -1; // basışta uç üstündeyse HizliGorunum değeri (kısa tık = snap) ImVec2 koseDondurBas{}; // Köşe compass'tan seçili obje taşıma int koseTutamac = -1; u32 koseGovde = 0; ImVec2 koseGrab{}; ImVec2 koseYon{}; f32 kosePixDunya = 1.0f; Vec3f koseWorldAx{}; Vec3d koseBaslaKonum; // Sürükleme commit (undo bağlama): bırakışta main tek DonusumIslem'e çevirir bool surukleTamam = false; // bu karede bir obje sürüklemesi bitti u32 surukleGovdeKimlik = 0; // hangi gövde Donusumd surukleEski; // sürükleme başındaki dönüşüm }; namespace pusula_ic { struct Isin { Vec3f orij, yon; }; // Işın: kaynak = near-düzlem noktası (perspektif VE ortografik için doğru; ortoda // ışınlar paraleldir, kaynak kamera noktası DEĞİL pikselin near noktasıdır). inline Isin imlecIsin(const Mat4f& invVP, f32 ndcX, f32 ndcY) { const Vec4f yH = invVP * Vec4f{ndcX, ndcY, 1.0f, 1.0f}; // reverse-Z: yakın düzlem = 1 const Vec4f uH = invVP * Vec4f{ndcX, ndcY, 0.0f, 1.0f}; // reverse-Z: uzak düzlem = 0 const Vec3f yakin = yH.xyz() * (1.0f / yH.w); const Vec3f uzak = uH.xyz() * (1.0f / uH.w); return {yakin, (uzak - yakin).birim()}; } inline f32 isinEksenParam(const Isin& r, Vec3f merkez, Vec3f eksen) { const Vec3f w0 = r.orij - merkez; const f32 b = r.yon.nokta(eksen); const f32 d = r.yon.nokta(w0); const f32 e = eksen.nokta(w0); const f32 payda = 1.0f - b * b; if (std::abs(payda) < 1e-5f) return 0.0f; return (e - b * d) / payda; } inline bool isinDuzlem(const Isin& r, Vec3f p0, Vec3f n, Vec3f& hit) { const f32 denom = r.yon.nokta(n); if (std::abs(denom) < 1e-6f) return false; const f32 t = (p0 - r.orij).nokta(n) / denom; if (t < 0) return false; hit = r.orij + r.yon * t; return true; } inline ImVec2 projekte(const Mat4f& vp, Vec3f p, f32 mx, f32 my, f32 w, f32 h) { const Vec4f c = vp * Vec4f{p, 1.0f}; const f32 iw = 1.0f / (std::abs(c.w) < 1e-6f ? 1e-6f : c.w); return ImVec2(mx + (c.x * iw * 0.5f + 0.5f) * w, my + (c.y * iw * 0.5f + 0.5f) * h); } inline f32 uzunlukEkr(ImVec2 a, ImVec2 b) { return std::sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } inline f32 manhattan(ImVec2 a, ImVec2 b) { return std::abs(a.x - b.x) + std::abs(a.y - b.y); } inline f32 segmentUzaklik(ImVec2 p, ImVec2 a, ImVec2 b) { const ImVec2 ab{b.x - a.x, b.y - a.y}; const ImVec2 ap{p.x - a.x, p.y - a.y}; f32 t = (ap.x * ab.x + ap.y * ab.y) / (ab.x * ab.x + ab.y * ab.y + 1e-6f); t = std::clamp(t, 0.0f, 1.0f); return uzunlukEkr(p, ImVec2{a.x + ab.x * t, a.y + ab.y * t}); } inline f32 isaret(ImVec2 a, ImVec2 b, ImVec2 c) { return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y); } inline bool ucgenIcinde(ImVec2 p, ImVec2 a, ImVec2 b, ImVec2 c) { const f32 d1 = isaret(p, a, b), d2 = isaret(p, b, c), d3 = isaret(p, c, a); return !(((d1 < 0) || (d2 < 0) || (d3 < 0)) && ((d1 > 0) || (d2 > 0) || (d3 > 0))); } inline bool quadIcinde(ImVec2 p, ImVec2 a, ImVec2 b, ImVec2 c, ImVec2 d) { return ucgenIcinde(p, a, b, c) || ucgenIcinde(p, a, c, d); } inline ImU32 tersRenk(ImU32 c) { return IM_COL32(255 - (int)((c >> IM_COL32_R_SHIFT) & 0xFF), 255 - (int)((c >> IM_COL32_G_SHIFT) & 0xFF), 255 - (int)((c >> IM_COL32_B_SHIFT) & 0xFF), (int)((c >> IM_COL32_A_SHIFT) & 0xFF)); } inline void metinStrok(ImDrawList* dl, ImVec2 p, ImU32 dolgu, ImU32 strok, const char* s, f32 k = 1.5f) { for (int a = 0; a < 8; ++a) { // font ÇEVRESİNE düzgün kontur (8 yön halka) const f32 t = (f32)a / 8.0f * 6.2831853f; dl->AddText(ImVec2(p.x + std::cos(t) * k, p.y + std::sin(t) * k), strok, s); } dl->AddText(p, dolgu, s); } inline Vec3f dunyaYon(const Donusumd& t, Vec3f y) { const Vec3d w = t.yonelim.dondur({(f64)y.x, (f64)y.y, (f64)y.z}); return Vec3f{(f32)w.x, (f32)w.y, (f32)w.z}.birim(); } inline Vec3f dunyaNokta(const Donusumd& t, Vec3f y) { const Vec3d w = t.noktaUygula({(f64)y.x, (f64)y.y, (f64)y.z}); return {(f32)w.x, (f32)w.y, (f32)w.z}; } } // namespace pusula_ic // Compass'ı bir yüzeye hizalayarak yapıştırır (nokta + normal, obje-yerel çerçeve) inline void pusulaYuzeyeYapistir(PusulaDurum& P, Sahne& sahne, u32 govde, Vec3f dnokta, Vec3f dnormal) { Dugum* d = sahne.bul(govde); if (!d) return; const Donusumd ters = d->donusum.ters(); const Vec3d lo = ters.noktaUygula({(f64)dnokta.x, (f64)dnokta.y, (f64)dnokta.z}); const Vec3d ln = d->donusum.yonelim.eslenik().dondur( {(f64)dnormal.x, (f64)dnormal.y, (f64)dnormal.z}); Vec3f lz = Vec3f{(f32)ln.x, (f32)ln.y, (f32)ln.z}.birim(); Vec3f ref = (std::abs(lz.z) < 0.9f) ? Vec3f{0, 0, 1} : Vec3f{1, 0, 0}; const Vec3f lx = ref.capraz(lz).birim(); const Vec3f ly = lz.capraz(lx); P.bagli = true; P.yuzeyKip = true; P.govde = govde; P.tutamac = -1; P.yerelOrigin = {(f32)lo.x, (f32)lo.y, (f32)lo.z}; P.yerelX = lx; P.yerelY = ly; P.yerelZ = lz; sahne.sec({govde, 0}, false); } // Compass'ı obje merkezine, dünya eksenli yapıştırır (yüzey yok) inline void pusulaObjeyeYapistir(PusulaDurum& P, Sahne& sahne, u32 govde) { P.bagli = true; P.yuzeyKip = false; P.govde = govde; P.tutamac = -1; sahne.sec({govde, 0}, false); } inline void pusulaCizVeIsle(PusulaDurum& P, Sahne& sahne, OrbitKamera& kamera, ImDrawList* dl, ImGuiIO& io, bool vpHover, f32 mx, f32 my, f32 vw, f32 vh, f32 enBoy, bool& handleUstunde, bool objTasiKapali = false) { using namespace pusula_ic; handleUstunde = false; P.bilgi.clear(); const Mat4f vp = kamera.izdusum(enBoy) * kamera.gorunum(); const Mat4f invVP = vp.ters(); const ImVec2 fp = io.MousePos; const f32 ndcX = 2.0f * (fp.x - mx) / vw - 1.0f; const f32 ndcY = 2.0f * (fp.y - my) / vh - 1.0f; const Isin isin = imlecIsin(invVP, ndcX, ndcY); const ImU32 renkler[3] = {IM_COL32(232, 86, 86, 255), IM_COL32(96, 200, 96, 255), IM_COL32(92, 146, 240, 255)}; const Vec3f dunyaEks[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; // ---------------- KÖŞE MOD ---------------- if (!P.bagli) { const f32 cemberR = 58.0f; // dış çember: SABİT const f32 R = 50.0f; // eksen boyu (çemberin içinde kalır) const ImVec2 mrk(mx + vw - cemberR - 12.0f, my + cemberR + 12.0f); const Mat4f gv = kamera.gorunum(); const HizliGorunum pozGor[3] = {HizliGorunum::Sag, HizliGorunum::Arka, HizliGorunum::Ust}; const HizliGorunum negGor[3] = {HizliGorunum::Sol, HizliGorunum::On, HizliGorunum::Alt}; dl->AddCircleFilled(mrk, cemberR, IM_COL32(18, 22, 30, 150), 48); dl->AddCircle(mrk, cemberR, IM_COL32(90, 100, 120, 90), 48, 1.0f); Vec3f cam[3]; for (int i = 0; i < 3; ++i) cam[i] = gv.yonDonustur(dunyaEks[i]); auto ekr = [&](Vec3f c, f32 o) { return ImVec2(mrk.x + c.x * R * o, mrk.y - c.y * R * o); }; ImVec2 scAx[3]; for (int i = 0; i < 3; ++i) scAx[i] = ekr(cam[i], 1.0f); for (int i = 0; i < 3; ++i) { const int a = (i + 1) % 3, b = (i + 2) % 3; const ImU32 rc = (renkler[i] & 0x00FFFFFF) | 0x66000000; ImVec2 onceki{}; for (int s = 0; s <= 14; ++s) { const f32 ang = (f32)s / 14.0f * 1.5707963f; const Vec3f dir = dunyaEks[a] * std::cos(ang) + dunyaEks[b] * std::sin(ang); const ImVec2 ps = ekr(gv.yonDonustur(dir), 0.74f); if (s > 0) dl->AddLine(onceki, ps, rc, 1.6f); onceki = ps; } } // Uçları derinliğe göre çiz + hover struct Uc { ImVec2 p; f32 d; int i; bool poz; }; Uc ucs[6]; for (int i = 0; i < 3; ++i) { ucs[2 * i] = {scAx[i], cam[i].z, i, true}; ucs[2 * i + 1] = {ekr(cam[i] * -1.0f, 1.0f), -cam[i].z, i, false}; } std::sort(ucs, ucs + 6, [](const Uc& a, const Uc& b) { return a.d < b.d; }); int tipI = -1; bool tipPoz = false; const char* etk[3] = {"X", "Y", "Z"}; for (int k = 0; k < 6; ++k) { const Uc& u = ucs[k]; if (u.poz) dl->AddLine(mrk, u.p, renkler[u.i], 3.0f); // Harf/nokta merkezi = tıklama hedefi. Poz uçta harf uçtan 14px dışarıda. const ImVec2 yon2{u.p.x - mrk.x, u.p.y - mrk.y}; const f32 uz = std::sqrt(yon2.x * yon2.x + yon2.y * yon2.y) + 1e-3f; const ImVec2 hp = u.poz ? ImVec2{u.p.x + yon2.x / uz * 14.0f, u.p.y + yon2.y / uz * 14.0f} : u.p; const f32 yari = u.poz ? 11.0f : 6.0f; const bool ust = vpHover && manhattan(fp, hp) < yari + 6.0f; if (ust) { tipI = u.i; tipPoz = u.poz; handleUstunde = true; } if (u.poz) { // yuvarlak yok → yalnız ters renkte kontarlı harf const ImVec2 ts = ImGui::CalcTextSize(etk[u.i]); metinStrok(dl, ImVec2(hp.x - ts.x * 0.5f, hp.y - ts.y * 0.5f), renkler[u.i], tersRenk(renkler[u.i]), etk[u.i], ust ? 2.6f : 2.0f); } else { dl->AddCircleFilled(u.p, ust ? yari + 2.0f : yari, (renkler[u.i] & 0x00FFFFFF) | 0x88000000, 20); } } // Seçili obje varsa: eksen ÇİZGİSİNDEN (uç değil) sürükle → objeyi o eksende taşı const auto secG = sahne.seciliGovdeler(); int cizgiI = -1; if (P.koseTutamac < 0 && !secG.empty() && tipI < 0 && vpHover) { for (int i = 0; i < 3; ++i) if (segmentUzaklik(fp, mrk, scAx[i]) < 7.0f) { cizgiI = i; handleUstunde = true; break; } } // Kırmızı base (kolay yakalanır) const f32 baseYari = 5.0f; const bool baseUst = vpHover && std::abs(fp.x - mrk.x) < baseYari + 7.0f && std::abs(fp.y - mrk.y) < baseYari + 7.0f; if (baseUst || P.baseSurukle) handleUstunde = true; dl->AddRectFilled(ImVec2(mrk.x - baseYari, mrk.y - baseYari), ImVec2(mrk.x + baseYari, mrk.y + baseYari), IM_COL32(235, 60, 60, 255), 2.0f); dl->AddRect(ImVec2(mrk.x - baseYari, mrk.y - baseYari), ImVec2(mrk.x + baseYari, mrk.y + baseYari), IM_COL32(255, 255, 255, 200), 2.0f, 0, 1.5f); // Çember içi VEYA çember dışına taşan bir harf/uç üstünde → döndür/snap tetiklenir const bool cemberUst = vpHover && (uzunlukEkr(fp, mrk) < cemberR || tipI >= 0); if (cemberUst) handleUstunde = true; // Köşe compass'ı sürükle → görünüş serbest döndür (kısa tık + uç = snap) if (P.koseDondur) { handleUstunde = true; kamera.dondur(io.MouseDelta.x, io.MouseDelta.y); if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { if (P.koseDondurGor >= 0 && manhattan(fp, P.koseDondurBas) < 5.0f) kamera.gorunumeGit((HizliGorunum)P.koseDondurGor); P.koseDondur = false; } } // Etkileşim başlat if (P.koseTutamac < 0 && !P.baseSurukle && !P.koseDondur && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (baseUst) { P.baseSurukle = true; } else if (cizgiI >= 0) { P.koseTutamac = cizgiI; P.koseGovde = secG.back(); P.koseGrab = fp; const Vec3f yon2 = Vec3f{scAx[cizgiI].x - mrk.x, scAx[cizgiI].y - mrk.y, 0}.birim(); P.koseYon = {yon2.x, yon2.y}; P.koseWorldAx = dunyaEks[cizgiI]; if (Dugum* dd = sahne.bul(P.koseGovde)) { P.koseBaslaKonum = dd->donusum.konum; P.surukleEski = dd->donusum; P.surukleGovdeKimlik = P.koseGovde; const Vec3f o0{(f32)dd->donusum.konum.x, (f32)dd->donusum.konum.y, (f32)dd->donusum.konum.z}; const ImVec2 s0 = projekte(vp, o0, mx, my, vw, vh); const ImVec2 s1 = projekte(vp, o0 + dunyaEks[cizgiI], mx, my, vw, vh); P.kosePixDunya = std::max(uzunlukEkr(s0, s1), 1e-3f); } } else if (cemberUst) { // Compass'a bas + sürükle → görünüş döndür; sürüklemeden bırak + uç = snap P.koseDondur = true; P.koseDondurBas = fp; P.koseDondurGor = (tipI >= 0) ? (int)(tipPoz ? pozGor[tipI] : negGor[tipI]) : -1; } } // Köşe eksen sürükle → seçili objeyi taşı if (P.koseTutamac >= 0) { handleUstunde = true; if (Dugum* dd = sahne.bul(P.koseGovde); dd && io.MouseDown[ImGuiMouseButton_Left]) { const f32 dpix = (fp.x - P.koseGrab.x) * P.koseYon.x + (fp.y - P.koseGrab.y) * P.koseYon.y; const f32 wdelta = dpix / P.kosePixDunya; dd->donusum.konum = {P.koseBaslaKonum.x + (f64)(P.koseWorldAx.x * wdelta), P.koseBaslaKonum.y + (f64)(P.koseWorldAx.y * wdelta), P.koseBaslaKonum.z + (f64)(P.koseWorldAx.z * wdelta)}; char bb[32]; const char* ad[3] = {"X", "Y", "Z"}; std::snprintf(bb, sizeof(bb), "%s: %.2f mm", ad[P.koseTutamac], wdelta); dl->AddText(ImVec2(fp.x + 12, fp.y - 6), IM_COL32(255, 220, 130, 255), bb); } if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { P.koseTutamac = -1; P.surukleTamam = true; } } // Base sürükle → yüzeye/objeye yapıştır if (P.baseSurukle) { dl->AddLine(mrk, fp, IM_COL32(235, 60, 60, 220), 2.0f); dl->AddText(ImVec2(fp.x + 12, fp.y - 6), IM_COL32(255, 210, 120, 255), "yüzeye bırak"); if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { P.baseSurukle = false; Sahne::IsinVurus vur; if (sahne.isinVur(isin.orij, isin.yon, vur)) pusulaYuzeyeYapistir(P, sahne, vur.govde, vur.nokta, vur.normal); else if (sahne.vurgu.govde != 0) pusulaObjeyeYapistir(P, sahne, sahne.vurgu.govde); } } return; } // ---------------- BAĞLI MANİPÜLATÖR ---------------- Dugum* d = sahne.bul(P.govde); if (!d) P.govde = 0; // obje silinmiş → serbest compass // Seçili bağlı obje varsa objeyi taşır; yoksa yalnız compass'ı taşır (serbest). // objTasiKapali → birleşik transform gizmosu bu gövdeyi yönetiyor; compass obje-taşımayı ona // bırakır (yalnız navigasyon compass'ı kalır) → redundant çift-manipülatör yok (menü/gizmo min). const bool objMod = d && sahne.govdeSeciliMi(P.govde) && !objTasiKapali; if (objMod) { if (P.yuzeyKip) { P.sOrigin = dunyaNokta(d->donusum, P.yerelOrigin); P.sX = dunyaYon(d->donusum, P.yerelX); P.sY = dunyaYon(d->donusum, P.yerelY); P.sZ = dunyaYon(d->donusum, P.yerelZ); } else { P.sOrigin = {(f32)d->donusum.konum.x, (f32)d->donusum.konum.y, (f32)d->donusum.konum.z}; P.sX = dunyaEks[0]; P.sY = dunyaEks[1]; P.sZ = dunyaEks[2]; } } // (serbest modda sOrigin/sX/Y/Z korunur → yalnız compass hareket eder) const Vec3f anchor = P.sOrigin; Vec3f ax[3] = {P.sX, P.sY, P.sZ}; const f32 L = std::max(kamera.mesafe() * 0.14f, 0.05f); const f32 Lp = L * 0.36f; const ImVec2 c0 = projekte(vp, anchor, mx, my, vw, vh); ImVec2 eksUc[3], plnA[3], plnAB[3], plnB[3]; for (int i = 0; i < 3; ++i) { eksUc[i] = projekte(vp, anchor + ax[i] * L, mx, my, vw, vh); const int a = (i + 1) % 3, b = (i + 2) % 3; plnA[i] = projekte(vp, anchor + ax[a] * Lp, mx, my, vw, vh); plnAB[i] = projekte(vp, anchor + (ax[a] + ax[b]) * Lp, mx, my, vw, vh); plnB[i] = projekte(vp, anchor + ax[b] * Lp, mx, my, vw, vh); } const bool baseUst = vpHover && std::abs(fp.x - c0.x) < 13.0f && std::abs(fp.y - c0.y) < 13.0f; int aday = -1; if (P.tutamac < 0 && !P.baseSurukle && vpHover && !baseUst) { for (int i = 0; i < 3; ++i) if (quadIcinde(fp, c0, plnA[i], plnAB[i], plnB[i])) { aday = 3 + i; break; } if (aday < 0) { f32 en = 9.0f; for (int i = 0; i < 3; ++i) { const f32 u = segmentUzaklik(fp, c0, eksUc[i]); if (u < en) { en = u; aday = i; } } } if (aday < 0) { for (int i = 0; i < 3; ++i) { const int a = (i + 1) % 3, b = (i + 2) % 3; f32 enY = 8.0f; bool yakin = false; ImVec2 onceki{}; for (int s = 0; s <= 12; ++s) { const f32 ang = (f32)s / 12.0f * 1.5707963f; const Vec3f pw = anchor + (ax[a] * std::cos(ang) + ax[b] * std::sin(ang)) * (L * 0.82f); const ImVec2 ps = projekte(vp, pw, mx, my, vw, vh); if (s > 0) { const f32 u = segmentUzaklik(fp, onceki, ps); if (u < enY) { enY = u; yakin = true; } } onceki = ps; } if (yakin) { aday = 6 + i; break; } } } } if (aday >= 0 || P.tutamac >= 0 || baseUst || P.baseSurukle) handleUstunde = true; if (P.tutamac < 0 && !P.baseSurukle && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (baseUst) { P.baseSurukle = true; } else if (aday >= 0) { P.tutamac = aday; P.dragObj = objMod; P.dragAnchor = anchor; P.dragAx[0] = ax[0]; P.dragAx[1] = ax[1]; P.dragAx[2] = ax[2]; if (objMod) { P.baslangicKonum = d->donusum.konum; P.baslangicYonelim = d->donusum.yonelim; P.surukleEski = d->donusum; P.surukleGovdeKimlik = P.govde; } else { P.bSOrigin = P.sOrigin; P.bSX = P.sX; P.bSY = P.sY; P.bSZ = P.sZ; } if (aday < 3) { P.t0 = isinEksenParam(isin, anchor, ax[aday]); } else if (aday < 6) { const int i = aday - 3, a = (i + 1) % 3, b = (i + 2) % 3; isinDuzlem(isin, anchor, ax[a].capraz(ax[b]), P.baslangicHit); } else { isinDuzlem(isin, anchor, ax[aday - 6], P.baslangicHit); } } } if (P.baseSurukle) { dl->AddLine(c0, fp, IM_COL32(235, 60, 60, 220), 2.0f); dl->AddText(ImVec2(fp.x + 12, fp.y - 6), IM_COL32(255, 210, 120, 255), "yüzeye taşı / boşluğa bırak"); if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { P.baseSurukle = false; Sahne::IsinVurus vur; if (sahne.isinVur(isin.orij, isin.yon, vur)) pusulaYuzeyeYapistir(P, sahne, vur.govde, vur.nokta, vur.normal); else { P.bagli = false; P.tutamac = -1; return; } } } // Manipülasyon — dragObj ? objeyi : yalnız compass'ı taşır if (P.tutamac >= 0 && io.MouseDown[ImGuiMouseButton_Left]) { const Vec3f A = P.dragAnchor; const char* prefix = P.dragObj ? "" : "compass "; if (P.tutamac < 3) { const int i = P.tutamac; const f32 t = isinEksenParam(isin, A, P.dragAx[i]); const f32 delta = t - P.t0; if (P.dragObj && d) { d->donusum.konum = {P.baslangicKonum.x + (f64)(P.dragAx[i].x * delta), P.baslangicKonum.y + (f64)(P.dragAx[i].y * delta), P.baslangicKonum.z + (f64)(P.dragAx[i].z * delta)}; } else { P.sOrigin = P.bSOrigin + P.dragAx[i] * delta; } char b[40]; const char* ad[3] = {"U", "V", "W"}; std::snprintf(b, sizeof(b), "%s%s: %.2f mm", prefix, ad[i], delta); P.bilgi = b; } else if (P.tutamac < 6) { const int i = P.tutamac - 3, a = (i + 1) % 3, b2 = (i + 2) % 3; Vec3f hit; if (isinDuzlem(isin, A, P.dragAx[a].capraz(P.dragAx[b2]), hit)) { const Vec3f delta = hit - P.baslangicHit; if (P.dragObj && d) { d->donusum.konum = {P.baslangicKonum.x + (f64)delta.x, P.baslangicKonum.y + (f64)delta.y, P.baslangicKonum.z + (f64)delta.z}; } else { P.sOrigin = P.bSOrigin + delta; } P.bilgi = P.dragObj ? "düzlemde taşı" : "compass düzlemde taşı"; } } else { const int i = P.tutamac - 6; Vec3f hit; if (isinDuzlem(isin, A, P.dragAx[i], hit)) { const Vec3f v0 = P.baslangicHit - A, v1 = hit - A; const f32 aci = std::atan2(v0.capraz(v1).nokta(P.dragAx[i]), v0.nokta(v1)); if (P.dragObj && d) { const Vec3d nD{(f64)P.dragAx[i].x, (f64)P.dragAx[i].y, (f64)P.dragAx[i].z}; const Quatd q = Quatd::eksenAci(nD, (f64)aci); d->donusum.yonelim = (q * P.baslangicYonelim).birim(); const Vec3d rel{P.baslangicKonum.x - (f64)A.x, P.baslangicKonum.y - (f64)A.y, P.baslangicKonum.z - (f64)A.z}; const Vec3d rd = q.dondur(rel); d->donusum.konum = {(f64)A.x + rd.x, (f64)A.y + rd.y, (f64)A.z + rd.z}; } else { const Quatf q = Quatf::eksenAci(P.dragAx[i], aci); P.sX = q.dondur(P.bSX); P.sY = q.dondur(P.bSY); P.sZ = q.dondur(P.bSZ); } char b[40]; const char* ad[3] = {"Ru", "Rv", "Rw"}; std::snprintf(b, sizeof(b), "%s%s: %.1f°", prefix, ad[i], aci * 57.2958f); P.bilgi = b; } } } if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { if (P.tutamac >= 0 && P.dragObj) P.surukleTamam = true; P.tutamac = -1; } // ---- Çizim ---- for (int i = 0; i < 3; ++i) { // yaylar const int a = (i + 1) % 3, b = (i + 2) % 3; const bool akt = (P.tutamac == 6 + i) || (P.tutamac < 0 && aday == 6 + i); ImVec2 onceki{}; for (int s = 0; s <= 16; ++s) { const f32 ang = (f32)s / 16.0f * 1.5707963f; const Vec3f pw = anchor + (ax[a] * std::cos(ang) + ax[b] * std::sin(ang)) * (L * 0.82f); const ImVec2 ps = projekte(vp, pw, mx, my, vw, vh); if (s > 0) dl->AddLine(onceki, ps, renkler[i], akt ? 3.5f : 2.0f); onceki = ps; } } for (int i = 0; i < 3; ++i) { // düzlemler const int a = (i + 1) % 3; const bool akt = (P.tutamac == 3 + i) || (P.tutamac < 0 && aday == 3 + i); const ImU32 dr = (renkler[a] & 0x00FFFFFF) | (akt ? 0xAA000000 : 0x55000000); dl->AddQuadFilled(c0, plnA[i], plnAB[i], plnB[i], dr); dl->AddQuad(c0, plnA[i], plnAB[i], plnB[i], (renkler[a] & 0x00FFFFFF) | 0xCC000000, akt ? 2.0f : 1.0f); } const char* ekAd[3] = {"U", "V", "W"}; for (int i = 0; i < 3; ++i) { // eksenler const bool akt = (P.tutamac == i) || (P.tutamac < 0 && aday == i); dl->AddLine(c0, eksUc[i], renkler[i], akt ? 4.0f : 2.5f); dl->AddCircleFilled(eksUc[i], akt ? 6.0f : 4.5f, renkler[i], 16); dl->AddText(ImVec2(eksUc[i].x + 4, eksUc[i].y - 6), renkler[i], ekAd[i]); } dl->AddRectFilled(ImVec2(c0.x - 6, c0.y - 6), ImVec2(c0.x + 6, c0.y + 6), IM_COL32(235, 60, 60, 255), 2.0f); dl->AddRect(ImVec2(c0.x - 6, c0.y - 6), ImVec2(c0.x + 6, c0.y + 6), IM_COL32(255, 255, 255, 210), 2.0f, 0, 1.5f); if (!P.bilgi.empty()) dl->AddText(ImVec2(c0.x + 12, c0.y + 10), IM_COL32(255, 220, 130, 255), P.bilgi.c_str()); } } // namespace fiko