#include "fiko/zeka/dedektorler.hpp" #include "fiko/zeka/dedektor.hpp" #include "fiko/zeka/sorgu.hpp" #include #include #include #include namespace fiko::zeka { namespace { // ============================================================================ // Fillet + Pah dedektörleri — topoloji katmanı grafından okur (BREP kararları // zeka_motoru.cpp'de OCCT'den yazılmıştır; burada mesh/tessellation YOK). // Teğetlik kenar düğümlerindeki dihedral_aci'dan okunur: bilgi grafta hazır, // yüz başına ekstra BREP taraması (tanjantYuzler) gerekmez. // ============================================================================ const std::string* yuzeyTip(const GrafDeposu& g, u64 yuz) { const Deger* d = g.oz(yuz, "yuzey_tip"); return d ? std::get_if(d) : nullptr; } // "sinir" ilişkisi kenar→yüz yönündedir; yüzden bakınca giren komşular kenarlardır. std::vector yuzKenarlari(const GrafDeposu& g, u64 yuz) { return g.komsular(yuz, "sinir", -1); } // Dikiş/sınır kenarlarda dihedral_aci yoktur → false. bool kenarAci(const GrafDeposu& g, u64 kenar, f64& aci) { const Deger* d = g.oz(kenar, "dihedral_aci"); return d && degerSayi(*d, aci); } class FilletDedektor final : public Dedektor { public: // Eşikler PUBLIC — Faz 2'de AyarSistemi'ne bağlanır (zeka.fillet.* kayıtları). f64 tegetAciTolDeg = 5.0; // dihedral <= tol → teğet (G1) bağlantı f64 yaricapUyumTol = 0.05; // zincirde komşu üyeler arası R farkı (mm, mutlak) const char* ad() const override { return "fillet"; } const char* katman() const override { return "feature"; } void esikAyarla(std::string_view anahtar, f64 deger) override { if (anahtar == "teget_aci_tol") tegetAciTolDeg = deger; else if (anahtar == "yaricap_uyum_tol") yaricapUyumTol = deger; } void calistir(DedektorBaglam& b) override { GrafDeposu& g = b.graf; // ---- 1) Aday yüzler: silindir şerit / torus köşe dönüşü / küre köşe blend'i. // Küre listede çünkü OCCT iki-kenar köşe blend'inde KÜRE yaması üretir // (kutu üst çevre filleti) — küresiz zincir köşede kopar. std::vector uyeYuz; std::vector uyeR; std::vector uyeBoy; // ortalama teğet kenar uzunluğu ≈ şerit boyu std::unordered_map yuzIndeks; for (u64 y : Sorgu(g).tip("Yuz").govdede(b.govdeVarlik).bul()) { const std::string* tip = yuzeyTip(g, y); if (!tip) continue; const bool silindir = *tip == "silindir"; const bool torus = *tip == "torus"; const bool kure = *tip == "kure"; if (!silindir && !torus && !kure) continue; u32 tegetSayi = 0; bool dikisVar = false; f64 tegetBoy = 0; for (u64 k : yuzKenarlari(g, y)) { if (g.oz(k, "dikis")) dikisVar = true; f64 aci; if (kenarAci(g, k, aci) && aci <= tegetAciTolDeg) { ++tegetSayi; tegetBoy += g.ozSayi(k, "uzunluk"); } } // Delik/boss duvarı TAM silindir (dikiş kenarlı); fillet şeridi kısmi yay. // Torus'ta dikiş normaldir (tam-tur çevre filleti) → yalnız silindirde ele. if (silindir && dikisVar) continue; // Fillet iki uzun kenarıyla komşularına teğet bağlanır; tek teğet kenarlı // hemisfer kapak / teğet dokunuşlu sıradan yüzey burada elenir. if (tegetSayi < 2) continue; const f64 r = torus ? g.ozSayi(y, "kucuk_yaricap") : g.ozSayi(y, "yaricap"); if (r <= 0) continue; yuzIndeks[y] = (u32)uyeYuz.size(); uyeYuz.push_back(y); uyeR.push_back(r); uyeBoy.push_back(tegetBoy / tegetSayi); } if (uyeYuz.empty()) return; // ---- 2) Fillet düğümleri ---- std::vector filletDugum(uyeYuz.size()); for (u32 i = 0; i < (u32)uyeYuz.size(); ++i) { u64 f = g.dugumEkle("Fillet"); g.ozAyarla(f, "yaricap", uyeR[i]); g.iliskiEkle("bagli", f, uyeYuz[i]); g.iliskiEkle("icerir", b.govdeDugum, f); filletDugum[i] = f; } // ---- 3) Zincir: teğet paylaşılan kenar + uyumlu R → union-find ---- std::vector ebeveyn(uyeYuz.size()); for (u32 i = 0; i < (u32)ebeveyn.size(); ++i) ebeveyn[i] = i; auto kok = [&](u32 i) { while (ebeveyn[i] != i) { ebeveyn[i] = ebeveyn[ebeveyn[i]]; i = ebeveyn[i]; } return i; }; const u32 komsuTip = g.adBul("komsu"); for (u32 i = 0; i < (u32)uyeYuz.size(); ++i) { for (u64 ilId : g.dugumIliskileri(uyeYuz[i], 0)) { const ZIliski* il = g.iliski(ilId); if (!il || il->tip != komsuTip) continue; const u64 diger = il->kaynak == uyeYuz[i] ? il->hedef : il->kaynak; auto it = yuzIndeks.find(diger); if (it == yuzIndeks.end()) continue; if (std::abs(uyeR[i] - uyeR[it->second]) > yaricapUyumTol) continue; // Paylaşılan kenara TEĞETLİK ŞARTI YOK: OCCT çevre halkasında köşeye top // yaması koymayabiliyor — silindir şeritler ~90° kenarla doğrudan buluşuyor // (kutu üst çevresinde 88.3° ölçüldü). Fillet-fillet komşuluğu + R uyumu // zincir için yeterli (CATIA çevre halkası tek zincirdir). const u32 a = kok(i), c = kok(it->second); if (a != c) ebeveyn[a] = c; } } // ---- 4) >=2 üyeli bileşen → FilletZinciri ---- std::unordered_map> bilesen; for (u32 i = 0; i < (u32)uyeYuz.size(); ++i) bilesen[kok(i)].push_back(i); for (auto& [temsilci, uyeler] : bilesen) { (void)temsilci; if (uyeler.size() < 2) continue; u64 z = g.dugumEkle("FilletZinciri"); f64 rToplam = 0, boy = 0; for (u32 i : uyeler) { rToplam += uyeR[i]; boy += uyeBoy[i]; g.iliskiEkle("icerir", z, filletDugum[i]); } g.ozAyarla(z, "yaricap", rToplam / (f64)uyeler.size()); g.ozAyarla(z, "uye_sayi", (i64)uyeler.size()); g.ozAyarla(z, "toplam_uzunluk", boy); g.iliskiEkle("icerir", b.govdeDugum, z); } } }; class PahDedektor final : public Dedektor { public: // Eşikler PUBLIC — Faz 2'de AyarSistemi'ne bağlanır (zeka.pah.* kayıtları). // Graftaki dihedral_aci normaller arası açıdır: 45° pahın iç açısı ~135°, // normal açısı ~45° — aralık 30/60 gibi asimetrik pahları da kapsar. f64 aciEnAzDeg = 20.0; f64 aciEnCokDeg = 70.0; f64 seritOranEnCok = 0.25; // alan / (en uzun kenar)² — şerit darlığı const char* ad() const override { return "pah"; } const char* katman() const override { return "feature"; } void esikAyarla(std::string_view anahtar, f64 deger) override { if (anahtar == "serit_oran") seritOranEnCok = deger; } void calistir(DedektorBaglam& b) override { GrafDeposu& g = b.graf; for (u64 y : Sorgu(g).tip("Yuz").govdede(b.govdeVarlik) .ozEsit("yuzey_tip", std::string("duzlem")).bul()) { f64 enUzun = 0, enKisa = 1e300; u32 egikKenar = 0; for (u64 k : yuzKenarlari(g, y)) { const f64 u = g.ozSayi(k, "uzunluk"); if (u > enUzun) enUzun = u; if (u > 0 && u < enKisa) enKisa = u; f64 aci; if (kenarAci(g, k, aci) && aci >= aciEnAzDeg && aci <= aciEnCokDeg) ++egikKenar; } if (enUzun <= 0) continue; const f64 alan = g.ozSayi(y, "alan"); if (alan <= 0 || alan / (enUzun * enUzun) > seritOranEnCok) continue; // Pah şeridi iki uzun kenarıyla komşularına eğik (~45°) bağlanır; // uç kenarları dik kalır — tek eğik kenarlı düzlemler (draft vb.) elenir. if (egikKenar < 2) continue; u64 p = g.dugumEkle("Pah"); g.ozAyarla(p, "genislik", enKisa); // dar kenar ≈ pah şerit genişliği g.iliskiEkle("bagli", p, y); g.iliskiEkle("icerir", b.govdeDugum, p); } } }; } // namespace std::unique_ptr filletDedektoru() { return std::make_unique(); } std::unique_ptr pahDedektoru() { return std::make_unique(); } } // namespace fiko::zeka