#include #include #include "fiko/dokum/methoding.hpp" #include "fiko/dokum/sonuc_katmanlari.hpp" #include "fiko/dokum/voxel_gorsel.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::dokum; namespace { // n³ kafes, [-1,1] AABB (h = 2/n m), tüm hücreler kalıp (Dis) başlar. VoxelKafes kafesYap(u32 n) { VoxelKafes k; Aabbd s; s.genislet({-1, -1, -1}); s.genislet({1, 1, 1}); k.kur(s, n, 0.0, 1.0); for (auto& t : k.tip) t = HucreTip::Dis; return k; } void hepsiIc(VoxelKafes& k) { for (auto& t : k.tip) t = HucreTip::Ic; } } // namespace FIKO_TEST(katman_cephe_hizi_duzgun) { // Düzgün cephe: t(x)=x/v düzlem dalgası → hız her yerde v (±%20). const u32 n = 6; VoxelKafes k = kafesYap(n); hepsiIc(k); const f64 v = 0.5, h = k.h(); std::vector varis(k.hucreSayi(), -1.0); for (u32 kk = 0; kk < n; ++kk) for (u32 j = 0; j < n; ++j) for (u32 i = 0; i < n; ++i) varis[k.indeks(i, j, kk)] = (i * h) / v; const std::vector hiz = cepheHiziHesapla(k, varis, 20.0); u32 kontrol = 0; for (u32 idx = 0; idx < k.hucreSayi(); ++idx) { FIKO_KONTROL(hiz[idx] >= 0.0f); if (std::abs(hiz[idx] - (f32)v) < 0.2f * (f32)v) ++kontrol; } FIKO_KONTROL(kontrol == k.hucreSayi()); // düzlem dalga: fark şeması kesin } FIKO_TEST(katman_gradyan_soguma_lst_tutarli) { // Bilinen Ṙ=8 °C/s, G=2 °C/mm → sdas ve niyama'dan geri kazanım doğru mu? const Alasim al = alasimAlSi7Mg(); VoxelKafes k = kafesYap(4); hepsiIc(k); const u32 N = k.hucreSayi(); const f64 R = 8.0, G = 2.0; const f64 sdasUm = al.sdasK * 1e6 * std::pow(R, -1.0 / 3.0); const f64 ny = G / std::sqrt(R); FIKO_KONTROL(std::abs(sogumaHiziSdas(sdasUm, al) - R) < 1e-6 * R); FIKO_KONTROL(sogumaHiziSdas(0.0, al) == 0.0); KatilasmaSonuc kat; kat.katilasmaSuresi.assign(N, 10.0); kat.sonSicaklik.assign(N, 400.0); kat.niyama.assign(N, ny); kat.sdas.assign(N, sdasUm); kat.hotSpotSure = 10.0; kat.hazir = true; k.fs.assign(N, 1.0); const SonucKatmanlari s = katmanlariHesapla(k, kat, nullptr, al); FIKO_KONTROL(s.hazir); const KatmanBilgi* soguma = s.bul("Soğuma Hızı"); const KatmanBilgi* grad = s.bul("Sıcaklık Gradyanı"); const KatmanBilgi* lst = s.bul("Yerel Katılaşma Süresi"); const KatmanBilgi* hot = s.bul("Hot-Spot (FSTime %)"); FIKO_KONTROL(soguma && grad && lst && hot); const u32 orta = k.indeks(2, 2, 2); FIKO_KONTROL(std::abs(soguma->alan[orta] - (f32)R) < 0.01f * (f32)R); FIKO_KONTROL(std::abs(grad->alan[orta] - (f32)G) < 0.01f * (f32)G); const f64 lstBeklenen = (al.tLikidus - al.tSolidus) / R; FIKO_KONTROL(std::abs(lst->alan[orta] - (f32)lstBeklenen) < 0.01f * (f32)lstBeklenen); FIKO_KONTROL(std::abs(hot->alan[orta] - 100.0f) < 1e-3f); // hepsi aynı an → %100 FIKO_KONTROL(lst->yaklasik); FIKO_KONTROL(!soguma->yaklasik); } FIKO_TEST(katman_akis_uzunlugu_monoton) { // x boyunca tek sıra hücre, varış artan → akış uzunluğu monoton artar. const u32 n = 6; VoxelKafes k = kafesYap(n); const u32 N = k.hucreSayi(); DolumSonuc d; d.varisZamani.assign(N, -1.0); for (u32 i = 0; i < n; ++i) { const u32 idx = k.indeks(i, 2, 2); k.tip[idx] = HucreTip::Ic; d.varisZamani[idx] = 0.1 * i; d.sira.push_back(idx); } d.toplamSure = 0.1 * (n - 1); d.hazir = true; const std::vector uz = akisUzunluguHesapla(k, d); const f32 hMm = (f32)(k.h() * 1000.0); FIKO_KONTROL(uz[k.indeks(0, 2, 2)] == 0.0f); // giriş (öncülsüz) = 0 for (u32 i = 1; i < n; ++i) { FIKO_KONTROL(uz[k.indeks(i, 2, 2)] > uz[k.indeks(i - 1, 2, 2)]); FIKO_KONTROL(std::abs(uz[k.indeks(i, 2, 2)] - i * hMm) < 1e-3f); } FIKO_KONTROL(uz[k.indeks(0, 0, 0)] == kKatmanGecersiz); // kalıp hücresi // sira boş verilirse varış zamanından kurulur (aynı sonuç). DolumSonuc d2 = d; d2.sira.clear(); const std::vector uz2 = akisUzunluguHesapla(k, d2); for (u32 i = 0; i < n; ++i) FIKO_KONTROL(uz2[k.indeks(i, 2, 2)] == uz[k.indeks(i, 2, 2)]); } FIKO_TEST(katman_dolum_yas_ve_duvar) { // Ergiyik yaşı = toplamSure − varış; duvar teması yalnız Sinir hücrede. const u32 n = 4; VoxelKafes k = kafesYap(n); const u32 ic = k.indeks(1, 1, 1), sinir = k.indeks(2, 1, 1); k.tip[ic] = HucreTip::Ic; k.tip[sinir] = HucreTip::Sinir; const u32 N = k.hucreSayi(); DolumSonuc d; d.varisZamani.assign(N, -1.0); d.varisT.assign(N, 0.0); d.varisZamani[ic] = 1.0; d.varisZamani[sinir] = 3.0; d.varisT[ic] = 690.0; d.toplamSure = 5.0; d.hazir = true; const SonucKatmanlari s = katmanlariHesapla(k, {}, &d, alasimAlSi7Mg()); FIKO_KONTROL(s.hazir); const KatmanBilgi* yas = s.bul("Ergiyik Yaşı"); const KatmanBilgi* duvar = s.bul("Duvar Temas Süresi"); const KatmanBilgi* zaman = s.bul("Dolum Zamanı"); const KatmanBilgi* cepheT = s.bul("Cephe Sıcaklığı"); FIKO_KONTROL(yas && duvar && zaman && cepheT); FIKO_KONTROL(std::abs(yas->alan[ic] - 4.0f) < 1e-5f); FIKO_KONTROL(std::abs(yas->alan[sinir] - 2.0f) < 1e-5f); FIKO_KONTROL(duvar->alan[ic] == kKatmanGecersiz); // iç hücre = duvar yok FIKO_KONTROL(std::abs(duvar->alan[sinir] - 2.0f) < 1e-5f); FIKO_KONTROL(std::abs(zaman->alan[ic] - 1.0f) < 1e-5f); FIKO_KONTROL(std::abs(cepheT->alan[ic] - 690.0f) < 1e-3f); // Katılaşma yok → yalnız dolum katmanları, hepsi Dolum kaynaklı. for (const auto& kb : s.katmanlar) FIKO_KONTROL(kb.kaynak == KatmanKaynak::Dolum); } FIKO_TEST(katman_jenerik_kontrat) { // UI kontratı: her katman ad+alan(N)+lejant min≤maks taşır; bul() çalışır. const u32 n = 4; VoxelKafes k = kafesYap(n); hepsiIc(k); const u32 N = k.hucreSayi(); k.fs.assign(N, 1.0); KatilasmaSonuc kat; kat.katilasmaSuresi.assign(N, 0.0); kat.sonSicaklik.assign(N, 300.0); kat.niyama.assign(N, 1.0); kat.sdas.assign(N, 30.0); kat.hotSpotSure = 0.0; kat.hazir = true; for (u32 i = 0; i < N; ++i) kat.katilasmaSuresi[i] = (f64)i; kat.hotSpotSure = (f64)(N - 1); DolumSonuc d; d.varisZamani.assign(N, 0.5); d.toplamSure = 2.0; d.hazir = true; const SonucKatmanlari s = katmanlariHesapla(k, kat, &d, alasimAlSi7Mg()); FIKO_KONTROL(s.hazir); FIKO_KONTROL(s.katmanlar.size() == 19); // 13 katılaşma (Feedmod+3 gerilme) + 6 dolum for (const auto& kb : s.katmanlar) { FIKO_KONTROL(!kb.ad.empty()); FIKO_KONTROL(!kb.aciklama.empty()); FIKO_KONTROL(kb.alan.size() == N); FIKO_KONTROL(kb.min <= kb.maks); } FIKO_KONTROL(s.bul("Niyama") != nullptr); FIKO_KONTROL(s.bul("olmayan-katman") == nullptr); const KatmanBilgi* fsT = s.bul("Katılaşma Süresi"); FIKO_KONTROL(fsT && fsT->maks > fsT->min); // 0..N-1 yayılı alan → aralık > 0 } FIKO_TEST(katman_feedmod_chvorinov_tersi) { // Feedmod: M_i = M_parça·√(t_i/t_maks)/10 [cm] — t_maks hücrede M_parça/10, // t_maks/4 hücrede yarısı (√ ölçekleme). Geç katılaşan > erken katılaşan. const Alasim al = alasimAlSi7Mg(); VoxelKafes k = kafesYap(4); hepsiIc(k); const u32 N = k.hucreSayi(); k.fs.assign(N, 1.0); KatilasmaSonuc kat; kat.katilasmaSuresi.assign(N, 100.0); kat.sonSicaklik.assign(N, 300.0); kat.niyama.assign(N, 1.0); kat.sdas.assign(N, 30.0); const u32 erken = k.indeks(1, 1, 1); kat.katilasmaSuresi[erken] = 25.0; // t_maks/4 → M yarısı kat.hotSpotSure = 100.0; kat.hazir = true; const ParcaModul pm = parcaModulu(k); FIKO_KONTROL(pm.gecerli && pm.modul > 0.0); const SonucKatmanlari s = katmanlariHesapla(k, kat, nullptr, al); const KatmanBilgi* feed = s.bul("Feedmod"); FIKO_KONTROL(feed && feed->yaklasik && feed->birim == "cm"); const u32 gec = k.indeks(2, 2, 2); const f32 mCm = (f32)(pm.modul * 0.1); FIKO_KONTROL(std::abs(feed->alan[gec] - mCm) < 1e-4f * mCm); FIKO_KONTROL(std::abs(feed->alan[erken] - 0.5f * mCm) < 1e-3f * mCm); } FIKO_TEST(katman_malzeme_kaynagi) { // girisId alanı → "Malzeme Kaynağı" katmanı (giriş no = id+1; yok = geçersiz). const u32 n = 4; VoxelKafes k = kafesYap(n); const u32 a = k.indeks(0, 1, 1), b = k.indeks(3, 1, 1), c = k.indeks(1, 1, 1); k.tip[a] = k.tip[b] = k.tip[c] = HucreTip::Ic; const u32 N = k.hucreSayi(); DolumSonuc d; d.varisZamani.assign(N, -1.0); d.varisZamani[a] = 0.0; d.varisZamani[b] = 0.5; d.varisZamani[c] = 1.0; d.girisId.assign(N, kGirisYok); d.girisId[a] = 0; d.girisId[b] = 1; d.girisId[c] = 0; d.toplamSure = 1.0; d.hazir = true; const SonucKatmanlari s = katmanlariHesapla(k, {}, &d, alasimAlSi7Mg()); const KatmanBilgi* mk = s.bul("Malzeme Kaynağı"); FIKO_KONTROL(mk && mk->yaklasik); FIKO_KONTROL(mk->alan[a] == 1.0f); FIKO_KONTROL(mk->alan[b] == 2.0f); FIKO_KONTROL(mk->alan[c] == 1.0f); FIKO_KONTROL(mk->alan[k.indeks(2, 2, 2)] == kKatmanGecersiz); // kalıp hücresi // girisId boy uyuşmazsa katman üretilmez (çökme yok). DolumSonuc d2 = d; d2.girisId.clear(); FIKO_KONTROL(katmanlariHesapla(k, {}, &d2, alasimAlSi7Mg()).bul("Malzeme Kaynağı") == nullptr); } FIKO_TEST(katman_kesit_ve_band) { // Kesit süpürme: X yarısı → hücre sayısı düşer, lejant aralığı DEĞİŞMEZ. // Kademeli kip: renkler bandSayi'dan fazla benzersiz olamaz. const u32 n = 6; VoxelKafes k = kafesYap(n); hepsiIc(k); const u32 N = k.hucreSayi(); std::vector alan(N); for (u32 i = 0; i < N; ++i) alan[i] = (f32)i; VoxelGorselAyar ay; const VoxelGorselSonuc tam = alanMeshKur(k, alan, ay, -0.5f); FIKO_KONTROL(tam.gecerli && tam.hucreSayi == N); ay.kesitEksen = 0; ay.kesitOran = 0.5f; const VoxelGorselSonuc yarim = alanMeshKur(k, alan, ay, -0.5f); FIKO_KONTROL(yarim.gecerli); FIKO_KONTROL(yarim.hucreSayi < tam.hucreSayi && yarim.hucreSayi >= N / 2 - n * n); FIKO_KONTROL(yarim.alanMin == tam.alanMin && yarim.alanMax == tam.alanMax); ay.kesitOran = 0.0f; // tek dilim FIKO_KONTROL(alanMeshKur(k, alan, ay, -0.5f).hucreSayi == n * n); // Kademeli: benzersiz vertex renk adedi ≤ bandSayi. ay.kesitEksen = -1; ay.bandli = true; ay.bandSayi = 5; const VoxelGorselSonuc bandli = alanMeshKur(k, alan, ay, -0.5f); std::vector renkler; for (const auto& v : bandli.mesh.vertexler) renkler.push_back(v.renk[0] * 1000.0f + v.renk[1] * 10.0f + v.renk[2]); std::sort(renkler.begin(), renkler.end()); renkler.erase(std::unique(renkler.begin(), renkler.end()), renkler.end()); FIKO_KONTROL((int)renkler.size() <= ay.bandSayi); } FIKO_TEST(katman_bos_giris_cokmez) { const Alasim al = alasimAlSi7Mg(); // Boş kafes → hazir=false. VoxelKafes bos; FIKO_KONTROL(!katmanlariHesapla(bos, {}, nullptr, al).hazir); // Kafes var ama ne katılaşma ne dolum → hazir=false. VoxelKafes k = kafesYap(4); FIKO_KONTROL(!katmanlariHesapla(k, {}, nullptr, al).hazir); // hazir=false katılaşma + boyutu yanlış dolum → hazir=false, çökme yok. KatilasmaSonuc hazirDegil; hazirDegil.katilasmaSuresi.assign(k.hucreSayi(), 1.0); DolumSonuc bozuk; bozuk.hazir = true; bozuk.varisZamani.assign(3, 0.0); FIKO_KONTROL(!katmanlariHesapla(k, hazirDegil, &bozuk, al).hazir); // Saf yardımcılar bozuk boyutla çökmeyip geçersiz alan döner. const std::vector hiz = cepheHiziHesapla(k, {}, 20.0); FIKO_KONTROL(hiz.size() == k.hucreSayi()); for (f32 v : hiz) FIKO_KONTROL(v == kKatmanGecersiz); DolumSonuc bosDolum; const std::vector uz = akisUzunluguHesapla(k, bosDolum); for (f32 v : uz) FIKO_KONTROL(v == kKatmanGecersiz); }