#include "zeka_penceresi.hpp" #include #include #include #include #include #include #include #include #include "ayar_kayitlari.hpp" // zekaAktif / zekaHesapAsync #include "fiko/analiz/analiz_sistemi.hpp" // kameraOdak köprüsü #include "fiko/cekirdek/cekirdek.hpp" // gorevler() — async kuyruklama #include "fiko/cekirdek/gorev.hpp" // GorevBaglam #include "fiko/geometri/brep.hpp" // govdeDerinKopya #include "fiko/core/birim_bicim.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/ui/bilesen_ek.hpp" // toastGoster #include "fiko/ui/form.hpp" // bilgiSeridi #include "fiko/ui/pencere_cerceve.hpp" #include "fiko/ui/tema.hpp" #include "fiko/zeka/zeka_motoru.hpp" #include "imgui.h" #include "uygulama_baglam.hpp" namespace fiko { namespace { // Liste SADECE pencere açılırken / graf sürümü değişince kurulur (sıcak yol temiz). struct ZekaSatir { u64 dugum = 0; std::string ad; // "Delik 1" std::string bilgi; // "Ø10 mm · derinlik 20 mm · kör" std::vector ordinaller; // bağlı yüz ordinalleri (1-tabanlı) Vec3d merkez{}; f64 yaricap = 0; bool odakVar = false; }; struct ZekaGrup { const char* ikon = ""; std::string baslik; const char* kimlik = ""; std::vector satirlar; }; bool g_acik = false; bool g_pin = false; u32 g_govde = 0; // Async çözüm durumu: pencere/komut "sürüyor" göstergesi (bir bool — kare-başı // sorgu yok) + gövde başına iş/nesil (çifte istek → eskisi iptal, bayat sonuç çöpe). bool g_analizSuruyor = false; std::unordered_map g_zekaIs; std::unordered_map g_zekaNesil; u64 g_surum = ~0ull; // graf sürüm damgası (değişince liste tazelenir) u64 g_seciliSatir = 0; std::string g_govdeAd; size_t g_toplam = 0; std::vector g_gruplar; // Feature'ın bağlı yüz düğümleri: doğrudan "bagli" + alt düğümler (FilletZinciri // "icerir" → Fillet, Pattern "uye" → yüz/feature) üzerinden 2 seviye. void yuzTopla(const zeka::GrafDeposu& g, u64 fk, std::vector& yuzler, int derinlik) { if (const zeka::ZDugum* d = g.dugum(fk); d && d->brep.eleman == 1) { yuzler.push_back(fk); // düğümün kendisi yüz (Pattern üyeleri doğrudan yüzdür) return; } for (u64 y : g.komsular(fk, "bagli", +1)) yuzler.push_back(y); if (derinlik >= 2) return; for (u64 c : g.komsular(fk, "icerir", +1)) yuzTopla(g, c, yuzler, derinlik + 1); for (u64 c : g.komsular(fk, "uye", +1)) yuzTopla(g, c, yuzler, derinlik + 1); } std::string uz(f64 v) { return birim::bicim(v, birim::Birim::Uzunluk); } const char* delikTipTr(const std::string& t) { if (t == "kor") return "kör"; if (t == "havsa") return "havşalı"; if (t == "kademeli") return "kademeli"; return "açık"; } // Tipe göre kısa özellik metni. std::string bilgiMetni(const zeka::GrafDeposu& g, u64 fk, const std::string& tip) { std::string s; if (tip == "Delik") { s = "Ø" + uz(g.ozSayi(fk, "cap")); s += " · derinlik " + uz(g.ozSayi(fk, "derinlik")); if (const zeka::Deger* d = g.oz(fk, "tip")) if (auto* t = std::get_if(d)) s += std::string(" · ") + delikTipTr(*t); } else if (tip == "Cep") { s = "derinlik " + uz(g.ozSayi(fk, "derinlik")); s += " · alan " + birim::bicim(g.ozSayi(fk, "alan"), birim::Birim::Alan); } else if (tip == "Slot") { s = uz(g.ozSayi(fk, "uzunluk")) + " × " + uz(g.ozSayi(fk, "genislik")); s += " · derinlik " + uz(g.ozSayi(fk, "derinlik")); } else if (tip == "Boss") { s = "yükseklik " + uz(g.ozSayi(fk, "yukseklik")); s += " · alan " + birim::bicim(g.ozSayi(fk, "alan"), birim::Birim::Alan); } else if (tip == "Fillet") { s = "R" + uz(g.ozSayi(fk, "yaricap")); } else if (tip == "FilletZinciri") { s = "R" + uz(g.ozSayi(fk, "yaricap")); s += " · " + std::to_string((i64)g.ozSayi(fk, "uye_sayi")) + " üye"; s += " · boy " + uz(g.ozSayi(fk, "toplam_uzunluk")); } else if (tip == "Pah") { s = "genişlik " + uz(g.ozSayi(fk, "genislik")); } else if (tip == "Pattern") { if (const zeka::Deger* d = g.oz(fk, "tip")) if (auto* t = std::get_if(d)) s = (*t == "dairesel") ? "dairesel" : "doğrusal"; s += (s.empty() ? "" : " · ") + std::to_string((i64)g.ozSayi(fk, "adet")) + " adet"; const f64 adim = g.ozSayi(fk, "adim_boy"); if (adim > 0) s += " · adım " + uz(adim); const f64 aci = g.ozSayi(fk, "aci_adim"); if (aci > 0) s += " · adım " + birim::bicim(aci, birim::Birim::Aci); } else if (tip == "SimetriDuzlemi") { s = "guven " + birim::bicim(g.ozSayi(fk, "guven") * 100.0, birim::Birim::Oran); } else if (tip == "DfmRapor") { const i64 toplam = static_cast(g.ozSayi(fk, "toplam_sorun")); const i64 kritik = static_cast(g.ozSayi(fk, "kritik_sayi")); const i64 uyari = static_cast(g.ozSayi(fk, "uyari_sayi")); const i64 bilgi = static_cast(g.ozSayi(fk, "bilgi_sayi")); const f64 skor = g.ozSayi(fk, "risk_skoru"); char buf[128]; std::snprintf(buf, sizeof(buf), "risk %.*f · %lld sorun (%lld kritik, %lld uyari, %lld bilgi)", 0, skor, (long long)toplam, (long long)kritik, (long long)uyari, (long long)bilgi); s = buf; } else if (tip == "DfmUyari") { if (const zeka::Deger* d = g.oz(fk, "mesaj")) if (auto* t = std::get_if(d)) s = *t; if (const zeka::Deger* d = g.oz(fk, "kategori")) if (auto* t = std::get_if(d)) { if (!s.empty()) s = "[" + *t + "] " + s; else s = *t; } } return s; } void listeKur(UygulamaBaglam& b) { g_gruplar.clear(); g_toplam = 0; g_seciliSatir = 0; const zeka::GrafDeposu& g = b.zekaSis.graf; g_surum = g.surum(); const Dugum* dz = b.sahne.bul(g_govde); g_govdeAd = dz ? dz->ad : "Gövde"; struct TipTanim { const char* tip; const char* ikon; const char* cogul; const char* tekil; }; static const TipTanim tanimlar[] = { {"Delik", "🕳", "Delikler", "Delik"}, {"Cep", "▢", "Cepler", "Cep"}, {"Slot", "▭", "Slotlar", "Slot"}, {"Boss", "⏶", "Boss'lar", "Boss"}, {"FilletZinciri", "◠", "Fillet Zincirleri", "Zincir"}, {"Fillet", "◡", "Fillet'ler", "Fillet"}, {"Pah", "◣", "Pahlar", "Pah"}, {"Pattern", "⧉", "Pattern'ler", "Pattern"}, {"SimetriDuzlemi", "⇋", "Simetri Düzlemleri", "Simetri"}, {"DfmRapor", "📊", "DFM Rapor", "DFM Rapor"}, {"DfmUyari", "⚠", "DFM Uyarıları", "DFM Uyarı"}}; const u32 zincirTip = g.adBul("FilletZinciri"); for (const TipTanim& t : tanimlar) { ZekaGrup grup; grup.ikon = t.ikon; grup.kimlik = t.tip; const u32 tipId = g.adBul(t.tip); if (!tipId) continue; int sira = 0; for (u64 fk : b.zekaSis.govdeFeatureleri(g_govde)) { const zeka::ZDugum* fd = g.dugum(fk); if (!fd || fd->tip != tipId) continue; // Zincir üyesi Fillet ayrıca listelenmez (zincir satırı temsil eder). if (std::string_view(t.tip) == "Fillet" && zincirTip) { bool zincirde = false; for (u64 ust : g.komsular(fk, "icerir", -1)) { const zeka::ZDugum* ud = g.dugum(ust); if (ud && ud->tip == zincirTip) { zincirde = true; break; } } if (zincirde) continue; } ZekaSatir sat; sat.dugum = fk; sat.ad = std::string(t.tekil) + " " + std::to_string(++sira); sat.bilgi = bilgiMetni(g, fk, t.tip); std::vector yuzler; yuzTopla(g, fk, yuzler, 0); std::sort(yuzler.begin(), yuzler.end()); yuzler.erase(std::unique(yuzler.begin(), yuzler.end()), yuzler.end()); Vec3d mToplam{}; f64 alanToplam = 0; int n = 0; for (u64 y : yuzler) { const zeka::ZDugum* yd = g.dugum(y); if (!yd || yd->brep.eleman != 1 || !yd->brep.ordinal) continue; sat.ordinaller.push_back(yd->brep.ordinal); alanToplam += g.ozSayi(y, "alan"); if (const zeka::Deger* mv = g.oz(y, "merkez")) if (auto* m = std::get_if(mv)) { mToplam = mToplam + *m; ++n; } } if (n > 0) { sat.merkez = mToplam * (1.0 / n); sat.yaricap = std::max(std::sqrt(std::max(alanToplam, 1e-9)) * 1.5, 1.0); sat.odakVar = true; } grup.satirlar.push_back(std::move(sat)); } if (grup.satirlar.empty()) continue; char bas[96]; std::snprintf(bas, sizeof(bas), "%s (%d)", t.cogul, (int)grup.satirlar.size()); grup.baslik = bas; g_toplam += grup.satirlar.size(); g_gruplar.push_back(std::move(grup)); } } // Satır tıklama: bağlı yüzleri sahnede seç + kameraya odakla. void satirUygula(UygulamaBaglam& b, const ZekaSatir& s) { if (!s.ordinaller.empty()) { if (b.sahne.kip() != SecimKip::Yuz) b.sahne.kipAyarla(SecimKip::Yuz); b.sahne.secimTemizle(); for (u32 o : s.ordinaller) b.sahne.sec({g_govde, o}, true); } if (s.odakVar && b.analizSis.kameraOdak) b.analizSis.kameraOdak(s.merkez, s.yaricap); } void satirCiz(UygulamaBaglam& b, const ZekaSatir& s) { const ImVec4 SOLUK{0.55f, 0.62f, 0.66f, 1.0f}; ImGui::PushID((void*)(intptr_t)s.dugum); const ImVec2 p0 = ImGui::GetCursorScreenPos(); if (ImGui::Selectable("##sat", g_seciliSatir == s.dugum)) { g_seciliSatir = s.dugum; satirUygula(b, s); } if (ImGui::IsItemHovered() && !s.ordinaller.empty()) ImGui::SetTooltip("%d yüz seç + odakla", (int)s.ordinaller.size()); ImDrawList* dl = ImGui::GetWindowDrawList(); const float adGenis = ImGui::CalcTextSize(s.ad.c_str()).x; dl->AddText({p0.x + 6, p0.y}, ImGui::GetColorU32(ImGuiCol_Text), s.ad.c_str()); dl->AddText({p0.x + 6 + adGenis + 14, p0.y}, ImGui::GetColorU32(SOLUK), s.bilgi.c_str()); ImGui::PopID(); } } // namespace void zekaPencereAc(u32 govdeVarlik) { g_acik = true; if (govdeVarlik) g_govde = govdeVarlik; g_surum = ~0ull; // ilk çizimde liste kurulur } bool zekaCoz(Cekirdek& cekirdek, Sahne& sahne, zeka::ZekaMotoru& zekaSis, u32 govdeVarlik, std::function bitinceCb) { Dugum* dz = sahne.bul(govdeVarlik); if (!dz || !dz->brep || !dz->brep->gecerliMi()) return false; dz->brep->kimlikleriBaslat(); // KYA etiketleri ORİJİNALDE doğar (ucuz, idempotent) const auto senkron = [&] { zekaSis.govdeCoz(*dz->brep, govdeVarlik); if (bitinceCb) bitinceCb(); }; if (!zekaHesapAsync()) { // bayrak kapalı → birebir eski yol senkron(); return false; } // Derin kopya: worker paylaşılan Geom'a dokunmaz (STEP kuralı). Kopya TopExp // sırasını + üçgenlemeyi korur → ordinal-indeksli ön-veri orijinale uygulanır. auto kopya = std::make_shared(geometri::govdeDerinKopya(*dz->brep)); if (!kopya->gecerliMi()) { // kopya çıkmadı → senkron yol (davranış korunur) senkron(); return false; } kopya->kimlikleriBaslat(); // ordinal sayıları etiket dizilerinden okunur (main-thread) if (auto it = g_zekaIs.find(govdeVarlik); it != g_zekaIs.end()) cekirdek.gorevler().iptalEt(it->second); // aynı gövdeye çifte istek: eskisi çöpe const u64 nesil = ++g_zekaNesil[govdeVarlik]; auto onVeri = std::make_shared(); g_analizSuruyor = true; const u64 is = cekirdek.gorevler().kuyrukla( "Zekâ Analizi", [kopya, onVeri](GorevBaglam& gb) { if (gb.iptalIstendi()) return; *onVeri = zeka::ZekaMotoru::onVeriCikar(*kopya); }, [&sahne, &zekaSis, govdeVarlik, nesil, onVeri, bitinceCb = std::move(bitinceCb)] { if (g_zekaNesil[govdeVarlik] != nesil) return; // bayat sonuç çöpe g_zekaIs.erase(govdeVarlik); g_analizSuruyor = false; Dugum* dz = sahne.bul(govdeVarlik); if (!dz || !dz->brep || !dz->brep->gecerliMi()) return; // gövde kayboldu zekaSis.govdeCoz(*dz->brep, govdeVarlik, onVeri.get()); // artık milisaniyelik if (bitinceCb) bitinceCb(); }); g_zekaIs[govdeVarlik] = is; return true; } void zekaPenceresiCiz(UygulamaBaglam& b) { if (!g_acik) return; if (b.zekaSis.graf.surum() != g_surum) listeKur(b); // graf değişti → tazele (O(1) kontrol) ui::Pencere p{"🧠 Zekâ Analizi###zeka", &g_acik, {.boyut = {430, 0}, .minBoyut = {350, 240}, .pinDurum = &g_pin, .skin = ui::PencereSkin::WebCam}}; if (!p) return; ImGui::TextColored(ui::tema().vurgu, "%s", g_govdeAd.c_str()); ImGui::SameLine(std::max(ImGui::GetWindowWidth() - 160.0f, 120.0f)); if (ImGui::SmallButton("🔄 Yeniden Analiz")) { if (!zekaAktif()) { ui::toastGoster("Zekâ Motoru kapalı — Ayarlar → Zekâ bölümünden açın", ui::ToastTip::Uyari); } else { Dugum* dz = b.sahne.bul(g_govde); if (dz && dz->brep && dz->brep->gecerliMi()) zekaCoz(b.cekirdek, b.sahne, b.zekaSis, g_govde); // bitince sürüm değişir → liste tazelenir else ui::toastGoster("Gövde artık geçerli bir BREP taşımıyor", ui::ToastTip::Uyari); } } if (g_analizSuruyor) ImGui::TextColored(ui::tema().vurgu, "⏳ analiz sürüyor…"); ImGui::TextDisabled("Toplam %d feature · graf %u düğüm / %u ilişki", (int)g_toplam, b.zekaSis.graf.dugumSayisi(), b.zekaSis.graf.iliskiSayisi()); ImGui::Spacing(); if (g_gruplar.empty()) { ui::bilgiSeridi(0, "Feature bulunamadı — eşikleri Ayarlar → Zekâ'dan gevşetebilirsin"); return; } for (ZekaGrup& grup : g_gruplar) { if (!ui::bolum(grup.ikon, grup.baslik.c_str(), grup.kimlik)) continue; for (const ZekaSatir& s : grup.satirlar) satirCiz(b, s); } } } // namespace fiko