#pragma once // DM Sketch İt/Çek jesti (Plasticity tarzı): SEÇİLİ sketch profilini tutup düzlem normali // boyunca sürükle → dışarı çek = Pad (fuse), içeri it = Cep/oy (cut) — kaynak gövdeye uygulanır. // push_pull.hpp'nin sketch karşılığı; butonsuz: seçili sketch'te merkez oku belirir, sürükle → // canlı önizleme, bırak → sahne.sketchKatiUygula + undo (DuzenleIslem). Kaynak gövde yoksa uyarır. #include #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "dm_tutamac_olay.hpp" #include "fiko/render/orbit_kamera.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/parca/part_design_sistemi.hpp" // parametrik Pad/Pocket feature #include "fiko/sahne/sahne_islem.hpp" #include "fiko/ui/bilesen_ek.hpp" // ui::toastGoster #include "dogrudan_ayar.hpp" #include "gizmo_gorsel.hpp" #include "imgui.h" namespace fiko { struct SketchItCekDurum { bool aktif = false; // DM workbench'te mi bool surukluyor = false; // sürükleme sürüyor Varlik sketch = VARLIK_YOK; u32 kaynakGovde = 0; // Pad/Cep hedefi (0 → yok, uyar) Vec3f merkezD{}, normalD{}; // profil centroid + düzlem normali (dünya) f32 mesafe = 0; // canlı sürükleme (mm; + dışa Pad, − içe Cep) std::vector> poliler; // profil önizleme polylineları (dünya) char tipBuf[24] = ""; // sürüklerken yazılan sayı (drag override) DugumPusula eski; // undo snapshot (kaynak gövde) }; // ustunde: ok üstünde/sürüklemede → kamera/seçim jestleri bastırılır (OR'lanır). inline void sketchItCekCizVeIsle(SketchItCekDurum& s, Sahne& sahne, Cekirdek& cekirdek, parca::PartDesignSistemi& partD, OrbitKamera& kamera, ImDrawList* dl, ImGuiIO& io, bool vpHover, f32 mx, f32 my, f32 vw, f32 vh, f32 enBoy, bool& ustunde) { (void)cekirdek; // artık feature yolu (partD) kullanılıyor; imza push_pull ile paralel kalsın ustunde = false; if (!s.aktif) return; const Mat4f vp = kamera.izdusum(enBoy) * kamera.gorunum(); const auto proj = [&](const Vec3f& p, ImVec2& o) -> bool { const Vec4f h = vp * Vec4f{p, 1.0f}; if (h.w <= 1e-4f) return false; o = ImVec2(mx + (h.x / h.w * 0.5f + 0.5f) * vw, my + (h.y / h.w * 0.5f + 0.5f) * vh); return true; }; const auto okBasi = [&](ImVec2 taban, ImVec2 uc, ImU32 renk) { f32 dx = uc.x - taban.x, dy = uc.y - taban.y; const f32 L = std::sqrt(dx * dx + dy * dy); if (L < 1.0f) return; dx /= L; dy /= L; const f32 tb = dogrudanAyar().tutamacBoy; const f32 u = 9.0f * tb, w2 = 3.5f * tb; dl->AddTriangleFilled(uc, ImVec2(uc.x - dx * u - dy * w2, uc.y - dy * u + dx * w2), ImVec2(uc.x - dx * u + dy * w2, uc.y - dy * u - dx * w2), renk); }; if (!s.surukluyor) { // ---- SEÇİLİ sketch profilinde merkez oku (düzlem normali) ---- const Varlik sk = sahne.seciliSketch(); if (sk == VARLIK_YOK) return; const Sahne::SketchItCekBilgi b = sahne.sketchItCekBilgi(sk); if (!b.gecerli) return; const Vec3f merkez{(f32)b.merkez.x, (f32)b.merkez.y, (f32)b.merkez.z}; const Vec3f normal = Vec3f{(f32)b.normal.x, (f32)b.normal.y, (f32)b.normal.z}.birim(); const f32 L = std::max(kamera.mesafe() * dogrudanAyar().okBoyOran, 0.03f); ImVec2 s0, s1; const bool okVar = proj(merkez, s0) && proj(merkez + normal * L, s1); // Profil konturu (soluk cyan) — hangi sketch olduğu belli olsun. for (const auto& lp : b.poliler) { const int n = (int)lp.size(); ImVec2 onceki{}; bool var = false; ImVec2 ilk{}; for (int i = 0; i < n; ++i) { ImVec2 p; if (proj(lp[i], p)) { if (var) dl->AddLine(onceki, p, IM_COL32(120, 220, 255, 130), 1.4f); else ilk = p; onceki = p; var = true; } } if (var) dl->AddLine(onceki, ilk, IM_COL32(120, 220, 255, 130), 1.4f); // kapat } bool okYakin = false; if (okVar) { const f32 dx = s1.x - s0.x, dy = s1.y - s0.y, L2 = dx * dx + dy * dy; f32 t = L2 > 1e-6f ? ((io.MousePos.x - s0.x) * dx + (io.MousePos.y - s0.y) * dy) / L2 : 0.0f; t = t < 0.0f ? 0.0f : (t > 1.0f ? 1.0f : t); const f32 qx = s0.x + t * dx - io.MousePos.x, qy = s0.y + t * dy - io.MousePos.y; okYakin = vpHover && (qx * qx + qy * qy) <= 14.0f * 14.0f; } ustunde = okYakin && ImGui::IsMouseDown(ImGuiMouseButton_Left); if (okVar) { const ImU32 renk = okYakin ? IM_COL32(150, 235, 255, 255) : IM_COL32(120, 220, 255, 200); const bool glow = okYakin && dogrudanAyar().glowAcik; if (glow) gizmo::glowCizgi(dl, s0, s1, renk, 3.2f); else dl->AddLine(s0, s1, renk, okYakin ? 3.2f : 2.6f); okBasi(s0, s1, renk); const f32 dr = (okYakin ? 4.0f : 3.0f) * dogrudanAyar().tutamacBoy; dl->AddCircleFilled(s0, dr, renk); } if (okYakin && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { s.surukluyor = true; s.sketch = sk; s.kaynakGovde = b.kaynakGovde; s.mesafe = 0; s.tipBuf[0] = 0; s.merkezD = merkez; s.normalD = normal; s.poliler = b.poliler; s.eski = b.kaynakGovde ? sahne.anlik(b.kaynakGovde) : DugumPusula{}; } return; } // ---- Sürükleme: canlı Pad/Cep önizlemesi ---- ustunde = true; ImVec2 c0, c1; if (proj(s.merkezD, c0) && proj(s.merkezD + s.normalD, c1)) { const f32 vx = c1.x - c0.x, vy = c1.y - c0.y, L2 = vx * vx + vy * vy; if (L2 > 1e-6f) s.mesafe += (io.MouseDelta.x * vx + io.MouseDelta.y * vy) / L2; } // Sürüklerken sayı yaz → hassas mesafe (drag override; CATIA/Fusion tarzı). for (int i = 0; i < io.InputQueueCharacters.Size; ++i) { const ImWchar c = io.InputQueueCharacters[i]; const size_t l = std::strlen(s.tipBuf); if (((c >= '0' && c <= '9') || c == '.' || (c == '-' && l == 0)) && l < sizeof(s.tipBuf) - 1) { s.tipBuf[l] = (char)c; s.tipBuf[l + 1] = 0; } } if (ImGui::IsKeyPressed(ImGuiKey_Backspace)) { const size_t l = std::strlen(s.tipBuf); if (l) s.tipBuf[l - 1] = 0; } const bool tipVar = s.tipBuf[0] && !(s.tipBuf[0] == '-' && !s.tipBuf[1]); if (tipVar) s.mesafe = (f32)std::atof(s.tipBuf); const bool ekle = s.mesafe >= 0; // + dışa Pad, − içe Cep const ImU32 col = ekle ? IM_COL32(120, 220, 255, 240) : IM_COL32(255, 150, 90, 240); const ImU32 baglanti = ekle ? IM_COL32(120, 220, 255, 110) : IM_COL32(255, 150, 90, 110); for (const auto& lp : s.poliler) { std::vector taban, tepe; taban.reserve(lp.size()); tepe.reserve(lp.size()); for (const auto& p : lp) { ImVec2 sb, st; if (proj(p, sb) && proj(p + s.normalD * s.mesafe, st)) { taban.push_back(sb); tepe.push_back(st); } } const int n = (int)tepe.size(); for (int i = 0; i < n; ++i) { dl->AddLine(tepe[i], tepe[(i + 1) % n], col, 1.8f); // üst kontur (yeni yüz) dl->AddLine(taban[i], taban[(i + 1) % n], baglanti, 1.0f); // taban kontur dl->AddLine(taban[i], tepe[i], baglanti, 1.0f); // yan bağ } } ImVec2 ml; if (proj(s.merkezD + s.normalD * s.mesafe, ml)) { char btxt[48]; if (tipVar) std::snprintf(btxt, sizeof(btxt), "%s mm ▏", s.tipBuf); else std::snprintf(btxt, sizeof(btxt), "%s %.2f mm", ekle ? "⬆ Pad" : "⬇ Cep", std::abs(s.mesafe)); gizmo::degerEtiketi(dl, ml, btxt, ekle ? IM_COL32(120, 220, 255, 255) : IM_COL32(255, 150, 90, 255)); } if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { const f32 mes = s.mesafe; const Varlik sk = s.sketch; const u32 kg = s.kaynakGovde; s.surukluyor = false; s.tipBuf[0] = 0; s.poliler.clear(); if (std::abs(mes) > 1e-3f) { // Bırakış → PARAMETRİK PartDesign feature (ürün ağacında düzenlenebilir + associatif): // dışa çek = Pad (kaynak/yeni gövdeye ekle), içe it = Pocket (kaynak gövdeden oy). // Yön: pad/pocket profil normali = sketch düzlemi +Z = gizmo normalD → +mes dışa Pad; // Pocket tersYon ile −normal (eski sketchKatiUygula Cep yönü birebir korunur). Kaynak // gövde yoksa oyulacak hedef yok → daima Pad (eski davranış). Undo: dmFeatureEkleUndo // (featureOnayla yalnız taslak bayrağını temizler, yığına kayıt İTMEZ). const f64 uzunluk = std::abs((f64)mes); const bool ice = (mes < 0) && (kg != 0); const char* tip = ice ? "pocket" : "pad"; const char* degerKey = ice ? "derinlik" : "uzunluk"; const u32 fk = partD.featureBaslat(tip, sk, kg); // kg=0 → Pad bağımsız yeni gövde if (fk) { // TEK recompute: `featureGuncelle` parametre BAŞINA tam zincir-recompute koşturur // (OCCT prizma + fuse + tessellation). Cep'te iki çağrı = jest başına 3 recompute // (featureBaslat dahil) → bırakışta gözle görülür donma. `featureParamToplu` tüm // parametreleri yazıp TEK recompute yapar; DM'nin diğer jestleri zaten bunu kullanır. std::vector> parametreler; if (ice) parametreler.emplace_back("tersYon", 1.0); // içe oy: −normal (gövdeye doğru) parametreler.emplace_back(degerKey, uzunluk); partD.featureParamToplu(fk, parametreler); if (partD.featureOnayla(fk)) dmFeatureEkleUndo(cekirdek, partD, fk); ui::toastGoster(ice ? "Cep (Pocket) feature eklendi" : (kg ? "Pad feature eklendi" : "Yeni gövde (Pad) feature eklendi"), ui::ToastTip::Basari); dmTutamacOlayiYay(cekirdek, "Değiştir", ice ? "Sketch Cep" : "Sketch Pad"); } else { ui::toastGoster("Sketch İt/Çek başarısız (geçersiz geometri)", ui::ToastTip::Hata); } } } } } // namespace fiko