#include "feature_penceresi.hpp" #include #include #include #include #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/geometri/brep.hpp" // zincir onizleme: kenarZinciri/kenarNoktalari #include "fiko/parca/feature.hpp" #include "fiko/parca/feature_registry.hpp" #include "fiko/parca/parca_islemleri.hpp" #include "fiko/parca/part_design_sistemi.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/sahne/sahne_ref_secim.hpp" #include "fiko/ui/form.hpp" #include "fiko/ui/pencere_cerceve.hpp" #include "fiko/ui/tema.hpp" #include "dogrudan_ayar.hpp" // asyncApply — pencere sayısal düzenlemesi de worker'a #include "imgui.h" namespace fiko { namespace { // featureAsyncUygula'nın DESTEKLEDİĞİ tipler (OCCT hesabı worker'a alınabilir): pencereden // sayısal parametre sürüklemesi bu tiplerde bırakışta TEK async apply'a gider → devasa // modelde her sürükleme karesinde senkron zincirHesapla ile UI donmaz. inline bool featureAsyncDestekli(const std::string& tip) { return tip == "fillet" || tip == "chamfer" || tip == "yuz_itcek" || tip == "fillet_var" || tip == "shell" || tip == "draft" || tip == "draft_reflect" || tip == "yuz_tasi"; } using parca::Feature; using parca::FeatureParam; using parca::FeatureTanim; using parca::ParamTip; using parca::PartDesignSistemi; constexpr ImVec4 TURUNCU{1.0f, 0.62f, 0.10f, 1.0f}; // parametrik formül rozeti (ƒ=) — özel renk, tema token'ı yok // Feature-basina acik pencere + pin durumu (UI-only). cam_paneli g_pinDurum kalibi. std::unordered_map g_featAcik; std::unordered_map g_featPin; // Duzenleme (onaylanmis feature) icin acilis param anlik goruntusu → FeatureDuzenle // Islem undo/redo. Taslak feature'lar icin kullanilmaz (onlar FeatureEkle). std::unordered_map> g_featOnceParam; // Veri-odakli param alanlari (web FikoKomutIcerik @switch(p.tip)). degisen // (anahtar, deger) → guncelle. Kosullu gorunurluk (p.gorunurMu) atlar. void paramAlanlari(PartDesignSistemi& pd, Feature& feat, const FeatureTanim& td, SahneRefSecim& refSecim) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; const auto& harita = feat.parametreler(); // Tek bir parametrenin alanını çizen çekirdek (grup-bağımsız). auto cizParam = [&](const FeatureParam& p) { ImGui::PushID(p.anahtar.c_str()); // her param benzersiz ID scope → aynı etiket çakışmaz const f64 mevcut = feat.p(p.anahtar); if (p.tip == ParamTip::SahneEksen) { // Sahneden kenar seç → yön/eksen referansı (G gövde + A ordinal). const u32 k = feat.kimlik(); const bool aktifBu = refSecim.aktifMi(k, p.anahtar); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); char btn[64]; std::snprintf(btn, sizeof(btn), "%s##%s", aktifBu ? "🎯 Kenara tıkla…" : "🎯 Sahneden Kenar Seç", p.anahtar.c_str()); if (ImGui::Button(btn, {-1, 0})) { refSecim.baslat( k, p.anahtar, [&pd, k, anahtar = p.anahtar](const SahneRefSecim::Vurus& v) -> bool { pd.featureParamToplu(k, {{anahtar + "G", (f64)v.govde}, {anahtar + "A", (f64)v.alt}}); // tek recompute return false; // tek tık → mod biter }, "Yön/eksen için bir kenara tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNoktaMi*/ false); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (feat.p(p.anahtar + "G") > 0) ImGui::TextColored(CYAN, "✔ Kenar #%d", (int)feat.p(p.anahtar + "A")); else ImGui::TextColored(SOLUK, "%s: kenar seçilmedi", p.etiket.c_str()); } else if (p.tip == ParamTip::SahneNokta) { // Up To Plane/Surface hedefi: yüz/düzleme tıkla → dünya noktası + yüz normali sakla // (x/y/z + Nx/Ny/Nz + Var). Dispatch bunlardan mesafe çözer. const u32 k = feat.kimlik(); const bool aktifBu = refSecim.aktifMi(k, p.anahtar); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); char btn[80]; std::snprintf(btn, sizeof(btn), "%s##%s", aktifBu ? "🎯 Yüze/düzleme tıkla…" : "🎯 Hedef Düzlem/Yüz Seç", p.anahtar.c_str()); if (ImGui::Button(btn, {-1, 0})) { refSecim.baslat( k, p.anahtar, [&pd, k, anahtar = p.anahtar](const SahneRefSecim::Vurus& v) -> bool { pd.featureParamToplu(k, {{anahtar + "x", v.nokta.x}, {anahtar + "y", v.nokta.y}, {anahtar + "z", v.nokta.z}, {anahtar + "Nx", v.normalVar ? v.normal.x : 0.0}, {anahtar + "Ny", v.normalVar ? v.normal.y : 0.0}, {anahtar + "Nz", v.normalVar ? v.normal.z : 0.0}, {anahtar + "Var", 1.0}}); // 7 ayrı recompute → TEK return false; // tek tık → mod biter }, "Limit için yüze/düzleme tıkla · ESC=bitir", /*beklenenTur*/ 1, /*serbestNoktaMi*/ true); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (feat.p(p.anahtar + "Var") > 0.5) ImGui::TextColored(CYAN, "✔ Hedef: (%.1f, %.1f, %.1f)", feat.p(p.anahtar + "x"), feat.p(p.anahtar + "y"), feat.p(p.anahtar + "z")); else ImGui::TextColored(SOLUK, "%s: hedef seçilmedi", p.etiket.c_str()); } else if (p.tip == ParamTip::Bayrak) { bool b = mevcut > 0.5; if (ui::anahtarSatiri(p.etiket.c_str(), &b)) pd.featureGuncelle(feat.kimlik(), p.anahtar, b ? 1.0 : 0.0); } else if (p.tip == ParamTip::Secim) { int v = (int)mevcut; std::vector ogeler; ogeler.reserve(p.secenekler.size()); for (const std::string& s : p.secenekler) ogeler.push_back(s.c_str()); const std::string wid = "##" + p.anahtar; if (!ogeler.empty()) { ui::alan(p.etiket.c_str()); if (ImGui::Combo(wid.c_str(), &v, ogeler.data(), (int)ogeler.size())) pd.featureGuncelle(feat.kimlik(), p.anahtar, (f64)v); } } else if (p.tip == ParamTip::Tamsayi) { int v = (int)mevcut; const std::string wid = "##" + p.anahtar; ui::alan(p.etiket.c_str()); if (ImGui::DragInt(wid.c_str(), &v, (f32)p.adim, (int)p.minVeya, p.maksVeya > 0 ? (int)p.maksVeya : 0)) pd.featureGuncelle(feat.kimlik(), p.anahtar, (f64)v); } else { // Mesafe / Sayi (parametrik formül destekli) char fmt[24]; std::snprintf(fmt, sizeof(fmt), "%%.3f%s%s", p.birim.empty() ? "" : " ", p.birim.c_str()); const f64 mn = p.minVeya, mx = p.maksVeya > 0 ? p.maksVeya : 0; const bool formulVar = feat.formulVarMi(p.anahtar); ImGui::SetNextItemWidth(-28); // ƒ butonuna yer bırak if (formulVar) { // Formül sürülen alan: çözülen değeri salt-okunur göster (turuncu rozet ile). f64 cz = feat.pEfektif(p.anahtar, pd.sahne().paramDepo()); ImGui::BeginDisabled(); ImGui::DragScalar(p.etiket.c_str(), ImGuiDataType_Double, &cz, 0.0f, &mn, mx > 0 ? &mx : nullptr, fmt); ImGui::EndDisabled(); } else { f64 v = mevcut; const bool suruklendi = ImGui::DragScalar(p.etiket.c_str(), ImGuiDataType_Double, &v, (f32)p.adim, &mn, mx > 0 ? &mx : nullptr, fmt); // ASYNC YOL (async-destekli tip + ayar açık): sürükleme sırasında değeri YAZ ama // recompute ETME (drag akıcı — devasa modelde donma yok); bırakışta (release) TEK // async apply. Diğer tiplerde/kapalıyken eski CANLI senkron yol (davranış birebir). if (featureAsyncDestekli(feat.tip()) && dogrudanAyar().asyncApply) { if (suruklendi) feat.pAyarla(p.anahtar, v); // sadece değeri sakla if (ImGui::IsItemDeactivatedAfterEdit()) { // drag bitti → tek recompute const f64 son = feat.p(p.anahtar); if (!pd.featureAsyncUygula(feat.kimlik(), {{p.anahtar, son}})) pd.featureGuncelle(feat.kimlik(), p.anahtar, son); // desteklenmezse senkron } } else if (suruklendi) { pd.featureGuncelle(feat.kimlik(), p.anahtar, v); } } // ƒ butonu: formül düzenleme popup'ı aç. ImGui::SameLine(0, 4); char fbtn[48]; std::snprintf(fbtn, sizeof(fbtn), "ƒ##formbtn_%s", p.anahtar.c_str()); static char formBuf[128] = ""; if (ImGui::Button(fbtn, {24, 0})) { std::snprintf(formBuf, sizeof(formBuf), "%s", feat.formulAl(p.anahtar).c_str()); ImGui::OpenPopup("##formpop"); } if (ImGui::IsItemHovered()) ImGui::SetTooltip("Formül (ör. genislik*2)"); if (formulVar) ImGui::TextColored(TURUNCU, "ƒ= %s", feat.formulAl(p.anahtar).c_str()); if (ImGui::BeginPopup("##formpop")) { ImGui::TextUnformatted("Formül ifadesi"); ImGui::SetNextItemWidth(200); const bool enter = ImGui::InputText("##formin", formBuf, sizeof(formBuf), ImGuiInputTextFlags_EnterReturnsTrue); if (ImGui::Button("Uygula") || enter) { feat.formulAyarla(p.anahtar, formBuf); pd.featureGuncelle(feat.kimlik(), p.anahtar, feat.p(p.anahtar)); // yeniden inşa ImGui::CloseCurrentPopup(); } ImGui::SameLine(); if (ImGui::Button("Temizle")) { feat.formulAyarla(p.anahtar, ""); pd.featureGuncelle(feat.kimlik(), p.anahtar, feat.p(p.anahtar)); ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } } ImGui::PopID(); }; // CATIA gruplu yerleşim: grupları ilk-görülme sırasında topla (order-independent), // her grup için SeparatorText başlığı + o gruba ait görünür paramlar. Boş grup = // başlıksız üst blok (ilk render). Registry'de param sırası korunur. std::vector grupSira; for (const FeatureParam& p : td.parametreler) { if (p.gorunurMu && !p.gorunurMu(harita)) continue; if (std::find(grupSira.begin(), grupSira.end(), p.grup) == grupSira.end()) grupSira.push_back(p.grup); } // Kanonik CATIA sırası: registry sırasından bağımsız. Bilinmeyen grup → sona, // grupsuz ("") "Parametreler" olarak en sona. static const std::vector kanonik = { "1. Limit", "2. Limit", "Yön", "İnce Duvar", "Çıkış Açısı", "Konum", "Profil", "Dizi", "Dönüşüm"}; auto rank = [&](const std::string& g) -> int { if (g.empty()) return 1000; // grupsuz → en son auto it = std::find(kanonik.begin(), kanonik.end(), g); return it == kanonik.end() ? 500 : (int)(it - kanonik.begin()); // bilinmeyen→first-seen }; std::stable_sort(grupSira.begin(), grupSira.end(), [&](const std::string& a, const std::string& b) { return rank(a) < rank(b); }); for (const std::string& g : grupSira) { ImGui::SeparatorText(g.empty() ? "Parametreler" : g.c_str()); for (const FeatureParam& p : td.parametreler) { if (p.grup != g) continue; if (p.gorunurMu && !p.gorunurMu(harita)) continue; cizParam(p); } } } // ---- Fillet/Pah ETKİ ÖNİZLEMESİ ("kıracağı her yer baştan görünsün") ---- // OCCT fillet/pah teğet-devam eden zincire YAYILIR (davranış) — kullanıcı tek kenar // seçse de kesim zinciri kırar. Seçilen kenarların zincir BİRLEŞİMİ (seçilenler hariç) // turuncu kalın + üstte çizilir: uygulamadan önce etki alanı belli. Görsel katman // keskin kenar kalıbı (kenarNesneEkle/Kalin/Ustte); imza değişmedikçe yeniden kurulmaz // (kare-başı yalnız FNV hash — tahsis/OCCT yok). struct ZincirOnizleme { u64 imza = 0; u32 dugum = 0; }; std::unordered_map g_zincirOnizleme; // feature kimlik → durum void zincirOnizlemeSil(Sahne& sahne, u32 featKimlik) { if (auto it = g_zincirOnizleme.find(featKimlik); it != g_zincirOnizleme.end()) { if (it->second.dugum) sahne.sil(it->second.dugum); g_zincirOnizleme.erase(it); } } void zincirOnizlemeGuncelle(Sahne& sahne, Feature& feat) { const u32 k = feat.kimlik(); if (!dogrudanAyar().zincirOnizleme) { zincirOnizlemeSil(sahne, k); return; } const int n = (int)feat.p("kenarSayi"); const u32 govde = feat.hedefDugum(); Dugum* d = govde ? sahne.bul(govde) : nullptr; if (n <= 0 || !d || !d->brep || !d->brep->gecerliMi()) { zincirOnizlemeSil(sahne, k); return; } u64 imza = 1469598103934665603ull ^ govde; std::vector kokler; kokler.reserve((size_t)n); for (int i = 0; i < n; ++i) { const u32 ord = (u32)feat.p("kenar" + std::to_string(i)); if (ord) kokler.push_back(ord); imza = (imza ^ ord) * 1099511628211ull; } auto& z = g_zincirOnizleme[k]; if (z.imza == imza && (z.dugum == 0 || sahne.bul(z.dugum))) return; // degisiklik yok z.imza = imza; // Zincir birlesimi — SECILENLER HARIC (onlar zaten secim vurgusunda gorunur; // onizleme yalniz "fazladan kirilacak" kenarlari isaretler). std::set secili(kokler.begin(), kokler.end()), zincir; for (const u32 ord : kokler) for (const u32 zk : d->brep->kenarZinciri(ord)) if (!secili.count(zk)) zincir.insert(zk); if (zincir.empty()) { if (z.dugum) { sahne.sil(z.dugum); z.dugum = 0; } return; } std::vector kv; Aabbf sinir; bool sinirVar = false; for (const u32 ord : zincir) { const std::vector poly = d->brep->kenarNoktalari(ord); for (size_t i = 0; i + 1 < poly.size(); ++i) { const Vec3d a = d->donusum.noktaUygula(poly[i]); const Vec3d b = d->donusum.noktaUygula(poly[i + 1]); const Vec3f af{(f32)a.x, (f32)a.y, (f32)a.z}; const Vec3f bf{(f32)b.x, (f32)b.y, (f32)b.z}; kv.push_back({{af.x, af.y, af.z}, 0}); kv.push_back({{bf.x, bf.y, bf.z}, 0}); if (!sinirVar) { sinir.asgari = sinir.azami = af; sinirVar = true; } sinir.genislet(af); sinir.genislet(bf); } } if (kv.empty() || !sinirVar) { if (z.dugum) { sahne.sil(z.dugum); z.dugum = 0; } return; } const Vec3f renk{1.0f, 0.62f, 0.10f}; // turuncu: "buraya da kirilacak" if (z.dugum && sahne.bul(z.dugum)) sahne.kenarNesneGuncelle(z.dugum, kv, sinir); else z.dugum = sahne.kenarNesneEkle("Zincir Önizleme", 0, renk, kv, sinir); sahne.kenarNesneKalin(z.dugum, true); sahne.kenarNesneUstte(z.dugum, true); // model arkasinda kalsa da etki gorunsun } // Fillet/Chamfer (kenar) + Shell/Draft (yüz) ortak: çoklu alt-öğe seçim bölümü. // altPrefix="kenar"/"yuz", sayiKey="kenarSayi"/"yuzSayi", beklenenTur 2=kenar 1=yüz, // ogeAd="Kenar"/"Yüz". 🎯 ile sahneden ekle (aynı gövde, tekrar yok), ✖ ile kaldır. void cokluAltBolum(PartDesignSistemi& pd, Feature& feat, SahneRefSecim& refSecim, Sahne& sahne, const char* baslik, const std::string& altPrefix, const std::string& sayiKey, int beklenenTur, const char* ogeAd, const char* btnEkle, const char* btnAktif, const char* ipucu, u32 zorunluGovde = 0) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; const u32 k = feat.kimlik(); ImGui::SeparatorText(baslik); const std::string et = altPrefix + "_sec"; const bool aktifBu = refSecim.aktifMi(k, et); // ➕ DM ÇOKLU-SEÇİM KÖPRÜSÜ: sahnede (kutu/shift/Selection Stack ile) seçili TÜM uygun // alt-öğeleri TEK adımda ekle (🎯 tek-tek tıklatmanın toplu ikizi). Kip eşleşmeli: yüz // feature'ı → Yüz kipi, kenar → Kenar kipi (SecimOge tip taşımaz; ayrım sahne.kip()'ten). const SecimKip gerekliKip = (beklenenTur == 2) ? SecimKip::Kenar : SecimKip::Yuz; const bool kipUygun = sahne.kip() == gerekliKip; ImGui::BeginDisabled(!kipUygun); if (ImGui::Button("➕ Seçili Öğeleri Ekle", {-1, 0})) { int n = (int)feat.p(sayiKey); std::vector> yeni; for (const SecimOge& o : sahne.secililer()) { if (o.alt == 0) continue; // gövde ögesi değil if (zorunluGovde) { if (o.govde != zorunluGovde) continue; // fused sonuç dışı → yok say } else { if (feat.hedefDugum() == 0) feat.hedefDugumAyarla(o.govde); // ilk seçim hedefi belirler if (o.govde != feat.hedefDugum()) continue; // başka gövde → tek-gövde MVP } bool var = false; for (int i = 0; i < n; ++i) if ((u32)feat.p(altPrefix + std::to_string(i)) == o.alt) { var = true; break; } if (var) continue; // zaten ekli yeni.emplace_back(altPrefix + std::to_string(n), (f64)o.alt); ++n; } if (!yeni.empty()) { yeni.emplace_back(sayiKey, (f64)n); pd.featureParamToplu(k, yeni); // TEK recompute (öğe başına ayrı recompute yerine) } } ImGui::EndDisabled(); if (!kipUygun) ImGui::TextColored(SOLUK, "Sahnede %s kipine geç + çoklu seç → bu butona bas", ogeAd); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(aktifBu ? btnAktif : btnEkle, {-1, 0})) { refSecim.baslat( k, et, [&pd, k, altPrefix, sayiKey, zorunluGovde](const SahneRefSecim::Vurus& v) -> bool { Feature* f = pd.bul(k); if (!f || v.alt == 0) return true; // alt-öğe değil → modda kal // zorunluGovde>0 → yüzler o gövdede olmalı (Union Trim: fused SONUÇ düğümü). Aksi // halde ilk seçim hedefi belirler (Fillet/Shell/Remove Lump: tek-gövde MVP). if (zorunluGovde) { if (v.govde != zorunluGovde) return true; // başka gövde → yok say } else { if (f->hedefDugum() == 0) f->hedefDugumAyarla(v.govde); // ilk seçim hedefi belirler if (v.govde != f->hedefDugum()) return true; // başka gövde → yok say (tek-gövde MVP) } const int n = (int)f->p(sayiKey); for (int i = 0; i < n; ++i) // zaten ekliyse yok say if ((u32)f->p(altPrefix + std::to_string(i)) == v.alt) return true; pd.featureGuncelle(k, altPrefix + std::to_string(n), (f64)v.alt); pd.featureGuncelle(k, sayiKey, (f64)(n + 1)); return true; // çoklu → modda kal }, ipucu, beklenenTur, /*serbestNoktaMi*/ false); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); const int n = (int)feat.p(sayiKey); if (n == 0) { ImGui::TextColored(SOLUK, "%s seçilmedi — 🎯 ile ekle", ogeAd); } else { ImGui::TextColored(CYAN, "%d %s seçili", n, ogeAd); for (int i = 0; i < n; ++i) { ImGui::Text("• %s #%d", ogeAd, (int)feat.p(altPrefix + std::to_string(i))); ImGui::SameLine(); char rid[24]; std::snprintf(rid, sizeof(rid), "✖##%s%d", altPrefix.c_str(), i); if (ImGui::SmallButton(rid)) { // i'yi çıkar → sonrakileri kaydır for (int j = i; j < n - 1; ++j) pd.featureGuncelle(k, altPrefix + std::to_string(j), feat.p(altPrefix + std::to_string(j + 1))); pd.featureGuncelle(k, sayiKey, (f64)(n - 1)); break; } } if (ImGui::SmallButton("Tümünü Temizle")) pd.featureGuncelle(k, sayiKey, 0.0); } } void featurePenceresiCiz(Cekirdek& cekirdek, Sahne& sahne, PartDesignSistemi& pd, Feature& feat, SahneRefSecim& refSecim) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 HATA_RENK = ui::tema().hata; const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; const FeatureTanim* td = parca::featureTanimBul(feat.tip()); if (!td) return; // Düzenleme (onaylanmış feature) penceresi ilk açılışında param snapshot al → // FeatureDuzenleIslem undo referansı. Taslak feature'lar snapshot almaz. if (!pd.taslakMi(feat.kimlik()) && !g_featOnceParam.count(feat.kimlik())) g_featOnceParam[feat.kimlik()] = feat.parametreler(); bool& ustte = g_featPin[feat.kimlik()]; char baslik[192]; std::snprintf(baslik, sizeof(baslik), "%s %s###feat_%u", td->simge.c_str(), feat.ad().c_str(), feat.kimlik()); using namespace fiko::ui; using u32 = fiko::u32; // ui::u32(ImVec4) ile tip cakismasini onler bool acik = true, erken = false; ui::Pencere pen{baslik, &acik, {.boyut = {300, 0}, .pinDurum = &ustte}}; if (pen) { // ---- Ad (inline duzenlenebilir) ---- { char buf[96]; std::snprintf(buf, sizeof(buf), "%s", feat.ad().c_str()); ImGui::SetNextItemWidth(-1); if (ImGui::InputText("##ad", buf, sizeof(buf))) feat.adAyarla(buf); } const bool holeMu = feat.tip() == "hole"; // fcMu: kenar seçimli (Fillet/Chamfer/Variable Fillet). sdMu: yüz seçimli (Shell/Draft/ // Face-Face/Tritangent Fillet). Her ikisi de profil kullanmaz; çoklu alt-öğe seçer. const bool fcMu = feat.tip() == "fillet" || feat.tip() == "chamfer" || feat.tip() == "fillet_var"; // Fillet/pah: kenar listesi degistikce zincir onizlemesini tazele (sekmeden bagimsiz — // pencere acikken etki alani HEP gorunur; imza ayni ise no-op, kare-basi ucuz). if (fcMu) zincirOnizlemeGuncelle(sahne, feat); const bool sdMu = feat.tip() == "shell" || feat.tip() == "draft" || feat.tip() == "fillet_ff" || feat.tip() == "fillet_tri" || feat.tip() == "remove_face"; const bool ribMu = feat.tip() == "rib" || feat.tip() == "slot"; // profil + kılavuz eğri süpürme const bool loftMu = feat.tip() == "loft" || feat.tip() == "loft_cikar"; // 1. kesit + ek kesitler const bool userPatMu = feat.tip() == "pattern_user"; // konum sketch'i (nokta konumlarına kopya) const bool patternMu = feat.tip() == "pattern_dik" || feat.tip() == "pattern_dairesel" || feat.tip() == "pattern_user" || feat.tip() == "mirror"; // Transformation (sketch/kenar/yüz seçimsiz; hedef katıyı dönüştürür — profil bölümü atlanır). const bool transformMu = feat.tip() == "translation" || feat.tip() == "rotation" || feat.tip() == "symmetry" || feat.tip() == "scaling"; const bool solidCombineMu = feat.tip() == "solid_combine"; // profil + 2. profil sketch kesişimi const bool unionTrimMu = feat.tip() == "union_trim"; // 2 gövde fuse + sonuç yüz-kırp const bool removeLumpMu = feat.tip() == "remove_lump"; // hedef parçalarından tut/at ImGui::TextColored(SOLUK, "%s", transformMu ? "Dönüşüm (hedef katıyı taşır/döndürür/ölçekler)" : patternMu ? "Dizi / Aynalama (hedef katıyı çoğaltır)" : (fcMu || sdMu) ? "Yüz/Kenar İşleme (hedef katıyı değiştirir)" : td->malzemeEkler ? "Malzeme Ekle (Prizma)" : "Malzeme Çıkar (Boolean)"); const u32 k = feat.kimlik(); const bool taslakMi = pd.taslakMi(k); if (sekmeBaslat("##featsek")) { // ── Profil: sketch / hedef / kılavuz / kesit seçimleri ── if (sekme("Profil", "📐")) { // ---- Profil / hedef bilgisi (Fillet/Chamfer/Shell/Draft/Pattern profil kullanmaz → atla) ---- if (fcMu || sdMu || patternMu || transformMu || unionTrimMu || removeLumpMu) { // Profil yok. Pattern/Transform/Boolean-lump: yalnız hedef + sayısal/yüz seçimi. } else if (holeMu) { ImGui::SeparatorText("Konum"); const std::string etiket = "hole_konum"; const bool aktifBu = refSecim.aktifMi(k, etiket); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(aktifBu ? "🎯 Yüzeye tıkla…" : "🎯 Yüzeyden Konum Seç", {-1, 0})) { // Yüz seç → tık noktası konum + yüz normali delik ekseni; hedef = o gövde. refSecim.baslat( k, etiket, [&pd, k](const SahneRefSecim::Vurus& v) -> bool { Feature* f = pd.bul(k); if (!f) return false; pd.featureGuncelle(k, "konumX", v.nokta.x); pd.featureGuncelle(k, "konumY", v.nokta.y); pd.featureGuncelle(k, "konumZ", v.nokta.z); if (v.normalVar) { // delik -normal yönünde delinir (yüzeye içeri) pd.featureGuncelle(k, "eksenX", -v.normal.x); pd.featureGuncelle(k, "eksenY", -v.normal.y); pd.featureGuncelle(k, "eksenZ", -v.normal.z); } if (v.govde) { f->hedefDugumAyarla(v.govde); pd.yenidenInsa(*f); } return false; // tek tık → mod biter }, "Delik için yüze tıkla · ESC=bitir", /*beklenenTur*/ 1, /*serbestNokta*/ true); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (feat.hedefDugum() != 0) ImGui::TextColored(CYAN, "✔ Yüzeyden konumlandı (XYZ ince ayar)"); else ImGui::TextColored(SOLUK, "Yüze tıkla · XYZ ile ince ayar"); } else { ImGui::SeparatorText("Profil"); // (A) EN SAĞLAM YOL: ağaçtan VEYA 3D'den seçili sketch'i profil yap. Sketch mesh'siz // olduğundan viewport ışın-tık ile seçmek zor; seçili sketch her iki kaynağı da kapsar. const Varlik seciliSk = sahne.seciliSketch(); ImGui::BeginDisabled(seciliSk == VARLIK_YOK); if (ImGui::Button("✔ Seçili Sketch'i Profil Yap", {-1, 0})) { feat.sketchAyarla(seciliSk); pd.yenidenInsa(feat); } ImGui::EndDisabled(); if (seciliSk == VARLIK_YOK) ImGui::TextColored(SOLUK, "Ağaçtan veya 3D'den bir sketch seç → bu butona bas"); // (B) Alternatif: sahneden DİREKT sketch kenarına tıkla (salt-kenar → beklenenTur=2). const std::string profEt = "feat_profil"; const bool profAktif = refSecim.aktifMi(k, profEt); if (profAktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(profAktif ? "🎯 Sketch'e tıkla…" : "🎯 Sahneden Sketch Seç", {-1, 0})) { refSecim.baslat( k, profEt, [&pd, &sahne, k](const SahneRefSecim::Vurus& v) -> bool { Feature* f = pd.bul(k); Dugum* d = sahne.bul(v.govde); if (f && d && d->tip == DugumTip::Sketch) { f->sketchAyarla(v.govde); pd.yenidenInsa(*f); } return false; // tek seçim → biter }, "Bir sketch çizgisine tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (profAktif) ImGui::PopStyleColor(); if (feat.sketch() != 0) { Dugum* sd = sahne.bul(feat.sketch()); ImGui::TextColored(CYAN, "✎ Profil: %s", sd ? sd->ad.c_str() : "sketch"); } else { ImGui::TextColored(HATA_RENK, "Sketch profili yok"); } } // ---- Rib/Slot: kılavuz eğri (center curve) — süpürme spine'ı olan İKİNCİ sketch ---- if (ribMu) { ImGui::SeparatorText("Kılavuz Eğri (Center Curve)"); const u32 kilSk = (u32)feat.p("kilavuzSketch"); // (A) Seçili sketch'i kılavuz yap (profil ile aynı olmamalı). const Varlik seciliSk = sahne.seciliSketch(); ImGui::BeginDisabled(seciliSk == VARLIK_YOK || seciliSk == feat.sketch()); if (ImGui::Button("➤ Seçili Sketch'i Kılavuz Yap", {-1, 0})) pd.featureGuncelle(k, "kilavuzSketch", (f64)seciliSk); ImGui::EndDisabled(); // (B) Sahneden DİREKT kılavuz sketch kenarına tıkla (salt-kenar → beklenenTur=2). const std::string kilEt = "feat_kilavuz"; const bool kilAktif = refSecim.aktifMi(k, kilEt); if (kilAktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(kilAktif ? "🎯 Kılavuza tıkla…" : "🎯 Sahneden Kılavuz Seç", {-1, 0})) { refSecim.baslat( k, kilEt, [&pd, &sahne, k](const SahneRefSecim::Vurus& v) -> bool { Dugum* d = sahne.bul(v.govde); if (d && d->tip == DugumTip::Sketch) pd.featureGuncelle(k, "kilavuzSketch", (f64)v.govde); return false; // tek seçim → biter }, "Kılavuz eğri sketch'ine tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (kilAktif) ImGui::PopStyleColor(); if (kilSk != 0) { Dugum* kd = sahne.bul(kilSk); ImGui::TextColored(CYAN, "➤ Kılavuz: %s", kd ? kd->ad.c_str() : "sketch"); } else { ImGui::TextColored(HATA_RENK, "Kılavuz eğri seçilmedi"); } } // ---- User Pattern: konum sketch'i — hedef kopyaları bu sketch'in NOKTA konumlarına yerleşir ---- if (userPatMu) { ImGui::SeparatorText("Konum Sketch'i (Nokta Konumları)"); const u32 konSk = (u32)feat.p("konumSketch"); // (A) Seçili sketch'i konum sketch'i yap. const Varlik seciliSk = sahne.seciliSketch(); ImGui::BeginDisabled(seciliSk == VARLIK_YOK); if (ImGui::Button("➤ Seçili Sketch'i Konum Yap", {-1, 0})) pd.featureGuncelle(k, "konumSketch", (f64)seciliSk); ImGui::EndDisabled(); // (B) Sahneden DİREKT konum sketch kenarına/noktasına tıkla. const std::string konEt = "feat_konum"; const bool konAktif = refSecim.aktifMi(k, konEt); if (konAktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(konAktif ? "🎯 Konuma tıkla…" : "🎯 Sahneden Konum Sketch Seç", {-1, 0})) { refSecim.baslat( k, konEt, [&pd, &sahne, k](const SahneRefSecim::Vurus& v) -> bool { Dugum* d = sahne.bul(v.govde); if (d && d->tip == DugumTip::Sketch) pd.featureGuncelle(k, "konumSketch", (f64)v.govde); return false; // tek seçim → biter }, "Konum (nokta) sketch'ine tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (konAktif) ImGui::PopStyleColor(); if (konSk != 0) { Dugum* kd = sahne.bul(konSk); ImGui::TextColored(CYAN, "✸ Konum: %s", kd ? kd->ad.c_str() : "sketch"); } else { ImGui::TextColored(HATA_RENK, "Konum sketch'i seçilmedi (nokta içermeli)"); } } // ---- Loft: ek kesit sketch'leri (1. kesit = yukarıdaki Profil; en az 1 ek → toplam ≥ 2) ---- if (loftMu) { ImGui::SeparatorText("Ek Kesitler (Multi-sections)"); ImGui::TextColored(SOLUK, "1. Kesit = yukarıdaki Profil · sıra = ekleme sırası"); const int n = (int)feat.p("kesitSayi"); // (A) Seçili sketch'i ek kesit yap (profil/mükerrer olmamalı). const Varlik seciliSk = sahne.seciliSketch(); bool zaten = seciliSk == feat.sketch(); for (int i = 0; i < n && !zaten; ++i) if ((u32)feat.p("kesit" + std::to_string(i)) == seciliSk) zaten = true; ImGui::BeginDisabled(seciliSk == VARLIK_YOK || zaten); if (ImGui::Button("➕ Seçili Sketch'i Kesit Ekle", {-1, 0})) { pd.featureGuncelle(k, "kesit" + std::to_string(n), (f64)seciliSk); pd.featureGuncelle(k, "kesitSayi", (f64)(n + 1)); } ImGui::EndDisabled(); // (B) Sahneden DİREKT kesit sketch kenarına tıkla (çoklu → modda kal; salt-kenar → tür 2). const std::string ksEt = "feat_kesit"; const bool ksAktif = refSecim.aktifMi(k, ksEt); if (ksAktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(ksAktif ? "🎯 Kesite tıkla… (çoklu · ESC bitir)" : "🎯 Sahneden Kesit Ekle", {-1, 0})) { refSecim.baslat( k, ksEt, [&pd, &sahne, k](const SahneRefSecim::Vurus& v) -> bool { Feature* f = pd.bul(k); Dugum* d = sahne.bul(v.govde); if (!f || !d || d->tip != DugumTip::Sketch) return true; // sketch değil → modda kal if (v.govde == f->sketch()) return true; // 1. kesit (profil) → yok say const int m = (int)f->p("kesitSayi"); for (int i = 0; i < m; ++i) // mükerrer → yok say if ((u32)f->p("kesit" + std::to_string(i)) == v.govde) return true; pd.featureGuncelle(k, "kesit" + std::to_string(m), (f64)v.govde); pd.featureGuncelle(k, "kesitSayi", (f64)(m + 1)); return true; // çoklu → modda kal }, "Ek kesit sketch çizgisine tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (ksAktif) ImGui::PopStyleColor(); if (ksAktif) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); if (n == 0) { ImGui::TextColored(HATA_RENK, "Ek kesit yok — en az 1 ek kesit ekleyin (toplam ≥ 2)"); } else { ImGui::TextColored(CYAN, "%d ek kesit (+1 profil = %d)", n, n + 1); for (int i = 0; i < n; ++i) { Dugum* sd = sahne.bul((u32)feat.p("kesit" + std::to_string(i))); ImGui::Text("• %d. Kesit: %s", i + 2, sd ? sd->ad.c_str() : "sketch"); ImGui::SameLine(); char rid[24]; std::snprintf(rid, sizeof(rid), "✖##kesit%d", i); if (ImGui::SmallButton(rid)) { // i'yi çıkar → sonrakileri kaydır for (int j = i; j < n - 1; ++j) pd.featureGuncelle(k, "kesit" + std::to_string(j), feat.p("kesit" + std::to_string(j + 1))); pd.featureGuncelle(k, "kesitSayi", (f64)(n - 1)); break; } } if (ImGui::SmallButton("Tümünü Temizle")) pd.featureGuncelle(k, "kesitSayi", 0.0); } } // ---- Solid Combine: 2. profil sketch (1. profil = yukarıdaki Profil) — öteleme kesişimi ---- if (solidCombineMu) { ImGui::SeparatorText("2. Profil (Kesişim)"); ImGui::TextColored(SOLUK, "Her profil kendi normalinde prizmalanır → kesişim katı"); const u32 sk2 = (u32)feat.p("ikinciSketch"); // (A) Seçili sketch'i 2. profil yap (1. profil ile aynı olmamalı). const Varlik seciliSk = sahne.seciliSketch(); ImGui::BeginDisabled(seciliSk == VARLIK_YOK || seciliSk == feat.sketch()); if (ImGui::Button("➤ Seçili Sketch'i 2. Profil Yap", {-1, 0})) pd.featureGuncelle(k, "ikinciSketch", (f64)seciliSk); ImGui::EndDisabled(); // (B) Sahneden DİREKT 2. profil sketch kenarına tıkla (salt-kenar → beklenenTur=2). const std::string p2Et = "feat_profil2"; const bool p2Aktif = refSecim.aktifMi(k, p2Et); if (p2Aktif) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(p2Aktif ? "🎯 2. Profile tıkla…" : "🎯 Sahneden 2. Profil Seç", {-1, 0})) { refSecim.baslat( k, p2Et, [&pd, &sahne, k](const SahneRefSecim::Vurus& v) -> bool { Feature* f = pd.bul(k); Dugum* d = sahne.bul(v.govde); if (f && d && d->tip == DugumTip::Sketch && v.govde != f->sketch()) pd.featureGuncelle(k, "ikinciSketch", (f64)v.govde); return false; // tek seçim → biter }, "2. profil sketch çizgisine tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (p2Aktif) ImGui::PopStyleColor(); if (sk2 != 0) { Dugum* sd = sahne.bul(sk2); ImGui::TextColored(CYAN, "⧓ 2. Profil: %s", sd ? sd->ad.c_str() : "sketch"); } else { ImGui::TextColored(HATA_RENK, "2. profil sketch'i seçilmedi"); } } if (!td->malzemeEkler) { if (Dugum* h = sahne.bul(feat.hedefDugum())) ImGui::Text("Hedef: %s", h->ad.c_str()); else ImGui::TextColored(HATA_RENK, "Hedef katı seçilmedi"); } sekmeBitir(); } // ── Öğe: çoklu kenar/yüz seçimi (Fillet/Chamfer/Shell/Draft/...) ── if ((fcMu || sdMu || removeLumpMu || unionTrimMu) && sekme("Öğe", "🔩")) { // ---- Fillet/Chamfer/Variable: çoklu (variable=tek) kenar · Shell/Draft/Face-Face/ // Tritangent: çoklu yüz seçimi (ortak bölüm) ---- if (fcMu) cokluAltBolum(pd, feat, refSecim, sahne, "Kenarlar", "kenar", "kenarSayi", /*beklenenTur*/ 2, "Kenar", "🎯 Kenar Ekle", "🎯 Kenara tıkla… (çoklu · ESC bitir)", feat.tip() == "fillet_var" ? "Değişken yarıçap için TEK kenara tıkla · ESC=bitir" : "Yuvarlanacak/pahlanacak kenarlara tıkla · ESC=bitir"); else if (sdMu) { const char* yuzIpucu = feat.tip() == "shell" ? "Açık bırakılacak yüzlere tıkla · ESC=bitir" : feat.tip() == "draft" ? "Eğilecek yüzlere tıkla · ESC=bitir" : feat.tip() == "fillet_ff" ? "Fillet için 2 yüze tıkla · ESC=bitir" : "Sıra: 2 tutulacak + son kaldırılacak yüz · ESC=bitir"; cokluAltBolum(pd, feat, refSecim, sahne, "Yüzler", "yuz", "yuzSayi", /*beklenenTur*/ 1, "Yüz", "🎯 Yüz Ekle", "🎯 Yüze tıkla… (çoklu · ESC bitir)", yuzIpucu); } else if (removeLumpMu) // Hedef katının ayrık parçalarından seçilecek yüz(ler) — tut/at mod param'da. cokluAltBolum(pd, feat, refSecim, sahne, "Parça Yüzleri", "yuz", "yuzSayi", /*beklenenTur*/ 1, "Yüz", "🎯 Parça Yüzü Ekle", "🎯 Yüze tıkla… (çoklu · ESC bitir)", "Tutulacak/atılacak parçanın yüzüne tıkla · ESC=bitir"); else if (unionTrimMu) // Fused SONUÇ düğümü üzerinde seçilir (2 gövde birleşince oluşan parçalar) → seçili lump atılır. cokluAltBolum(pd, feat, refSecim, sahne, "Kaldırılacak Parça Yüzleri", "yuz", "yuzSayi", /*beklenenTur*/ 1, "Yüz", "🎯 Kaldırılacak Yüz Ekle", "🎯 Yüze tıkla… (çoklu · ESC bitir)", "Kaldırılacak parçanın yüzüne tıkla (birleşim sonucu) · ESC=bitir", /*zorunluGovde*/ feat.sonucDugum()); sekmeBitir(); } // ── Parametre: veri-odaklı alanlar (CATIA gruplu yerleşim) ── if (sekme("Parametre", "⚙")) { // ---- Parametreler (veri-odakli, CATIA gruplu yerleşim) ---- paramAlanlari(pd, feat, *td, refSecim); // ---- Hole dişli etiketi (meta; ürün ağacı adına yansıtılır) ---- if (holeMu && feat.p("disli") > 0.5) { const parca::DisliBilgi& db = parca::disliBilgisi((int)feat.p("disliStd")); ImGui::TextColored(CYAN, "⚙ %s dişli · adım %.2f mm · derinlik %.1f mm (matkap Ø%.2f mm)", db.etiket, feat.p("disAdim"), feat.p("disDerinlik"), db.tapDrill); } sekmeBitir(); } sekmeKapat(); } // ---- Hata satiri (OCCT basarisizsa) ---- if (!feat.hata().empty()) { ImGui::Spacing(); ui::bilgiSeridi(3, feat.hata().c_str()); } // ---- Alt eylem cubugu: ✔ Tamam / (taslak) ✖ İptal · (kalıcı) 🗑 Sil ---- ImGui::Separator(); const bool onaylanabilir = feat.hata().empty(); if (!onaylanabilir) ImGui::BeginDisabled(); if (ImGui::Button("✔ Tamam", {-90, 0})) { if (refSecim.sahip() == k) refSecim.bitir(); if (pd.featureOnayla(k)) { // taslak bayragini kaldirir // Dişli: ürün ağacı adına M-etiketi yansıt (meta). if (holeMu && feat.p("disli") > 0.5) { const parca::DisliBilgi& db = parca::disliBilgisi((int)feat.p("disliStd")); std::string ad = feat.ad(); if (ad.find(db.etiket) == std::string::npos) feat.adAyarla(ad + " (" + db.etiket + ")"); } if (taslakMi) { // Yeni feature → undo geçmişine ekle (canlı zaten var; ilk uygula no-op). cekirdek.uygula(std::make_unique(pd, k)); } else { // Düzenleme → param değişikliği undo/redo. auto once = g_featOnceParam.count(k) ? g_featOnceParam[k] : feat.parametreler(); if (once != feat.parametreler()) cekirdek.uygula( std::make_unique(pd, k, once, feat.parametreler())); g_featOnceParam.erase(k); } g_featAcik[k] = false; zincirOnizlemeSil(sahne, k); // onaylandi → etki onizlemesi kalkar } } if (!onaylanabilir) ImGui::EndDisabled(); ImGui::SameLine(); if (taslakMi) { if (ImGui::Button("✖ İptal", {-1, 0})) { if (refSecim.sahip() == k) refSecim.bitir(); pd.featureIptal(k); // taslak sonuc dugum + feature silinir (undo'ya girmez) g_featAcik[k] = false; g_featOnceParam.erase(k); zincirOnizlemeSil(sahne, k); erken = true; } } else { if (ImGui::Button("🗑 Sil", {-1, 0})) { if (refSecim.sahip() == k) refSecim.bitir(); g_featAcik[k] = false; g_featOnceParam.erase(k); zincirOnizlemeSil(sahne, k); cekirdek.uygula(std::make_unique(pd, k)); erken = true; } } } // if (pen) if (!erken && !acik) { if (refSecim.sahip() == feat.kimlik()) refSecim.bitir(); g_featAcik[feat.kimlik()] = false; zincirOnizlemeSil(sahne, feat.kimlik()); } } } // namespace FeatureOnizlemeAyar& featureOnizlemeAyar() { static FeatureOnizlemeAyar a; return a; } void featurePencereAc(u32 kimlik) { g_featAcik[kimlik] = true; } void featurePencereleriCiz(Cekirdek& cekirdek, Sahne& sahne, PartDesignSistemi& pd, SahneRefSecim& refSecim) { for (auto it = g_featAcik.begin(); it != g_featAcik.end();) { if (!it->second) { it = g_featAcik.erase(it); continue; } Feature* feat = pd.bul(it->first); if (!feat) { // feature silinmis → ona ait seçim modunu da kapat if (refSecim.sahip() == it->first) refSecim.bitir(); it = g_featAcik.erase(it); continue; } featurePenceresiCiz(cekirdek, sahne, pd, *feat, refSecim); ++it; } // ---- Ghost önizleme: açık TASLAK feature'ın sonuç düğümü yarı-saydam çizilir ---- // (bekleyen sonuç hissi; ✔ Tamam kalıcı yapar, ✖ İptal siler). Saydamlık render'da // her kare okunur (mesh rebuild yok) → kapanınca/onaylanınca eski değere geri yüklenir. static std::unordered_map g_ghostEski; // sonuç düğümü → önceki saydamlık const FeatureOnizlemeAyar& onAyar = featureOnizlemeAyar(); const f32 GHOST_SAYDAM = std::clamp(onAyar.saydamlik, 0.1f, 0.9f); std::unordered_set istenen; if (onAyar.aktif) { for (const auto& [k, acikMi] : g_featAcik) { if (!acikMi) continue; Feature* f = pd.bul(k); if (!f || !pd.taslakMi(k)) continue; if (const u32 dg = f->sonucDugum()) istenen.insert(dg); } } // Geri yükle: artık ghost olmayan düğümler for (auto it = g_ghostEski.begin(); it != g_ghostEski.end();) { if (!istenen.count(it->first)) { if (Dugum* d = sahne.bul(it->first)) d->saydamlik = it->second; it = g_ghostEski.erase(it); } else { ++it; } } // Uygula: HER KARE zorla (yeniden-inşa saydamlığı sıfırlasa da korunur). Eski // değer yalnız İLK kez saklanır → geri yükleme gerçek orijinale döner. for (u32 dg : istenen) { if (Dugum* d = sahne.bul(dg)) { if (!g_ghostEski.count(dg)) g_ghostEski[dg] = d->saydamlik; d->saydamlik = GHOST_SAYDAM; } } } } // namespace fiko