#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 #include #include namespace fiko::zeka { namespace { // ============================================================================ // DelikDedektor — silindirik İÇ yüzeylerden "Delik" feature düğümleri kurar. // Karar tamamen BREP + graf (mesh'ten karar yok): iç/dış ayrımı gerçek yüzey // normalinden (yuzNoktaNormali), eşeksenli kademeli zincir graf komşuluğundan. // Kenar tekilleştirmesini topoloji katmanı zaten yaptı — graftan gezilir, // ordinal uzayından değil. // ============================================================================ struct SilindirAday { u64 dugum = 0; u32 ordinal = 0; f64 yaricap = 0; Vec3d eksen{}; // birim Vec3d eksenNokta{}; }; // Async ön-veride bu yüzün hazır örnekleri (yoksa nullptr → BREP yolu). const TopolojiOnVeri::SilindirOrnek* onVeriOrnek(const DedektorBaglam& b, u32 ordinal) { if (!b.onVeri) return nullptr; const auto it = b.onVeri->silindirOrnekleri.find(ordinal); return (it != b.onVeri->silindirOrnekleri.end() && !it->second.noktalar.empty()) ? &it->second : nullptr; } // Kenar bilgisi: onVeri varsa ondan (worker'da toplandı), yoksa BREP (eski yol). bool kenarBilgiOku(const DedektorBaglam& b, u32 ord, geometri::KenarBilgi& kb) { if (b.onVeri && ord && ord <= b.onVeri->kenarlar.size() && b.onVeri->kenarGecerli[ord - 1]) { kb = b.onVeri->kenarlar[ord - 1]; return true; } return b.brep.kenarBilgi(ord, kb); } // Yüzey üzerinde örnek noktalar. Önce async ön-veri; üçgenleme yoksa (salt-geometri // birim testi) sınır kenarlarından TAM geometri örnekleri alınır — mesh bağımlılığı yok. std::vector yuzOrnekleri(const DedektorBaglam& b, const GrafDeposu& g, u64 yuzDugum, u32 ordinal) { if (const auto* so = onVeriOrnek(b, ordinal)) return so->noktalar; auto noktalar = b.brep.yuzNoktalari(ordinal); if (!noktalar.empty()) return noktalar; for (u64 k : g.komsular(yuzDugum, "sinir", -1)) { const ZDugum* kd = g.dugum(k); if (!kd || !kd->brep.ordinal) continue; geometri::KenarBilgi kb; if (!kenarBilgiOku(b, kd->brep.ordinal, kb)) continue; noktalar.push_back(kb.bas); noktalar.push_back(kb.orta); noktalar.push_back(kb.son); } return noktalar; } class DelikDedektor final : public Dedektor { public: // Eşikler PUBLIC — Faz 2'de AyarSistemi'ne bağlanacak (ayar_kayitlari.cpp kalıbı) f64 eksenAciTolDeg = 1.0; // eşeksenlilik: eksen yönleri arası maks açı f64 eksenMesafeTol = 0.05; // mm — eksen doğruları arası maks kaçıklık f64 tabanAlanOran = 1.5; // düzlem alanı <= pi*r²*oran → delik içi yüz (taban/omuz) f64 capTol = 1e-3; // mm — kademe sayılması için çap farkı eşiği const char* ad() const override { return "delik"; } void calistir(DedektorBaglam& b) override; private: bool esYonlu(Vec3d a, Vec3d b) const { return std::abs(a.nokta(b)) >= std::cos(eksenAciTolDeg * std::numbers::pi_v / 180.0); } bool esEksenli(Vec3d eksenA, Vec3d noktaA, Vec3d eksenB, Vec3d noktaB) const { if (!esYonlu(eksenA, eksenB)) return false; const Vec3d fark = noktaB - noktaA; return (fark - eksenA * fark.nokta(eksenA)).uzunluk() <= eksenMesafeTol; } }; void DelikDedektor::calistir(DedektorBaglam& b) { GrafDeposu& g = b.graf; const f64 pi = std::numbers::pi_v; const auto ozVec = [&g](u64 d, const char* anahtar, Vec3d& v) { const Deger* p = g.oz(d, anahtar); if (!p || !std::holds_alternative(*p)) return false; v = std::get(*p); return true; }; const auto ozMetin = [&g](u64 d, const char* anahtar) -> std::string { const Deger* p = g.oz(d, anahtar); return (p && std::holds_alternative(*p)) ? std::get(*p) : std::string{}; }; // ---- 1) İç (delik duvarı) silindir yüzleri ---- // Dışa-bakan gerçek normal eksene DOĞRU bakıyorsa iç yüzey = delik duvarı; // dışa bakıyorsa boss — atlanır (cep/boss dedektörünün işi, Delik düğümü yok). std::vector icler; for (u64 y : Sorgu(g).tip("Yuz").govdede(b.govdeVarlik) .ozEsit("yuzey_tip", std::string("silindir")).bul()) { const ZDugum* d = g.dugum(y); if (!d || !d->brep.ordinal) continue; SilindirAday a; a.dugum = y; a.ordinal = d->brep.ordinal; a.yaricap = g.ozSayi(y, "yaricap"); if (a.yaricap <= 0) continue; if (!ozVec(y, "eksen", a.eksen) || !ozVec(y, "eksen_nokta", a.eksenNokta)) continue; a.eksen = a.eksen.birim(); if (a.eksen.uzunlukKare() < 0.5) continue; bool ic = false, karar = false; if (const auto* so = onVeriOrnek(b, a.ordinal)) { // Normal çiftleri worker'da hazırlandı — main-thread OCCT okuması yok. for (size_t i = 0; i < so->noktalar.size(); ++i) { const Vec3d v = so->noktalar[i] - a.eksenNokta; const Vec3d radyal = v - a.eksen * v.nokta(a.eksen); if (radyal.uzunlukKare() < 1e-12) continue; if (!so->normalVar[i] || so->normaller[i].uzunlukKare() < 1e-12) continue; ic = so->normaller[i].nokta(radyal) < 0; karar = true; break; } } else { for (const Vec3d& p : yuzOrnekleri(b, g, y, a.ordinal)) { const Vec3d v = p - a.eksenNokta; const Vec3d radyal = v - a.eksen * v.nokta(a.eksen); if (radyal.uzunlukKare() < 1e-12) continue; Vec3d n; if (!b.brep.yuzNoktaNormali(a.ordinal, p, n) || n.uzunlukKare() < 1e-12) continue; ic = n.nokta(radyal) < 0; karar = true; break; } } if (karar && ic) icler.push_back(a); } if (icler.empty()) return; // ---- 2) Eşeksenli zincirleme (kademeli delik) ---- const size_t n = icler.size(); std::vector> komsuluk(n); for (size_t i = 0; i < n; ++i) komsuluk[i] = g.komsular(icler[i].dugum, "komsu", 0); // Delik içi geçiş yüzü: kademe omzu (eksene dik, eksende oturan KÜÇÜK halka/disk // düzlem) veya eşeksenli koni. Gövdenin dev dış yüzü alan eşiğine takılır — // aynı plakadaki iki ayrı delik ortak dış yüz üzerinden zincirlenemez. const auto delikIciYuz = [&](u64 f, const SilindirAday& a) { const std::string t = ozMetin(f, "yuzey_tip"); Vec3d e, en; if (t == "koni") return ozVec(f, "eksen", e) && ozVec(f, "eksen_nokta", en) && esEksenli(a.eksen, a.eksenNokta, e.birim(), en); if (t != "duzlem") return false; Vec3d normal, merkez; if (!ozVec(f, "normal", normal) || !ozVec(f, "merkez", merkez)) return false; if (!esYonlu(normal.birim(), a.eksen)) return false; const Vec3d v = merkez - a.eksenNokta; if ((v - a.eksen * v.nokta(a.eksen)).uzunluk() > a.yaricap + eksenMesafeTol) return false; return g.ozSayi(f, "alan") <= pi * a.yaricap * a.yaricap * tabanAlanOran; }; const auto zincirli = [&](size_t i, size_t j) { const SilindirAday& A = icler[i]; const SilindirAday& B = icler[j]; if (!esEksenli(A.eksen, A.eksenNokta, B.eksen, B.eksenNokta)) return false; for (u64 f : komsuluk[i]) { if (f == B.dugum) return true; // doğrudan ortak kenar if (std::find(komsuluk[j].begin(), komsuluk[j].end(), f) == komsuluk[j].end()) continue; if (delikIciYuz(f, A.yaricap >= B.yaricap ? A : B)) return true; // omuz/koni köprüsü } return false; }; std::vector grupNo(n, -1); std::vector> gruplar; for (size_t i = 0; i < n; ++i) { if (grupNo[i] >= 0) continue; const int no = (int)gruplar.size(); gruplar.emplace_back(); std::vector kuyruk{i}; grupNo[i] = no; while (!kuyruk.empty()) { const size_t k = kuyruk.back(); kuyruk.pop_back(); gruplar[no].push_back(k); for (size_t j = 0; j < n; ++j) if (grupNo[j] < 0 && zincirli(k, j)) { grupNo[j] = no; kuyruk.push_back(j); } } } // ---- 3) Grup başına Delik düğümü ---- for (const auto& grup : gruplar) { const SilindirAday& ref = icler[grup[0]]; const auto grupUyesiMi = [&](u64 f) { for (size_t k : grup) if (icler[k].dugum == f) return true; return false; }; // Eksensel yayılım (derinlik) + kademe sırası f64 tMin = 1e300, tMax = -1e300, minYaricap = 1e300; struct Kademe { f64 t = 0, cap = 0; }; std::vector kademeler; for (size_t k : grup) { const SilindirAday& a = icler[k]; minYaricap = std::min(minYaricap, a.yaricap); f64 uMin = 1e300, uMax = -1e300; for (const Vec3d& p : yuzOrnekleri(b, g, a.dugum, a.ordinal)) { const f64 t = (p - ref.eksenNokta).nokta(ref.eksen); uMin = std::min(uMin, t); uMax = std::max(uMax, t); } if (uMin > uMax) continue; tMin = std::min(tMin, uMin); tMax = std::max(tMax, uMax); kademeler.push_back({(uMin + uMax) * 0.5, a.yaricap * 2}); } std::sort(kademeler.begin(), kademeler.end(), [](const Kademe& a, const Kademe& b) { return a.t < b.t; }); bool kademeliMi = false; { std::vector yaricaplar; for (size_t k : grup) yaricaplar.push_back(icler[k].yaricap); std::sort(yaricaplar.begin(), yaricaplar.end()); for (size_t i = 1; i < yaricaplar.size(); ++i) if (yaricaplar[i] - yaricaplar[i - 1] > capTol * 0.5) kademeliMi = true; } // Uç sınıflandırma: grup-dışı komşular. Ağızda eşeksenli koni → havşa (dışa // düzlemle açılır) ya da matkap ucu → kör (tek komşusu silindir, tepesi kapalı); // eksende oturan küçük düzlem → taban = kör; büyük/eksen-dışı düzlem = gövde // dış yüzü = açık uç. İki grup üyesine komşu delik-içi düzlem = kademe omzu. bool havsaVar = false, korVar = false; std::vector bagliYuzler; for (size_t k : grup) bagliYuzler.push_back(icler[k].dugum); std::unordered_map> disKomsu; for (size_t k : grup) for (u64 f : komsuluk[k]) { if (grupUyesiMi(f)) continue; auto& uyeler = disKomsu[f]; if (std::find(uyeler.begin(), uyeler.end(), k) == uyeler.end()) uyeler.push_back(k); } for (const auto& [f, uyeler] : disKomsu) { const std::string t = ozMetin(f, "yuzey_tip"); if (t == "koni") { Vec3d ke, kn; if (!(ozVec(f, "eksen", ke) && ozVec(f, "eksen_nokta", kn) && esEksenli(ref.eksen, ref.eksenNokta, ke.birim(), kn))) continue; bool disaAcik = false; for (u64 kf : g.komsular(f, "komsu", 0)) { if (grupUyesiMi(kf)) continue; if (ozMetin(kf, "yuzey_tip") == "duzlem") { disaAcik = true; break; } } if (disaAcik) havsaVar = true; else korVar = true; bagliYuzler.push_back(f); } else if (t == "duzlem") { f64 r = 0; for (size_t u : uyeler) r = std::max(r, icler[u].yaricap); Vec3d normal, merkez; if (!ozVec(f, "normal", normal) || !ozVec(f, "merkez", merkez)) continue; if (!esYonlu(normal.birim(), ref.eksen)) continue; const Vec3d v = merkez - ref.eksenNokta; const bool eksende = (v - ref.eksen * v.nokta(ref.eksen)).uzunluk() <= r + eksenMesafeTol; const bool kucuk = g.ozSayi(f, "alan") <= pi * r * r * tabanAlanOran; if (eksende && kucuk) { if (uyeler.size() < 2) korVar = true; // >=2 üye = kademe omzu (delik içi) bagliYuzler.push_back(f); } } } const char* tip = kademeliMi ? "kademeli" : havsaVar ? "havsa" : korVar ? "kor" : "acik"; const u64 delik = g.dugumEkle("Delik"); g.ozAyarla(delik, "cap", minYaricap * 2); g.ozAyarla(delik, "derinlik", tMax >= tMin ? tMax - tMin : 0.0); g.ozAyarla(delik, "tip", std::string(tip)); g.ozAyarla(delik, "eksen", ref.eksen); g.ozAyarla(delik, "eksen_nokta", ref.eksenNokta); g.ozAyarla(delik, "uretim_tipi", std::string("delme")); if (havsaVar) g.ozAyarla(delik, "havsa", true); if (kademeliMi && !kademeler.empty()) { std::vector caplar; caplar.reserve(kademeler.size()); for (const Kademe& kd : kademeler) caplar.push_back(kd.cap); g.ozAyarla(delik, "kademe_caplar", std::move(caplar)); } // brepBagla YOK — yüz düğümleri zaten BREP'e bağlı, aynı kid çakışırdı. g.iliskiEkle("icerir", b.govdeDugum, delik); std::sort(bagliYuzler.begin(), bagliYuzler.end()); bagliYuzler.erase(std::unique(bagliYuzler.begin(), bagliYuzler.end()), bagliYuzler.end()); for (u64 f : bagliYuzler) g.iliskiEkle("bagli", delik, f); } } } // namespace std::unique_ptr delikDedektoru() { return std::make_unique(); } } // namespace fiko::zeka