#include "fiko/dokum/dokum_simulasyonu.hpp" #include #include #include "fiko/dokum/dokum_kurulum.hpp" #include "fiko/dokum/dolum.hpp" #include "fiko/dokum/katilasma_gpu.hpp" #include "fiko/dokum/sph_gpu.hpp" #include "fiko/dokum/voxelize.hpp" #include "fiko/geometri/brep.hpp" #include "fiko/render/mesh_veri.hpp" namespace fiko::dokum { // Kafes kur + sınıfla + KURULUMU uygula (besleyici/yolluk → metal hücre). // Ortak yol: hesaplaGovde + hesaplaGovdeDolumlu buradan geçer. bool DokumSimulasyonu::kafesiKur_(const geometri::BrepGovde& govde) { if (!govde.gecerliMi()) return false; const UcgenCorba corba = corbaBrepten(govde, 0.01); if (corba.ucgenSayi() == 0 || !corba.sinir.gecerliMi()) return false; // Voxel kafesi (mesh AABB → kübik grid; pay = kalıp emici bölge). // Kurulum geometrisi (besleyici/yolluk) AABB'ye dahil edilir ki kırpılmasın. // Gövde mm biriminde → fizik SI için birimOlcek = 0.001 (mm→m). Aabbd sinir = corba.sinir; kurulumSinirGenislet(sinir, kurulum); if (!kafes.kur(sinir, cozunurluk, 0.4, 0.001)) return false; // NaN guard kafesiSinifla(kafes, corba); // GERÇEK parça SDF'si: çorba SADECE burada elde → sonradan aranmasın diye // hücre-başı f32 alan olarak kafeste saklanır. siviYuzeyKur bunu kullanır; // yoksa chamfer vekiline düşer (voxelleşmiş sınır → %5 taşma). // ⚠️ kurulumKafeseUygula'dan ÖNCE: besleyici/yolluk hücreleri metal yapar ama // onlar çorbada YOK → SDF sonra hesaplanırsa o hücrelerde yanlış işaret çıkar. parcaSdfHesapla(kafes, corba); kurulumKafeseUygula(kafes, kurulum); // Kalıp/proses seçimi süreçle uyumlu (kokil → çelik kalıp varsayılan). if (surec == DokumSurec::Kokil && kalip.ad == kalipSilikaKum().ad) kalip = kalipCelikKalip(); return true; } namespace { // Malzeme → SPH fizik parametreleri köprüsü (TEK KAYNAK; CPU/GPU/async yolları // aynı değeri görsün diye çağıran yerlerde değil, burada kurulur). // Yüzey gerilimi: kullanıcı AyarSistemi'nden elle girmediyse (< 0) ALAŞIMIN // erimiş haldeki σ değeri kullanılır (AlSi7Mg 0.80, GG25 1.40, çinko 0.50…). // Böylece malzeme değiştirince akış fiziksel olarak da değişir — gerçek erimiş // metallerde yüzey gerilimi belirleyicidir (sise kalkma/jet kopması). // AyarSistemi'nin "elle" değeri korunur (>= 0) → deney/parametre taraması mümkün. void sphMalzemeUygula(SphDolumAyar& a, const Alasim& alasim) { if (a.yuzeyGerilimOtomatik) a.yuzeyGerilim = std::max(0.0, alasim.yuzeyGerilimi); } } // namespace bool DokumSimulasyonu::hesaplaGovde(const geometri::BrepGovde& govde, IlerlemeCB ilerleme) { if (!kafesiKur_(govde)) return false; const std::vector chillH = chillHtcHaritasi(kafes, kurulum); sonuc = katilasmaCoz(kafes, alasim, kalip, ayar, niyamaEsik, ilerleme, nullptr, chillH.empty() ? nullptr : &chillH); bayat = !sonuc.hazir; return sonuc.hazir; } bool DokumSimulasyonu::hesaplaGovdeGpu(VulkanBaglam& vb, const geometri::BrepGovde& govde, IlerlemeCB ilerleme) { if (!kafesiKur_(govde)) return false; const std::vector chillH = chillHtcHaritasi(kafes, kurulum); const std::vector* hH = chillH.empty() ? nullptr : &chillH; bool gpuOk = false; sonuc = katilasmaGpuCoz(vb, kafes, alasim, kalip, ayar, gpuOk, niyamaEsik, ilerleme, nullptr, hH); if (!gpuOk) // GPU koşmadı (cihaz yok/device-lost) → CPU'ya düş (aynı sonuç). sonuc = katilasmaCoz(kafes, alasim, kalip, ayar, niyamaEsik, ilerleme, nullptr, hH); bayat = !sonuc.hazir; return sonuc.hazir; } bool DokumSimulasyonu::dolumCozGpu(VulkanBaglam& vb, IlerlemeCB ilerleme) { if (!kafes.gecerliMi() || !sphKullan) return false; sphAyar.dokumSicaklik = ayar.dokumSicaklik; sphMalzemeUygula(sphAyar, alasim); // σ ← alaşım (otomatik modda) sph = sphGpuCoz(vb, kafes, kurulum, alasim, sphAyar, ilerleme); if (!sph.dolum.hazir) return false; // GPU koşamadı → çağıran CPU worker'a düşer dolum = std::move(sph.dolum); sph.dolum = DolumSonuc{}; // tek kopya: tüketiciler this->dolum'dan okur dolumBayat = false; return true; } bool DokumSimulasyonu::dolumCoz(IlerlemeCB ilerleme) { if (!kafes.gecerliMi()) return false; // Gerçek SPH yolu (D3 Yol B): kurulum girişlerinden emitter; DolumSonuc-uyumlu // çıktı .dolum'a taşınır (mevcut zincir değişmeden), kare/hız sph'te kalır. if (sphKullan) { sphAyar.dokumSicaklik = ayar.dokumSicaklik; sphMalzemeUygula(sphAyar, alasim); // σ ← alaşım (otomatik modda) sph = sphDolumCoz(kafes, kurulum, alasim, sphAyar, ilerleme); dolum = std::move(sph.dolum); sph.dolum = DolumSonuc{}; // tek kopya: tüketiciler this->dolum'dan okur dolumBayat = !dolum.hazir; return dolum.hazir; } sph = SphDolumSonuc{}; // hızlı yol: bayat SPH kare/hız serisi kalmasın dolumAyar.dokumSicaklik = ayar.dokumSicaklik; // ingate = döküm sıcaklığı const Vec3d gv{kurulum.graviteYon.x, kurulum.graviteYon.y, kurulum.graviteYon.z}; // Kurulum girişleri (zamanlamalı çoklu kaynak) — her giriş kendi penceresinde // [gecikme, gecikme+süre] akar; hacimsel debi = (kütle/ρ)/süre. std::vector kaynaklar; for (const auto& g : kurulum.girisler) { if (!g.aktif) continue; const u32 idx = enYakinMetalHucre(kafes, g.konum); if (idx == static_cast(-1)) continue; const f64 debi = (g.sureS > 0 && g.kutleKg > 0) ? (g.kutleKg / alasim.yogunluk) / g.sureS : 0.0; kaynaklar.push_back({idx, std::max(g.gecikmeS, 0.0), g.sureS, debi}); } if (kaynaklar.empty()) { // Eski yol: elle giriş hücresi veya graviteye göre en üst metal hücre. if (girisHucre != static_cast(-1) && girisHucre < kafes.hucreSayi()) kaynaklar.push_back({girisHucre, 0.0, 0.0, 0.0}); else if (const u32 g = enUstMetalHucre(kafes, gv); g != static_cast(-1)) kaynaklar.push_back({g, 0.0, 0.0, 0.0}); } dolum = dokum::dolumCoz(kafes, alasim, dolumAyar, kaynaklar, gv, ilerleme); dolumBayat = !dolum.hazir; return dolum.hazir; } bool DokumSimulasyonu::hesaplaGovdeDolumlu(const geometri::BrepGovde& govde, IlerlemeCB ilerleme) { if (!kafesiKur_(govde)) return false; // 1) Dolum (kalıp doldurma) — varış zamanı + soğumuş cephe sıcaklığı. if (!dolumCoz(ilerleme)) return false; // 2) Köprü: dolum sonrası cephe sıcaklığı → katılaşma başlangıç koşulu. const std::vector* baslangic = nullptr; if (dolumKatilasmaKopru && dolum.hazir && dolum.varisT.size() == kafes.hucreSayi()) baslangic = &dolum.varisT; const std::vector chillH = chillHtcHaritasi(kafes, kurulum); sonuc = katilasmaCoz(kafes, alasim, kalip, ayar, niyamaEsik, ilerleme, baslangic, chillH.empty() ? nullptr : &chillH); bayat = !sonuc.hazir; return sonuc.hazir; } OzellikSeti DokumSimulasyonu::ozellikler(Dunya&) { OzellikSeti o; o.push_back(Ozellik::sayi( "Döküm sıcaklığı [°C]", [this] { return ayar.dokumSicaklik; }, [this](f64 v) { ayar.dokumSicaklik = v; bayat = true; })); o.push_back(Ozellik::sayi( "Çözünürlük (hücre)", [this] { return (f64)cozunurluk; }, [this](f64 v) { cozunurluk = v < 4 ? 4 : (u32)v; bayat = true; })); o.push_back(Ozellik::sayi( "Niyama eşiği", [this] { return niyamaEsik; }, [this](f64 v) { niyamaEsik = v; bayat = true; })); o.push_back(Ozellik::metin( "Alaşım", [this] { return alasim.ad; }, [](const std::string&) {})); // DB seçimi UI'da (salt-görüntü burada) o.push_back(Ozellik::metin( "Kalıp", [this] { return kalip.ad; }, [](const std::string&) {})); o.push_back(Ozellik::sayi( "Katılaşma süresi [s]", [this] { return sonuc.toplamSure; }, [](f64) {})); o.push_back(Ozellik::bayrak( "SPH dolum", [this] { return sphKullan; }, [this](bool v) { sphKullan = v; dolumBayat = true; })); o.push_back(Ozellik::sayi( "SPH maks hız [m/s]", [this] { return sph.maksHiz; }, [](f64) {})); // ---- Kurulum özetleri (makro/plugin erişimi — mimari ilke) ---- o.push_back(Ozellik::sayi( "Giriş sayısı", [this] { return (f64)kurulum.girisler.size(); }, [](f64) {})); o.push_back(Ozellik::sayi( "Soğutucu sayısı", [this] { return (f64)kurulum.sogutucular.size(); }, [](f64) {})); o.push_back(Ozellik::sayi( "Besleyici sayısı", [this] { return (f64)kurulum.besleyiciler.size(); }, [](f64) {})); o.push_back(Ozellik::sayi( "Yolluk sayısı", [this] { return (f64)kurulum.yolluklar.size(); }, [](f64) {})); o.push_back(Ozellik::metin( "Gravite yönü", [this] { char b[48]; std::snprintf(b, sizeof(b), "(%.2f, %.2f, %.2f)", kurulum.graviteYon.x, kurulum.graviteYon.y, kurulum.graviteYon.z); return std::string(b); }, [](const std::string&) {})); return o; } } // namespace fiko::dokum