#include #include #include "fiko/kutuk/kutuk_motor.hpp" #include "fiko/kutuk/tridexel_motor.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::kutuk; namespace { Aabbf kutuSinir() { Aabbf s; s.asgari = {0, 0, 0}; s.azami = {40, 40, 20}; return s; } cam::Stok kutuStok() { cam::Stok s; s.tip = cam::StokTip::Kutu; s.boyut = {40, 40, 20}; return s; } TakimGeo duzTakim(f64 cap) { TakimGeo t; t.tip = TakimGeo::Tip::Duz; t.cap = cap; t.boy = 40; t.eksen = {0, 0, 1}; return t; } } // namespace // ============================================================================ // TriDexel Pro (profesyonel analitik tri-dexel) testleri // ============================================================================ // (T1) Fabrika + stok kurulum: kip dogru, uyelik dogru, span'lar dolu. FIKO_TEST(tridexel_fabrika_ve_stok) { auto m = kutukMotoruYap(KutukSimKip::TriDexel); FIKO_KONTROL(m != nullptr); FIKO_KONTROL(m->kip() == KutukSimKip::TriDexel); FIKO_KONTROL(m->kutukKur(kutuStok(), kutuSinir(), 1.0)); FIKO_KONTROL(m->noktaIcerideMi({20, 20, 10})); FIKO_KONTROL(!m->noktaIcerideMi({50, 20, 10})); FIKO_KONTROL(!m->noktaIcerideMi({20, 20, 30})); FIKO_KONTROL(m->kaldirilanHacimMm3() == 0.0); } // (T2) ANALITIK KESKINLIK — motorun varolus sebebi: duz freze dalisinda span // uclari GRID'E YUVARLANMADAN tam kesici sinirinda olmali (±2e-3 mm; h=1mm // gridde MC/voxel bunu ±0.5mm yapardi). Z: taban tam z=12; X: duvar tam 15/25. FIKO_TEST(tridexel_analitik_keskinlik) { TriDexelMotoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); TakimGeo t = duzTakim(10.0); m.takimUygula({20, 20, 12}, t); // tip z=12 → z∈[12,∞) silindir Ø10 kesildi // Kafes yarim-hucre kaymali: dugum20 = 19.5mm. Z-dexel (x=19.5,y=19.5) merkeze // r=0.707<5 uzak → kesildi; kalan span [0,12] — t1 TAM 12 (yuvarlanMAdi; grid // tabanli motor 11.5/12.5 verirdi). const auto& sz = m.seti(2); const auto& kz = sz.kolon[(size_t)20 * sz.nu + 20]; FIKO_KONTROL(kz.size() == 1); FIKO_YAKIN((f64)kz[0].t0, 0.0, 2e-3); FIKO_YAKIN((f64)kz[0].t1, 12.0, 2e-3); // ← keskin taban (analitik) // X-dexel (y=19.5, z=15.5): silindir duvarlari x = 20 ∓ √(25−0.25) — ANALITIK // (grid 0.5mm'e yuvarlardi; burada ±2e-3 tutmali). const f64 yar = std::sqrt(25.0 - 0.25); const auto& sx = m.seti(0); const auto& kx = sx.kolon[(size_t)16 * sx.nu + 20]; // u=y(dugum20), v=z(dugum16) FIKO_KONTROL(kx.size() == 2); FIKO_YAKIN((f64)kx[0].t1, 20.0 - yar, 2e-3); // ← sol duvar analitik FIKO_YAKIN((f64)kx[1].t0, 20.0 + yar, 2e-3); // ← sag duvar analitik // Hacim: silindir π·25·8 ≈ 628.3 mm³ ±%20 (dugum-ornekleme alan modeli; gosterge). const f64 beklenen = 3.14159265358979 * 25.0 * 8.0; FIKO_YAKIN(m.kaldirilanHacimMm3(), beklenen, beklenen * 0.20); } // (T3) Swept (yatay kanal) hacim + uyelik: a→b supurme tek konveks blok. FIKO_TEST(tridexel_swept_kanal) { TriDexelMotoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); TakimGeo t = duzTakim(8.0); m.sweptUygula({10, 20, 14}, {30, 20, 14}, t); // z∈[14,20] kanal // Kanal ici bos, alti dolu. FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 17})); FIKO_KONTROL(m.noktaIcerideMi({20, 20, 10})); FIKO_KONTROL(m.noktaIcerideMi({20, 5, 17})); // Hacim: dikdortgen 20×8×6 + iki yarim silindir π·16·6 ≈ 960+301.6 ±%20 (gosterge). const f64 beklenen = 20.0 * 8.0 * 6.0 + 3.14159265358979 * 16.0 * 6.0; FIKO_YAKIN(m.kaldirilanHacimMm3(), beklenen, beklenen * 0.20); } // (T4) DC mesh: kapali + DISA sarim (isaretli hacim POZITIF ~stok−kesim) + sonlu. FIKO_TEST(tridexel_mesh_kapali_ve_yon) { TriDexelMotoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); TakimGeo t = duzTakim(10.0); m.takimUygula({20, 20, 12}, t); MeshVeri mesh; m.meshCikar(mesh); FIKO_KONTROL(mesh.vertexSayi() > 0); FIKO_KONTROL(mesh.ucgenSayi() > 0); for (f32 v : mesh.pozisyon) FIKO_KONTROL(std::isfinite(v)); auto gv = [&](u32 vi, int c) { return (f64)mesh.pozisyon[vi * 3 + c]; }; f64 V6 = 0.0; for (size_t q = 0; q + 2 < mesh.indeks.size(); q += 3) { const u32 i0 = mesh.indeks[q], i1 = mesh.indeks[q + 1], i2 = mesh.indeks[q + 2]; const f64 ax = gv(i0, 0), ay = gv(i0, 1), az = gv(i0, 2); const f64 bx = gv(i1, 0), by = gv(i1, 1), bz = gv(i1, 2); const f64 cx = gv(i2, 0), cy = gv(i2, 1), cz = gv(i2, 2); V6 += ax * (by * cz - bz * cy) + ay * (bz * cx - bx * cz) + az * (bx * cy - by * cx); } const f64 V = V6 / 6.0; FIKO_KONTROL(std::isfinite(V)); FIKO_KONTROL(V > 0.0); // disa sarim // Stok 32000 − kesim ~628 ≈ 31372 ±%15 (dugum-orta uyelik payi). FIKO_YAKIN(V, 31372.0, 31372.0 * 0.15); } // (T5) Checkpoint roundtrip: kaydet → daha oy → yukle → hacim/uyelik/mesh birebir. FIKO_TEST(tridexel_checkpoint) { TriDexelMotoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); FIKO_KONTROL(m.durumBayt() > 0); TakimGeo t = duzTakim(8.0); m.takimUygula({12, 20, 10}, t); const f64 hac1 = m.kaldirilanHacimMm3(); auto snap = m.durumKaydet(); FIKO_KONTROL(snap != nullptr); MeshVeri mesh1; m.meshCikar(mesh1); m.takimUygula({28, 20, 10}, t); FIKO_KONTROL(m.kaldirilanHacimMm3() > hac1); FIKO_KONTROL(m.durumYukle(snap)); FIKO_YAKIN(m.kaldirilanHacimMm3(), hac1, 1e-9); FIKO_KONTROL(m.noktaIcerideMi({28, 20, 15})); // 2. kesim geri geldi MeshVeri mesh2; m.meshCikar(mesh2); FIKO_KONTROL(mesh1.pozisyon.size() == mesh2.pozisyon.size()); for (size_t i = 0; i < mesh1.pozisyon.size(); ++i) FIKO_KONTROL(mesh1.pozisyon[i] == mesh2.pozisyon[i]); } // (T6) Sifirla + dayaniklilik: NaN/sifir girisler cokertmez, sifirla stok'a doner. FIKO_TEST(tridexel_sifirla_dayaniklilik) { TriDexelMotoru m; Aabbf ters; ters.asgari = {40, 40, 20}; ters.azami = {0, 0, 0}; FIKO_KONTROL(!m.kutukKur(kutuStok(), ters, 1.0)); FIKO_KONTROL(!m.sonHata().empty()); FIKO_KONTROL(m.kutukKur(kutuStok(), kutuSinir(), 1.0)); TakimGeo t = duzTakim(8.0); const f64 nan = std::numeric_limits::quiet_NaN(); m.takimUygula({nan, 20, 20}, t); m.sweptUygula({nan, 0, 0}, {10, 10, 10}, t); t.eksen = {0, 0, 0}; m.takimUygula({20, 20, 15}, t); // sifir eksen → (0,0,1) fallback FIKO_KONTROL(std::isfinite(m.kaldirilanHacimMm3())); m.sifirla(); FIKO_KONTROL(m.kaldirilanHacimMm3() == 0.0); FIKO_KONTROL(m.noktaIcerideMi({20, 20, 15})); // stok geri doldu } // (T7) Paralel batchUygula = seri per-hamle (BIREBIR): 3-eksen × v-bant paralel // carve, seri sweptUygula/takimUygula ile ayni span verisi + hacim + mesh. FIKO_TEST(tridexel_batch_seri_ile_ayni) { TakimGeo t = duzTakim(6.0); std::vector hm; auto ekle = [&](Vec3d a, Vec3d b, bool ilk) { KutukSimMotoru::KarveHamle k; k.a = a; k.b = b; k.takim = t; k.ilk = ilk; k.kesme = true; hm.push_back(k); }; ekle({10, 10, 8}, {10, 10, 8}, true); ekle({10, 10, 8}, {30, 10, 8}, false); ekle({30, 10, 8}, {30, 30, 12}, false); ekle({30, 30, 12}, {10, 30, 12}, false); ekle({10, 30, 12}, {10, 10, 8}, false); TriDexelMotoru ser; ser.kutukKur(kutuStok(), kutuSinir(), 1.0); for (const auto& k : hm) { if (k.ilk) ser.takimUygula(k.b, k.takim); else ser.sweptUygula(k.a, k.b, k.takim); } TriDexelMotoru bat; bat.kutukKur(kutuStok(), kutuSinir(), 1.0); bat.batchUygula(hm.data(), hm.size()); FIKO_YAKIN(bat.kaldirilanHacimMm3(), ser.kaldirilanHacimMm3(), 1e-6); for (int d = 0; d < 3; ++d) { const auto& ss = ser.seti(d); const auto& bs = bat.seti(d); FIKO_KONTROL(ss.kolon.size() == bs.kolon.size()); for (size_t c = 0; c < ss.kolon.size(); ++c) { FIKO_KONTROL(ss.kolon[c].size() == bs.kolon[c].size()); for (size_t i = 0; i < ss.kolon[c].size(); ++i) { FIKO_KONTROL(ss.kolon[c][i].t0 == bs.kolon[c][i].t0); FIKO_KONTROL(ss.kolon[c][i].t1 == bs.kolon[c][i].t1); } } } MeshVeri ms, mb; ser.meshCikar(ms); bat.meshCikar(mb); FIKO_KONTROL(ms.pozisyon.size() == mb.pozisyon.size()); for (size_t i = 0; i < ms.pozisyon.size(); ++i) FIKO_KONTROL(ms.pozisyon[i] == mb.pozisyon[i]); }