#include "fiko/zeka/zeka_motoru.hpp" #include "fiko/geometri/brep.hpp" #include #include #include #include #include namespace fiko::zeka { namespace { // Topoloji kurulumunun kendi yazdığı anahtarlar — her çözümde tazelenir, // miras taşımaz (govdeCoz ile senkron tutulmalı). bool standartAnahtarMi(const std::string& a) { static const char* liste[] = {"yuzey_tip", "alan", "merkez", "normal", "eksen", "eksen_nokta", "yaricap", "kucuk_yaricap", "uzunluk", "kenar_tip", "dihedral_aci", "disbukey", "dikis", "sinir_kenar", "konum"}; for (const char* s : liste) if (a == s) return true; return false; } // Feature düğümü miras kimliği: tip + bağlı yüzlerin KYA kid kümesi (sıralı) — // dedektör aynı feature'ı yeniden ürettiğinde imza değişmez, kaybolursa // eşleşme olmaz ve miras sessizce düşer (doğru davranış). std::string featureImza(const GrafDeposu& g, const ZDugum& d) { std::vector kidler; for (u64 komsu : g.komsular(d.kimlik, {}, 0)) { const ZDugum* h = g.dugum(komsu); if (h && h->brep.eleman == 1 && h->brep.kid) kidler.push_back(h->brep.kid); } std::sort(kidler.begin(), kidler.end()); kidler.erase(std::unique(kidler.begin(), kidler.end()), kidler.end()); std::string s = g.adMetin(d.tip); s += '|'; for (u64 k : kidler) { s += std::to_string(k); s += ','; } return s; } } // namespace void ZekaMotoru::dedektorEkle(std::unique_ptr d) { if (d) dedektorler_.push_back(std::move(d)); } Dedektor* ZekaMotoru::dedektor(std::string_view ad) { for (auto& d : dedektorler_) if (ad == d->ad()) return d.get(); return nullptr; } void ZekaMotoru::govdeBayatla(u64 govdeVarlik) { if (govdeKok_.count(govdeVarlik)) bayat_[govdeVarlik] = true; } bool ZekaMotoru::bayatMi(u64 govdeVarlik) const { auto it = bayat_.find(govdeVarlik); return it != bayat_.end() && it->second; } u64 ZekaMotoru::govdeKok(u64 govdeVarlik) const { auto it = govdeKok_.find(govdeVarlik); return it == govdeKok_.end() ? 0 : it->second; } void ZekaMotoru::govdeSil(u64 govdeVarlik) { auto it = govdeKok_.find(govdeVarlik); if (it == govdeKok_.end()) return; // Silinecekler: BREP'e bağlı düğümler + kökten "icerir" ile erişilen BREP'siz // düğümler (dedektörlerin ürettiği feature/analiz düğümleri köke bağlanır). std::vector silinecek = graf.govdeDugumleri(govdeVarlik); std::deque kuyruk{it->second}; std::unordered_map gezildi; while (!kuyruk.empty()) { u64 d = kuyruk.front(); kuyruk.pop_front(); if (gezildi[d]) continue; gezildi[d] = true; silinecek.push_back(d); for (u64 alt : graf.komsular(d, "icerir", +1)) kuyruk.push_back(alt); } for (u64 d : silinecek) graf.dugumSil(d); // tekrarlar zararsız (silik → false) govdeKok_.erase(it); bayat_.erase(govdeVarlik); } std::vector ZekaMotoru::govdeFeatureleri(u64 govdeVarlik) const { std::vector sonuc; auto it = govdeKok_.find(govdeVarlik); if (it == govdeKok_.end()) return sonuc; std::deque kuyruk{it->second}; std::unordered_map gezildi; while (!kuyruk.empty()) { u64 dk = kuyruk.front(); kuyruk.pop_front(); if (gezildi[dk]) continue; gezildi[dk] = true; for (u64 alt : graf.komsular(dk, "icerir", +1)) kuyruk.push_back(alt); const ZDugum* dn = graf.dugum(dk); if (dn && dn->brep.govde == 0) sonuc.push_back(dk); } return sonuc; } ZekaMotoru::MirasVeri ZekaMotoru::mirasCikar(u64 govdeVarlik) const { MirasVeri m; auto it = govdeKok_.find(govdeVarlik); if (it == govdeKok_.end()) return m; for (u64 dk : graf.govdeDugumleri(govdeVarlik)) { const ZDugum* dn = graf.dugum(dk); if (!dn || dn->brep.eleman < 1 || dn->brep.eleman > 3 || !dn->brep.kid) continue; std::vector> ozler; for (const auto& [ad, v] : dn->oz) { const std::string& metin = graf.adMetin(ad); if (!standartAnahtarMi(metin)) ozler.emplace_back(metin, v); } if (!ozler.empty()) m.eleman.emplace(((u64)dn->brep.eleman << 56) ^ dn->brep.kid, std::move(ozler)); } // Feature düğümleri: kökten "icerir" ile inen, BREP bağı olmayanlar. // Tüm özellikler saklanır — geri yazım yalnız eksik anahtara olduğu için // dedektörün taze değerleri ezilmez. Aynı imzada ilk görülen kazanır. std::deque kuyruk{it->second}; std::unordered_map gezildi; while (!kuyruk.empty()) { u64 dk = kuyruk.front(); kuyruk.pop_front(); if (gezildi[dk]) continue; gezildi[dk] = true; for (u64 alt : graf.komsular(dk, "icerir", +1)) kuyruk.push_back(alt); const ZDugum* dn = graf.dugum(dk); if (!dn || dn->brep.govde != 0 || dn->oz.empty()) continue; std::vector> ozler; ozler.reserve(dn->oz.size()); for (const auto& [ad, v] : dn->oz) ozler.emplace_back(graf.adMetin(ad), v); m.feature.emplace(featureImza(graf, *dn), std::move(ozler)); } return m; } void ZekaMotoru::mirasElemanUygula(u64 govdeVarlik, const MirasVeri& m) { for (const auto& [anahtar, ozler] : m.eleman) { const u8 eleman = (u8)(anahtar >> 56); const u64 kid = anahtar ^ ((u64)eleman << 56); u64 d = graf.brepDugum(govdeVarlik, eleman, kid); if (!d) continue; // eleman kaybolmuş — miras sessizce düşer for (const auto& [ad, v] : ozler) if (!graf.oz(d, ad)) graf.ozAyarla(d, ad, v); } } void ZekaMotoru::mirasFeatureUygula(u64 kok, const MirasVeri& m) { if (m.feature.empty()) return; std::deque kuyruk{kok}; std::unordered_map gezildi; while (!kuyruk.empty()) { u64 dk = kuyruk.front(); kuyruk.pop_front(); if (gezildi[dk]) continue; gezildi[dk] = true; for (u64 alt : graf.komsular(dk, "icerir", +1)) kuyruk.push_back(alt); const ZDugum* dn = graf.dugum(dk); if (!dn || dn->brep.govde != 0) continue; auto it = m.feature.find(featureImza(graf, *dn)); if (it == m.feature.end()) continue; for (const auto& [ad, v] : it->second) if (!graf.oz(dk, ad)) graf.ozAyarla(dk, ad, v); } } u64 ZekaMotoru::govdeCoz(geometri::BrepGovde& b, u64 govdeVarlik, const TopolojiOnVeri* onVeri, bool noktalarDahil) { const MirasVeri miras = mirasCikar(govdeVarlik); // silmeden ÖNCE ekstra özellikler govdeSil(govdeVarlik); // bayat/eski alt-graf tamamen düşer b.kimlikleriBaslat(); // KYA etiketleri BREP bağlantısının esası (idempotent) const u32 yuzSayi = (u32)b.yuzKimlikleri().size(); const u32 kenarSayi = (u32)b.kenarKimlikleri().size(); if (onVeri && !onVeri->uyumlu(yuzSayi, kenarSayi)) onVeri = nullptr; // bayat/uyumsuz ön-veri → senkron yol (davranış korunur) u64 kok = graf.dugumEkle("Govde"); graf.brepBagla(kok, {govdeVarlik, 4, 0, 0}); graf.ozAyarla(kok, "yuz_sayi", (i64)yuzSayi); // ---- Yüz düğümleri ---- std::vector yuzDugum(yuzSayi + 1, 0); // ordinal → düğüm for (u32 ord = 1; ord <= yuzSayi; ++ord) { geometri::YuzBilgi yb; if (onVeri) { if (!onVeri->yuzGecerli[ord - 1]) continue; yb = onVeri->yuzler[ord - 1]; } else if (!b.yuzBilgi(ord, yb)) continue; u64 d = graf.dugumEkle("Yuz"); yuzDugum[ord] = d; graf.brepBagla(d, {govdeVarlik, 1, b.yuzKimlik(ord), ord}); const char* tip = yb.duzlemMi ? "duzlem" : yb.silindirMi ? "silindir" : yb.kureMi ? "kure" : yb.koniMi ? "koni" : yb.torusMu ? "torus" : "serbest"; graf.ozAyarla(d, "yuzey_tip", std::string(tip)); graf.ozAyarla(d, "alan", yb.alan); graf.ozAyarla(d, "merkez", yb.merkez); if (yb.duzlemMi) graf.ozAyarla(d, "normal", yb.normal); if (yb.silindirMi || yb.koniMi || yb.kureMi || yb.torusMu) { graf.ozAyarla(d, "eksen", yb.eksen); graf.ozAyarla(d, "eksen_nokta", yb.eksenNokta); graf.ozAyarla(d, "yaricap", yb.yaricap); if (yb.torusMu) graf.ozAyarla(d, "kucuk_yaricap", yb.kucukYaricap); } graf.iliskiEkle("icerir", kok, d); } // ---- Kenar düğümleri + sinir/komsu ilişkileri ---- // Tekil kenarKomsuYuzler O(E·(E+F²)) — toplu tarama şart (brep.hpp notu). // Ordinal uzayı paylaşılan kenarı İKİ kez sayar (depo değişmezi) — fiziksel // kenar tek düğüm olsun diye keskin_kenar kalıbı: yüz-çifti + kuantalanmış // orta nokta anahtarıyla tekilleştirilir. const auto komsuYuzlerYerel = onVeri ? std::vector>{} : b.tumKenarKomsuYuzler(); const auto& komsuYuzler = onVeri ? onVeri->kenarKomsuYuzler : komsuYuzlerYerel; std::set> gorulenKenar; u32 tekilKenar = 0; for (u32 ord = 1; ord <= kenarSayi; ++ord) { geometri::KenarBilgi kb; if (onVeri) { if (!onVeri->kenarGecerli[ord - 1]) continue; kb = onVeri->kenarlar[ord - 1]; } else if (!b.kenarBilgi(ord, kb)) continue; { u32 fa = 0, fb = 0; if (ord <= komsuYuzler.size() && !komsuYuzler[ord - 1].empty()) { const auto& v = komsuYuzler[ord - 1]; fa = *std::min_element(v.begin(), v.end()); fb = *std::max_element(v.begin(), v.end()); } const auto q = [](f64 v) { return (i64)std::llround(v * 1e4); }; // 0.1 µm if (!gorulenKenar.insert({fa, fb, q(kb.orta.x), q(kb.orta.y), q(kb.orta.z)}).second) continue; // aynı fiziksel kenarın ikinci occurrence'ı } ++tekilKenar; u64 d = graf.dugumEkle("Kenar"); graf.brepBagla(d, {govdeVarlik, 2, b.kenarKimlik(ord), ord}); graf.ozAyarla(d, "uzunluk", kb.uzunluk); graf.ozAyarla(d, "kenar_tip", std::string(kb.dogruMu ? "dogru" : kb.cemberMi ? "cember" : "egri")); if (kb.cemberMi) graf.ozAyarla(d, "yaricap", kb.yaricap); graf.iliskiEkle("icerir", kok, d); // Komşu yüzler (seam kenarında aynı yüz iki kez gelir → tekilleştir) std::vector yuzler; u32 hamSayi = 0; // dikiş (seam) kenarında aynı yüz iki kez gelir if (ord <= komsuYuzler.size()) { hamSayi = (u32)komsuYuzler[ord - 1].size(); for (u32 f : komsuYuzler[ord - 1]) if (std::find(yuzler.begin(), yuzler.end(), f) == yuzler.end()) yuzler.push_back(f); } for (u32 f : yuzler) if (f <= yuzSayi && yuzDugum[f]) graf.iliskiEkle("sinir", d, yuzDugum[f]); if (yuzler.size() >= 2) { const geometri::KenarDihedralBilgi dh = onVeri ? onVeri->dihedraller[ord - 1] : b.kenarDihedral(ord, yuzler[0], yuzler[1]); if (dh.gecerli) { graf.ozAyarla(d, "dihedral_aci", dh.aciDeg); graf.ozAyarla(d, "disbukey", dh.disbukey); } // Yüz-yüz komşuluğu materyalize: gezinti 2 atlama yerine tek atlama, // paylaşılan kenar ilişki özelliğinde taşınır. if (yuzDugum[yuzler[0]] && yuzDugum[yuzler[1]]) { u64 il = graf.iliskiEkle("komsu", yuzDugum[yuzler[0]], yuzDugum[yuzler[1]]); graf.iliskiOzAyarla(il, "kenar", (i64)d); } } else if (hamSayi >= 2) { graf.ozAyarla(d, "dikis", true); // seam: aynı yüz iki kez (silindir kapanışı) } else { graf.ozAyarla(d, "sinir_kenar", true); // serbest/sınır kenar (açık kabuk) } } graf.ozAyarla(kok, "kenar_sayi", (i64)tekilKenar); // fiziksel (tekil) kenar sayısı // ---- Nokta düğümleri (istenirse — dev gövdede şişmesin diye varsayılan kapalı) ---- if (noktalarDahil) { const u32 noktaSayi = (u32)b.noktaKimlikleri().size(); for (u32 ord = 1; ord <= noktaSayi; ++ord) { Vec3d konum; if (!b.noktaKonum(ord, konum)) continue; u64 d = graf.dugumEkle("Nokta"); graf.brepBagla(d, {govdeVarlik, 3, b.noktaKimlik(ord), ord}); graf.ozAyarla(d, "konum", konum); graf.iliskiEkle("icerir", kok, d); } } govdeKok_[govdeVarlik] = kok; bayat_[govdeVarlik] = false; // Yüz/kenar/nokta mirası dedektörlerden ÖNCE — dedektör taşınan özelliği görür mirasElemanUygula(govdeVarlik, miras); // ---- Dedektörler (feature/üretim/analiz katmanları) ---- DedektorBaglam baglam{b, govdeVarlik, kok, graf, onVeri}; for (auto& det : dedektorler_) if (det->aktif) det->calistir(baglam); mirasFeatureUygula(kok, miras); if (grafGuncellendi) grafGuncellendi(govdeVarlik); return kok; } TopolojiOnVeri ZekaMotoru::onVeriCikar(const geometri::BrepGovde& b) { TopolojiOnVeri v; if (!b.gecerliMi()) return v; const u32 yuzSayi = (u32)b.yuzKimlikleri().size(); const u32 kenarSayi = (u32)b.kenarKimlikleri().size(); v.yuzler.resize(yuzSayi); v.yuzGecerli.assign(yuzSayi, 0); for (u32 ord = 1; ord <= yuzSayi; ++ord) if (b.yuzBilgi(ord, v.yuzler[ord - 1])) v.yuzGecerli[ord - 1] = 1; v.kenarlar.resize(kenarSayi); v.kenarGecerli.assign(kenarSayi, 0); for (u32 ord = 1; ord <= kenarSayi; ++ord) if (b.kenarBilgi(ord, v.kenarlar[ord - 1])) v.kenarGecerli[ord - 1] = 1; v.kenarKomsuYuzler = b.tumKenarKomsuYuzler(); // Dihedral: govdeCoz ile AYNI sıra/tekilleştirme (ilk iki FARKLI komşu yüz). v.dihedraller.resize(kenarSayi); for (u32 ord = 1; ord <= kenarSayi && ord <= v.kenarKomsuYuzler.size(); ++ord) { std::vector yuzler; for (u32 f : v.kenarKomsuYuzler[ord - 1]) if (std::find(yuzler.begin(), yuzler.end(), f) == yuzler.end()) yuzler.push_back(f); if (yuzler.size() >= 2) v.dihedraller[ord - 1] = b.kenarDihedral(ord, yuzler[0], yuzler[1]); } // Silindir yüz örnekleri: delik dedektörünün iç/dış kararı + derinlik ölçümü. // Mesh yoksa (yuzNoktalari boş) kayıt açılmaz → dedektör eski BREP yoluna düşer. for (u32 ord = 1; ord <= yuzSayi; ++ord) { if (!v.yuzGecerli[ord - 1] || !v.yuzler[ord - 1].silindirMi) continue; auto noktalar = b.yuzNoktalari(ord); if (noktalar.empty()) continue; TopolojiOnVeri::SilindirOrnek so; so.normaller.resize(noktalar.size()); so.normalVar.assign(noktalar.size(), 0); for (size_t i = 0; i < noktalar.size(); ++i) if (b.yuzNoktaNormali(ord, noktalar[i], so.normaller[i])) so.normalVar[i] = 1; so.noktalar = std::move(noktalar); v.silindirOrnekleri.emplace(ord, std::move(so)); } return v; } } // namespace fiko::zeka