#include "fiko/geometri/brep.hpp" #include "fiko/zeka/dedektor.hpp" #include "fiko/zeka/dedektorler.hpp" #include "fiko/zeka/sorgu.hpp" #include "fiko/zeka/zeka_motoru.hpp" #include #include #include #include namespace fiko::zeka { namespace { const std::string* ozMetin(const GrafDeposu& g, u64 dugum, std::string_view anahtar) { const Deger* v = g.oz(dugum, anahtar); return v ? std::get_if(v) : nullptr; } bool ozVec3(const GrafDeposu& g, u64 dugum, std::string_view anahtar, Vec3d& sonuc) { const Deger* v = g.oz(dugum, anahtar); if (!v) return false; if (const Vec3d* p = std::get_if(v)) { sonuc = *p; return true; } return false; } bool ozBool(const GrafDeposu& g, u64 dugum, std::string_view anahtar, bool& sonuc) { const Deger* v = g.oz(dugum, anahtar); if (!v) return false; if (const bool* p = std::get_if(v)) { sonuc = *p; return true; } return false; } f64 parcaMesafeKare(Vec3d p, Vec3d a, Vec3d b) { const Vec3d ab = b - a; const f64 uk = ab.uzunlukKare(); if (uk < 1e-18) return (p - a).uzunlukKare(); const f64 t = std::clamp((p - a).nokta(ab) / uk, 0.0, 1.0); return (p - (a + ab * t)).uzunlukKare(); } // Kapali polyline uzerinde mi (son nokta ilkine ortuk bagli — yuzKonturlari kurali). bool konturUzerinde(const std::vector& kontur, Vec3d p, f64 tol) { const f64 tolKare = tol * tol; for (size_t i = 0; i < kontur.size(); ++i) if (parcaMesafeKare(p, kontur[i], kontur[(i + 1) % kontur.size()]) < tolKare) return true; return false; } // Dis konturun duzlem-ici sinir kutusu. Eksen hizasiz slot AABB'de sismesin diye // en uzun parca yonu yerel eksen alinir. bool konturBbox(const std::vector& kontur, Vec3d normal, f64& uzun, f64& genis) { if (kontur.size() < 3) return false; Vec3d enParca{}; f64 enKare = 0; for (size_t i = 0; i < kontur.size(); ++i) { const Vec3d f = kontur[(i + 1) % kontur.size()] - kontur[i]; const f64 uk = f.uzunlukKare(); if (uk > enKare) { enKare = uk; enParca = f; } } if (enKare < 1e-12) return false; const Vec3d u = enParca.birim(); const Vec3d v = normal.capraz(u).birim(); f64 u0 = 1e300, u1 = -1e300, v0 = 1e300, v1 = -1e300; for (const Vec3d& p : kontur) { const f64 pu = p.nokta(u), pv = p.nokta(v); u0 = std::min(u0, pu); u1 = std::max(u1, pu); v0 = std::min(v0, pv); v1 = std::max(v1, pv); } uzun = std::max(u1 - u0, v1 - v0); genis = std::min(u1 - u0, v1 - v0); return genis > 1e-9; } struct SinirKenar { u64 kenar = 0; u64 karsiYuz = 0; Vec3d karsiMerkez{}; bool icbukey = false; }; bool kenarOrta(const DedektorBaglam& b, const GrafDeposu& g, u64 kenarDugum, Vec3d& orta) { const ZDugum* kd = g.dugum(kenarDugum); if (!kd || kd->brep.ordinal == 0) return false; const u32 ord = kd->brep.ordinal; if (b.onVeri && ord <= b.onVeri->kenarlar.size() && b.onVeri->kenarGecerli[ord - 1]) { orta = b.onVeri->kenarlar[ord - 1].orta; // worker'da toplandı — OCCT okuması yok return true; } geometri::KenarBilgi kb; if (!b.brep.kenarBilgi(ord, kb)) return false; orta = kb.orta; return true; } bool duvardaIcbukeyVar(const GrafDeposu& g, u64 yuz) { for (u64 k : g.komsular(yuz, "sinir", -1)) { bool dis = true; if (ozBool(g, k, "disbukey", dis) && !dis) return true; } return false; } } // namespace // ============================================================================ // CepDedektor — cep / slot / boss tanıma. Karar tamamen grafın BREP verisinden // (disbukey, yüz tip/merkez/normal); mesh yok. Kontur yalnız dış/iç kenar ayrımı // ve slot oranı için (o da BREP'ten örneklenir). // Cep : dış konturu içbükey kenarlı düzlem taban; içbükey olmayan dış kenara // yalnız komşusu taban düzleminin ALTINDA ise izin → boydan kanal / // açık cep de Cep sayılır (ayrı tip değil — bilinçli karar). // Slot: cep alt türü — dış kontur uzun/dar ya da ≥2 silindir duvarlı. // Boss: tüm kenarları dışbükey küçük düzlem ada; her duvarı gövdeye içbükey // basar (kutunun kendi dış yüzleri böylece elenir). // ============================================================================ struct CepDedektor final : public Dedektor { // Faz 2'de AyarSistemi'ne bağlanacak (ayar_kayitlari.cpp kalıbı) f64 slotOranEsik = 3.0; // dış kontur uzun/geniş > eşik → Slot f64 bossAlanOranEsik = 0.5; // tepe alanı / gövdenin en büyük yüz alanı f64 bossYukseklikTol = 0.25; // duvar yükseklikleri göreli sapması (tek yükseklik halkası) const char* ad() const override { return "cep"; } const char* katman() const override { return "feature"; } void esikAyarla(std::string_view anahtar, f64 deger) override { if (anahtar == "slot_oran") slotOranEsik = deger; else if (anahtar == "boss_alan_oran") bossAlanOranEsik = deger; } void calistir(DedektorBaglam& b) override { GrafDeposu& g = b.graf; const auto yuzler = Sorgu(g).tip("Yuz").govdede(b.govdeVarlik).bul(); f64 enBuyukAlan = 0; for (u64 y : yuzler) enBuyukAlan = std::max(enBuyukAlan, g.ozSayi(y, "alan")); for (u64 y : yuzler) { const std::string* yuzeyTip = ozMetin(g, y, "yuzey_tip"); if (!yuzeyTip || *yuzeyTip != "duzlem") continue; // MVP: yalnız düzlem taban/tepe u32 ordinal = 0; // ZDugum* dugumEkle ile geçersizleşir — ordinal hemen kopyalanır, pointer tutulmaz if (const ZDugum* yd = g.dugum(y)) ordinal = yd->brep.ordinal; if (ordinal == 0) continue; Vec3d normal{}, merkez{}; if (!ozVec3(g, y, "normal", normal) || !ozVec3(g, y, "merkez", merkez)) continue; normal = normal.birim(); if (normal.uzunlukKare() < 0.5) continue; // Sınır kenarları: hepsi dihedral-tanımlı olmalı (seam / açık kabuk → aday değil) std::vector kenarlar; bool tanimli = true; u32 icbukeySayi = 0; for (u64 k : g.komsular(y, "sinir", -1)) { bool dis = true; if (!ozBool(g, k, "disbukey", dis)) { tanimli = false; break; } u64 karsi = 0; for (u64 f : g.komsular(k, "sinir", +1)) if (f != y) karsi = f; Vec3d karsiMerkez{}; if (!karsi || !ozVec3(g, karsi, "merkez", karsiMerkez)) { tanimli = false; break; } kenarlar.push_back({k, karsi, karsiMerkez, !dis}); if (!dis) ++icbukeySayi; } if (!tanimli || kenarlar.empty()) continue; if (icbukeySayi == 0) bossDene(b, y, normal, merkez, kenarlar, enBuyukAlan); else if (icbukeySayi >= 2) cepDene(b, y, ordinal, normal, merkez, kenarlar); // tek içbükey kenarlı yüz ne cep tabanı ne boss tepesidir (kanal duvarı vb.) } } private: void cepDene(DedektorBaglam& b, u64 taban, u32 ordinal, Vec3d n, Vec3d merkez, const std::vector& kenarlar) { GrafDeposu& g = b.graf; // Ağız yönü: duvarlar +n tarafında kalacak şekilde yönlendir (OCCT yüz // yönelimine bel bağlanmaz) f64 yon = 0; for (const auto& k : kenarlar) if (k.icbukey) yon += (k.karsiMerkez - merkez).nokta(n); if (yon < 0) n = -n; const auto konturlar = b.brep.yuzKonturlari(ordinal); if (konturlar.empty()) return; const std::vector& disKontur = konturlar[0]; const bool cokKontur = konturlar.size() > 1; // Dış kontur kuralı: içbükey olmayan dış kenara yalnız komşusu taban // düzleminin ALTINDA ise izin (boydan kanal / açık cep ucu). İç kontur // kenarları (taban içindeki delik/ada ağzı) cep kararını bozmaz. u32 disIcbukey = 0; for (const auto& k : kenarlar) { bool dista = true; if (cokKontur) { Vec3d orta{}; if (!kenarOrta(b, g, k.kenar, orta)) return; dista = konturUzerinde(disKontur, orta, 0.2); } if (!dista) continue; if (k.icbukey) ++disIcbukey; else if ((k.karsiMerkez - merkez).nokta(n) > -1e-6) return; // dışbükey dış kenar üstte/aynı düzeyde kalan yüze açılıyor → taban değil } if (disIcbukey < 2) return; // Duvarlar (tekil) + derinlik: dik duvar merkezi taban düzleminden yarı // yükseklikte durur → 2× dik mesafe std::vector duvarlar; f64 enDerin = 0; u32 silindirDuvar = 0, duzlemDuvar = 0; for (const auto& k : kenarlar) { if (!k.icbukey) continue; if (std::find(duvarlar.begin(), duvarlar.end(), k.karsiYuz) != duvarlar.end()) continue; duvarlar.push_back(k.karsiYuz); enDerin = std::max(enDerin, (k.karsiMerkez - merkez).nokta(n)); if (const std::string* dt = ozMetin(g, k.karsiYuz, "yuzey_tip")) { if (*dt == "silindir") ++silindirDuvar; else if (*dt == "duzlem") ++duzlemDuvar; } } const f64 derinlik = 2 * enDerin; if (derinlik < 1e-6 || duvarlar.empty()) return; f64 uzun = 0, genis = 0; const bool bboxVar = konturBbox(disKontur, n, uzun, genis); const bool slot = (bboxVar && uzun > slotOranEsik * genis) || (silindirDuvar >= 2 && duzlemDuvar <= 2); const u64 f = g.dugumEkle(slot ? "Slot" : "Cep"); g.ozAyarla(f, "alan", g.ozSayi(taban, "alan")); g.ozAyarla(f, "derinlik", derinlik); g.ozAyarla(f, "uretim_tipi", std::string("cep_frezeleme")); if (slot && bboxVar) { g.ozAyarla(f, "uzunluk", uzun); g.ozAyarla(f, "genislik", genis); } g.iliskiEkle("icerir", b.govdeDugum, f); u64 il = g.iliskiEkle("bagli", f, taban); g.iliskiOzAyarla(il, "rol", std::string("taban")); for (u64 d : duvarlar) { il = g.iliskiEkle("bagli", f, d); g.iliskiOzAyarla(il, "rol", std::string("duvar")); } } void bossDene(DedektorBaglam& b, u64 tepe, Vec3d n, Vec3d merkez, const std::vector& kenarlar, f64 enBuyukAlan) { GrafDeposu& g = b.graf; const f64 alan = g.ozSayi(tepe, "alan"); // Küçük ada şartı: gövdenin en büyük yüzüne yakın/eşit tepe = dış kabuk yüzü if (enBuyukAlan <= 0 || alan >= bossAlanOranEsik * enBuyukAlan) return; std::vector duvarlar; std::vector duvarMerkez; f64 yon = 0; for (const auto& k : kenarlar) { if (std::find(duvarlar.begin(), duvarlar.end(), k.karsiYuz) != duvarlar.end()) continue; duvarlar.push_back(k.karsiYuz); duvarMerkez.push_back(k.karsiMerkez); yon += (k.karsiMerkez - merkez).nokta(n); } if (duvarlar.empty()) return; if (yon > 0) n = -n; // tepe normali gövdeden dışa baksın (duvarlar -n tarafında) // Her duvar gövde ana kütlesine İÇBÜKEY basmalı (kutunun kendi dış yüzleri // burada elenir) + duvarlar tek yükseklikte kapalı halka olmalı f64 hEnAz = 1e300, hEnCok = 0; for (size_t i = 0; i < duvarlar.size(); ++i) { if (!duvardaIcbukeyVar(g, duvarlar[i])) return; const f64 h = 2 * (merkez - duvarMerkez[i]).nokta(n); if (h < 1e-6) return; hEnAz = std::min(hEnAz, h); hEnCok = std::max(hEnCok, h); } if (hEnCok - hEnAz > bossYukseklikTol * hEnCok) return; const u64 f = g.dugumEkle("Boss"); g.ozAyarla(f, "alan", alan); g.ozAyarla(f, "yukseklik", hEnCok); g.iliskiEkle("icerir", b.govdeDugum, f); u64 il = g.iliskiEkle("bagli", f, tepe); g.iliskiOzAyarla(il, "rol", std::string("tepe")); for (u64 d : duvarlar) { il = g.iliskiEkle("bagli", f, d); g.iliskiOzAyarla(il, "rol", std::string("duvar")); } } }; std::unique_ptr cepDedektoru() { return std::make_unique(); } } // namespace fiko::zeka