#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 namespace fiko::zeka { namespace { // ---- Yardimcilar (diger dedektorlerle ortak kalip) ---- 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; } std::string fmtSayi(f64 deger, int ondalik) { char buf[64]; std::snprintf(buf, sizeof(buf), "%.*f", ondalik, deger); return buf; } // ---- DFM Uyari Seviye ---- enum class DfmSev : u8 { Bilgi = 0, Uyari = 1, Kritik = 2 }; u64 uyariEkle(GrafDeposu& g, u64 govdeDugum, u64 ilgiliDugum, const std::string& kategori, const std::string& mesaj, DfmSev seviye, const std::string& uretimTipi) { const u64 d = g.dugumEkle("DfmUyari"); g.ozAyarla(d, "kategori", kategori); g.ozAyarla(d, "mesaj", mesaj); g.ozAyarla(d, "severlik", static_cast(seviye)); g.ozAyarla(d, "uretim_tipi", uretimTipi); g.iliskiEkle("icerir", govdeDugum, d); if (ilgiliDugum) g.iliskiEkle("bagli", d, ilgiliDugum); return d; } bool govdeyeAit(const GrafDeposu& g, u64 dugum, u64 govdeDugum) { for (u64 rel : g.dugumIliskileri(dugum, -1)) { const ZIliski* il = g.iliski(rel); if (il && il->kaynak == govdeDugum && g.adMetin(il->tip) == "icerir") return true; } return false; } } // namespace // ============================================================================ // DfmDedektor -- Design-for-Manufacturing (DFM) analizi. Katman: "uretim". // Mevcut grafta daha once olusturulmus feature dugumlerini (Delik, Cep, Slot, // Boss, Fillet, Pah) okur ve uretilebilirlik kurallarini uygular. Her ihlal // grafa "DfmUyari" dugumu ekler. // // CNC Kontrolleri: // - Derin cep/slot orani (derinlik/genislik > esik) // - Ince duvar (iki paralel duzlem arasi mesafe < esik) // - Kucuk fillet yaricapi (takim capi limiti) // - Dar slot genisligi (minimum frez capi) // // Dokum Kontrolleri: // - Ince duvar (dokum kalibinda dolma sorunu) // - Derin cep (kalip cekme zorlugu) // - Kucuk ic kose (catlama riski) // - Buyuk alan degisimleri (cekme/buzulme) // ============================================================================ struct DfmDedektor final : public Dedektor { // --- AyarSistemi esikleri (Faz 2'de ayar_kayitlari.cpp'den baglanir) --- // CNC esikleri f64 cncDerinlikOranEsik = 4.0; // cep derinlik/genislik orani f64 cncMinDuvarKalinlik = 0.8; // mm f64 cncMinFilletYaricap = 0.5; // mm f64 cncMinSlotGenislik = 3.0; // mm f64 cncMinDelikCap = 1.0; // mm f64 cncMaxDelikDerinlikOran = 10.0; // L/D // Dokum esikleri f64 dokumMinDuvar = 2.0; // mm f64 dokumMaxDerinlikOran = 3.0; f64 dokumMinIcKoseYaricap = 1.0; // mm f64 dokumMaxAlanOran = 5.0; const char* ad() const override { return "dfm"; } const char* katman() const override { return "uretim"; } void esikAyarla(std::string_view anahtar, f64 deger) override { if (anahtar == "cnc_derinlik_oran") cncDerinlikOranEsik = deger; else if (anahtar == "cnc_min_duvar") cncMinDuvarKalinlik = deger; else if (anahtar == "cnc_min_fillet") cncMinFilletYaricap = deger; else if (anahtar == "cnc_min_slot_gen") cncMinSlotGenislik = deger; else if (anahtar == "cnc_min_delik_cap") cncMinDelikCap = deger; else if (anahtar == "cnc_max_delik_derinlik") cncMaxDelikDerinlikOran = deger; else if (anahtar == "dokum_min_duvar") dokumMinDuvar = deger; else if (anahtar == "dokum_max_derinlik_oran") dokumMaxDerinlikOran = deger; else if (anahtar == "dokum_min_ic_kose") dokumMinIcKoseYaricap = deger; else if (anahtar == "dokum_max_alan_oran") dokumMaxAlanOran = deger; } void calistir(DedektorBaglam& b) override { cncKontroller(b); dokumKontroller(b); raporOlustur(b); } private: // ======== CNC Kontrolleri ======== void cncKontroller(DedektorBaglam& b) { GrafDeposu& g = b.graf; // 1) Derin cep/slot kontrolu for (u64 id : g.tipteki("Cep")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; const f64 derinlik = g.ozSayi(id, "derinlik"); const f64 alan = g.ozSayi(id, "alan"); if (alan <= 0 || derinlik <= 0) continue; const f64 yaklasikGen = std::sqrt(alan); const f64 oran = derinlik / yaklasikGen; if (oran > cncDerinlikOranEsik) uyariEkle(g, b.govdeDugum, id, "cnc_derin_cep", "Cep derinlik/genislik orani (" + fmtSayi(oran, 1) + ") CNC limiti (" + fmtSayi(cncDerinlikOranEsik, 1) + ") asiyor", DfmSev::Uyari, "cnc"); } for (u64 id : g.tipteki("Slot")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; const f64 derinlik = g.ozSayi(id, "derinlik"); const f64 genislik = g.ozSayi(id, "genislik"); if (genislik <= 0 || derinlik <= 0) continue; if (derinlik / genislik > cncDerinlikOranEsik) uyariEkle(g, b.govdeDugum, id, "cnc_derin_slot", "Slot derinlik/genislik orani CNC limiti asiyor", DfmSev::Uyari, "cnc"); if (genislik < cncMinSlotGenislik) uyariEkle(g, b.govdeDugum, id, "cnc_dar_slot", "Slot genisligi (" + fmtSayi(genislik, 2) + " mm) minimum frez capi (" + fmtSayi(cncMinSlotGenislik, 1) + " mm) altinda", DfmSev::Kritik, "cnc"); } // 2) Kucuk delik / derin delik kontrolu for (u64 id : g.tipteki("Delik")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; const f64 cap = g.ozSayi(id, "cap"); const f64 derinlik = g.ozSayi(id, "derinlik"); if (cap > 0 && cap < cncMinDelikCap) uyariEkle(g, b.govdeDugum, id, "cnc_kucuk_delik", "Delik capi (" + fmtSayi(cap, 2) + " mm) minimum delme limiti (" + fmtSayi(cncMinDelikCap, 1) + " mm) altinda", DfmSev::Uyari, "cnc"); if (cap > 0 && derinlik > 0 && (derinlik / cap) > cncMaxDelikDerinlikOran) uyariEkle(g, b.govdeDugum, id, "cnc_derin_delik", "Delik derinlik/cap orani (" + fmtSayi(derinlik / cap, 1) + ") CNC limiti asiyor", DfmSev::Uyari, "cnc"); } // 3) Kucuk fillet yaricapi kontrolu for (u64 id : g.tipteki("Fillet")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; const f64 yaricap = g.ozSayi(id, "yaricap"); if (yaricap > 0 && yaricap < cncMinFilletYaricap) uyariEkle(g, b.govdeDugum, id, "cnc_kucuk_fillet", "Fillet yaricapi (" + fmtSayi(yaricap, 2) + " mm) CNC takim limiti (" + fmtSayi(cncMinFilletYaricap, 1) + " mm) altinda", DfmSev::Bilgi, "cnc"); } // 4) Ince duvar kontrolu (paralel duzlem yuz ciftleri) inceDuvarKontrol(b, cncMinDuvarKalinlik, "cnc"); } // ======== Dokum Kontrolleri ======== void dokumKontroller(DedektorBaglam& b) { GrafDeposu& g = b.graf; // 1) Ince duvar (dokum toleransi genellikle CNC'den yuksek) inceDuvarKontrol(b, dokumMinDuvar, "dokum"); // 2) Derin cep -- kalip cekme zorlugu for (u64 id : g.tipteki("Cep")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; const f64 derinlik = g.ozSayi(id, "derinlik"); const f64 alan = g.ozSayi(id, "alan"); if (alan <= 0 || derinlik <= 0) continue; const f64 gen = std::sqrt(alan); if (gen > 0 && derinlik / gen > dokumMaxDerinlikOran) uyariEkle(g, b.govdeDugum, id, "dokum_derin_cep", "Cep derinlik/genislik orani dokum kalibi icin cok yuksek", DfmSev::Uyari, "dokum"); } // 3) Ic kose fillet eksikligi / cok kucuk fillet for (u64 id : g.tipteki("Yuz")) { if (!govdeyeAit(g, id, b.govdeDugum)) continue; for (u64 k : g.komsular(id, "sinir", -1)) { bool dis = true; if (!ozBool(g, k, "disbukey", dis)) continue; if (dis) continue; bool filletVar = false; for (u64 rel : g.dugumIliskileri(k, -1)) { const ZIliski* il = g.iliski(rel); if (!il) continue; const ZDugum* kaynak = g.dugum(il->kaynak); if (kaynak && g.adMetin(kaynak->tip) == "Fillet") { filletVar = true; break; } } if (!filletVar) uyariEkle(g, b.govdeDugum, k, "dokum_ic_kose_filletsiz", "Icbukey kenar filletsiz -- dokum catlama riski", DfmSev::Bilgi, "dokum"); } } // 4) Buyuk kesit alani degisimi (cekme/buzulme) alanDegisimiKontrol(b); } // ---- Ortak Yardimcilar ---- void inceDuvarKontrol(DedektorBaglam& b, f64 esik, const std::string& tip) { GrafDeposu& g = b.graf; const auto yuzler = Sorgu(g).tip("Yuz").govdede(b.govdeVarlik).bul(); for (size_t i = 0; i < yuzler.size(); ++i) { const std::string* tip1 = ozMetin(g, yuzler[i], "yuzey_tip"); if (!tip1 || *tip1 != "duzlem") continue; Vec3d n1{}, m1{}; if (!ozVec3(g, yuzler[i], "normal", n1) || !ozVec3(g, yuzler[i], "merkez", m1)) continue; n1 = n1.birim(); if (n1.uzunlukKare() < 0.5) continue; for (size_t j = i + 1; j < yuzler.size(); ++j) { const std::string* tip2 = ozMetin(g, yuzler[j], "yuzey_tip"); if (!tip2 || *tip2 != "duzlem") continue; Vec3d n2{}, m2{}; if (!ozVec3(g, yuzler[j], "normal", n2) || !ozVec3(g, yuzler[j], "merkez", m2)) continue; n2 = n2.birim(); if (n2.uzunlukKare() < 0.5) continue; const f64 dot = n1.nokta(n2); if (dot > -0.95) continue; const f64 mesafe = std::abs((m2 - m1).nokta(n1)); if (mesafe > 0 && mesafe < esik) uyariEkle(g, b.govdeDugum, yuzler[i], tip == "cnc" ? "cnc_ince_duvar" : "dokum_ince_duvar", "Ince duvar tespit edildi (" + fmtSayi(mesafe, 2) + " mm) -- minimum: " + fmtSayi(esik, 1) + " mm", DfmSev::Kritik, tip); } } } void alanDegisimiKontrol(DedektorBaglam& b) { GrafDeposu& g = b.graf; const auto yuzler = Sorgu(g).tip("Yuz").govdede(b.govdeVarlik).bul(); f64 enBuyukAlan = 0, enKucukAlan = 1e300; for (u64 y : yuzler) { const f64 a = g.ozSayi(y, "alan"); if (a > 0) { enBuyukAlan = std::max(enBuyukAlan, a); enKucukAlan = std::min(enKucukAlan, a); } } if (enKucukAlan > 0 && enBuyukAlan / enKucukAlan > dokumMaxAlanOran) uyariEkle(g, b.govdeDugum, u64(0), "dokum_alan_degisimi", "Kesit alani degisimi orani (" + fmtSayi(enBuyukAlan / enKucukAlan, 1) + ") cok yuksek -- dokum cekme/buzulme riski", DfmSev::Uyari, "dokum"); } void raporOlustur(DedektorBaglam& b) { GrafDeposu& g = b.graf; const auto uyarilar = g.tipteki("DfmUyari"); u32 cncSayi = 0, dokumSayi = 0; u32 kritikSayi = 0, uyariSayi = 0, bilgiSayi = 0; for (u64 u : uyarilar) { bool ait = false; for (u64 rel : g.dugumIliskileri(u, -1)) { const ZIliski* il = g.iliski(rel); if (il && il->kaynak == b.govdeDugum) { ait = true; break; } } if (!ait) continue; const std::string* ut = ozMetin(g, u, "uretim_tipi"); if (ut && *ut == "cnc") ++cncSayi; else ++dokumSayi; const i64 sev = static_cast(g.ozSayi(u, "severlik")); if (sev == 2) ++kritikSayi; else if (sev == 1) ++uyariSayi; else ++bilgiSayi; } const u64 rapor = g.dugumEkle("DfmRapor"); g.ozAyarla(rapor, "cnc_uyari_sayi", static_cast(cncSayi)); g.ozAyarla(rapor, "dokum_uyari_sayi", static_cast(dokumSayi)); g.ozAyarla(rapor, "kritik_sayi", static_cast(kritikSayi)); g.ozAyarla(rapor, "uyari_sayi", static_cast(uyariSayi)); g.ozAyarla(rapor, "bilgi_sayi", static_cast(bilgiSayi)); g.ozAyarla(rapor, "toplam_sorun", static_cast(cncSayi + dokumSayi)); // Risk skoru: 0-100 (kritik agirlik 30, uyari 10, bilgi 2; 100'de kap) const f64 skor = std::min(100.0, kritikSayi * 30.0 + uyariSayi * 10.0 + bilgiSayi * 2.0); g.ozAyarla(rapor, "risk_skoru", skor); g.iliskiEkle("icerir", b.govdeDugum, rapor); } }; std::unique_ptr dfmDedektoru() { return std::make_unique(); } } // namespace fiko::zeka