#include #include #include #include "fiko/cam/takim.hpp" #include "fiko/kutuk/dexel3_motor.hpp" #include "fiko/kutuk/kutuk_motor.hpp" #include "fiko/kutuk/zbuffer6_motor.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::kutuk; namespace { // 40x40x20 kutu kutuk, koki (0,0,0), cozunurluk 1mm. 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; // kutugu tamamen delip gecmeye yeter t.eksen = {0, 0, 1}; return t; } } // namespace // (1) Kutu kutuk hacmi ~ boyut carpimi (40*40*20 = 32000 mm^3). FIKO_TEST(kutu_hacim) { Dexel3Motoru m; FIKO_KONTROL(m.kutukKur(kutuStok(), kutuSinir(), 1.0)); // Dolu hacmi noktaIcerideMi ile ornekle: merkez ici, disari disi. FIKO_KONTROL(m.noktaIcerideMi({20, 20, 10})); FIKO_KONTROL(!m.noktaIcerideMi({50, 20, 10})); FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 30})); } // (2) Duz takim tek dalis -> kaldirilan hacim ~ silindir hacmi (tol %5). FIKO_TEST(duz_dalis_hacim) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 0.5); const f64 cap = 8.0; const f64 R = cap * 0.5; // Takimi kutugun icine 10mm derinlik dalar: uc z=20 (ust), boy 40 -> delip gecer. // Kutuk kalinligi 20mm, cap 8 -> silindir hacmi = pi*R^2*20. TakimGeo t = duzTakim(cap); t.boy = 40; // Uc konumu = takim ucu (en alt); govde +Z yonunde uzar. Delip gecmek icin // uc kutugun altina (z=0) inmeli -> govde [0,40] tum z=[0,20] kalinligi kaplar. m.takimUygula({20, 20, 0}, t); const f64 beklenen = 3.14159265358979 * R * R * 20.0; const f64 hac = m.kaldirilanHacimMm3(); FIKO_YAKIN(hac, beklenen, beklenen * 0.05); } // (3) Span split: ortadan kesim -> 2 span (kopru olusumu). FIKO_TEST(span_split_kopru) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); // Kutuk sutunu z=[0,20]. Ortadan (z=8..12) kesim -> [0,8]+[12,20] iki span. // Bunu bir sutunda test etmek icin ince takimla ortadan yatay kesim yerine // dogrudan noktaIcerideMi ile dogrula: kesimden sonra orta bosluk dis olmali. TakimGeo t = duzTakim(6.0); t.boy = 4.0; // sadece 4mm derinlik t.eksen = {0, 0, 1}; m.takimUygula({20, 20, 12}, t); // uc z=12, tepe z=16 -> [12,16] araligi cikar // Orta bosluk (z=14) dis, alt (z=5) ve ust (z=18) ici olmali -> 2 span. FIKO_KONTROL(m.noktaIcerideMi({20, 20, 5})); // alt span FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 14})); // kesilen bosluk FIKO_KONTROL(m.noktaIcerideMi({20, 20, 18})); // ust span (kopru) } // (4) Swept cizgi -> oluk hacmi makul (dikdortgen prizma yaklasik). FIKO_TEST(swept_oluk) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 0.5); TakimGeo t = duzTakim(6.0); t.boy = 5.0; // uc z=15 -> govde [15,20], ust yuzeyden 5mm oluk // (10,20,15)->(30,20,15) ust yuzeyde 20mm boyunca oluk. m.sweptUygula({10, 20, 15}, {30, 20, 15}, t); const f64 hac = m.kaldirilanHacimMm3(); // Oluk ~ uzunluk(20) * cap(6) * derinlik(5) = 600, uc yaricapli -> pozitif ve makul. FIKO_KONTROL(hac > 300.0 && hac < 900.0); FIKO_KONTROL(!m.supurmeCapUyarisi()); // kisa hamle cap'e takilmamali } // (5) isPointInMaterial undercut senaryosu (yatay kesim, YZ grid AND). FIKO_TEST(undercut_yatay_kesim) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); // Yatay eksende (X yonu) takim uygulayarak yan cepten malzeme al. // eksen degil, poz X yonunde bir kesim: takim +Z eksenli ama farkli sutun. // Basit undercut testi: bir bolgeyi bosalt, 3-grid AND ile dis dogrula. TakimGeo t = duzTakim(10.0); t.boy = 40; m.takimUygula({20, 20, 0}, t); // merkez delik (uc alttan, delip gecer) // Delik merkezi 3 grid'de de dis olmali (AND). FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 10})); // Kenar hala ici. FIKO_KONTROL(m.noktaIcerideMi({3, 3, 10})); } // (6) Gecersiz girdi (NaN eksen, ters bbox) cokmez. FIKO_TEST(gecersiz_girdi_dayanikli) { Dexel3Motoru m; // Ters bbox -> reddedilmeli (Turkce hata), cokmemeli. 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()); // Gecerli kur, sonra NaN eksenli/NaN pozlu takim -> cokmez. FIKO_KONTROL(m.kutukKur(kutuStok(), kutuSinir(), 2.0)); TakimGeo t = duzTakim(8.0); t.eksen = {0, 0, 0}; // sifir eksen -> (0,0,1) fallback m.takimUygula({20, 20, 20}, t); // cokmemeli const f64 nan = std::numeric_limits::quiet_NaN(); m.takimUygula({nan, 20, 20}, t); // NaN poz -> atla m.sweptUygula({nan, 0, 0}, {10, 10, 10}, t); // NaN uc -> atla FIKO_KONTROL(std::isfinite(m.kaldirilanHacimMm3())); } // (7) Cok-span heightmap dogrulugu + bos kutuk bos mesh (NaN bbox yok). FIKO_TEST(mesh_cokspan_ve_bos) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 1.0); MeshVeri mesh; m.meshCikar(mesh); FIKO_KONTROL(mesh.vertexSayi() > 0); FIKO_KONTROL(mesh.ucgenSayi() > 0); // Sinir sonlu olmali (NaN bbox uretme gotcha). FIKO_KONTROL(std::isfinite(mesh.sinir.asgari.x) && std::isfinite(mesh.sinir.azami.z)); // Bos/dejenerre kutuk -> bos mesh, NaN bbox ASLA. Dexel3Motoru bos; cam::Stok s = kutuStok(); Aabbf dejenerre; dejenerre.asgari = {0, 0, 0}; dejenerre.azami = {0, 0, 0}; // sifir hacim FIKO_KONTROL(bos.kutukKur(s, dejenerre, 1.0)); // basari ama bos MeshVeri bosMesh; bos.meshCikar(bosMesh); FIKO_KONTROL(bosMesh.vertexSayi() == 0); FIKO_KONTROL(!bos.noktaIcerideMi({0, 0, 0})); // bos -> icerde degil } // (8) Fabrika + kip: Dexel3 + ZBuffer6 + SDF_MC gecerli, VoxelBrick nullptr. FIKO_TEST(fabrika_kip) { auto d = kutukMotoruYap(KutukSimKip::Dexel3); FIKO_KONTROL(d != nullptr); FIKO_KONTROL(d->kip() == KutukSimKip::Dexel3); auto z = kutukMotoruYap(KutukSimKip::ZBuffer6); FIKO_KONTROL(z != nullptr); FIKO_KONTROL(z->kip() == KutukSimKip::ZBuffer6); auto s = kutukMotoruYap(KutukSimKip::SDF_MC); // DALGA 4: artik gecerli FIKO_KONTROL(s != nullptr); FIKO_KONTROL(s->kip() == KutukSimKip::SDF_MC); FIKO_KONTROL(kutukMotoruYap(KutukSimKip::VoxelBrick) == nullptr); // sonraki dalga } // ============================================================================ // ZBuffer6 CPU backend testleri (DALGA 3) // ============================================================================ // (Z1) Kutu kutuk hacmi: +Z koridor icinde/disinda dogru (noktaIcerideMi). FIKO_TEST(zbuf_kutu_hacim) { ZBuffer6Motoru m; FIKO_KONTROL(m.kutukKur(kutuStok(), kutuSinir(), 1.0)); FIKO_KONTROL(m.noktaIcerideMi({20, 20, 10})); // ici FIKO_KONTROL(!m.noktaIcerideMi({50, 20, 10})); // XY disi FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 30})); // Z disi (koridor ustu) FIKO_KONTROL(!m.noktaIcerideMi({20, 20, -5})); // koridor alti } // (Z2) Duz takim tek dalis -> kaldirilan hacim ~ silindir hacmi (tol %5). FIKO_TEST(zbuf_dalis_hacim) { ZBuffer6Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 0.5); const f64 cap = 8.0; const f64 R = cap * 0.5; TakimGeo t = duzTakim(cap); t.boy = 40; // delip gecer (uc z=0 -> govde [0,40] tum kalinligi kaplar) m.takimUygula({20, 20, 0}, t); const f64 beklenen = 3.14159265358979 * R * R * 20.0; const f64 hac = m.kaldirilanHacimMm3(); FIKO_YAKIN(hac, beklenen, beklenen * 0.05); } // (Z3) Delinme guard: takim tum koridoru kapsar -> piksel bosalt (near>=far). FIKO_TEST(zbuf_delinme_guard) { ZBuffer6Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 0.5); TakimGeo t = duzTakim(10.0); t.boy = 40; m.takimUygula({20, 20, 0}, t); // merkez delik (delip gecer) // Delik merkezi artik dis olmali (koridor bosaldi). FIKO_KONTROL(!m.noktaIcerideMi({20, 20, 10})); // Kenar hala ici. FIKO_KONTROL(m.noktaIcerideMi({3, 3, 10})); FIKO_KONTROL(std::isfinite(m.kaldirilanHacimMm3())); } // (Z4) Gecersiz girdi: ters bbox reddi + NaN eksen/poz cokmez + bos mesh NaN yok. FIKO_TEST(zbuf_gecersiz_girdi) { ZBuffer6Motoru 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(), 2.0)); TakimGeo t = duzTakim(8.0); t.eksen = {0, 0, 0}; // sifir eksen -> (0,0,1) fallback m.takimUygula({20, 20, 20}, t); const f64 nan = std::numeric_limits::quiet_NaN(); m.takimUygula({nan, 20, 20}, t); m.sweptUygula({nan, 0, 0}, {10, 10, 10}, t); FIKO_KONTROL(std::isfinite(m.kaldirilanHacimMm3())); // Mesh sonlu bbox + bos kutuk bos mesh. MeshVeri mesh; m.meshCikar(mesh); FIKO_KONTROL(mesh.vertexSayi() > 0); FIKO_KONTROL(std::isfinite(mesh.sinir.asgari.x) && std::isfinite(mesh.sinir.azami.z)); ZBuffer6Motoru bos; Aabbf dejenerre; dejenerre.asgari = {0, 0, 0}; dejenerre.azami = {0, 0, 0}; FIKO_KONTROL(bos.kutukKur(kutuStok(), dejenerre, 1.0)); MeshVeri bosMesh; bos.meshCikar(bosMesh); FIKO_KONTROL(bosMesh.vertexSayi() == 0); FIKO_KONTROL(!bos.noktaIcerideMi({0, 0, 0})); } // (Z5) CAPRAZ DOGRULAMA: ayni dalis senaryosunda Dexel3 vs ZBuffer6 hacim ±%10. FIKO_TEST(zbuf_dexel_capraz) { const f64 cap = 8.0; TakimGeo t = duzTakim(cap); t.boy = 40; Dexel3Motoru d; d.kutukKur(kutuStok(), kutuSinir(), 0.5); d.takimUygula({20, 20, 0}, t); const f64 hd = d.kaldirilanHacimMm3(); ZBuffer6Motoru z; z.kutukKur(kutuStok(), kutuSinir(), 0.5); z.takimUygula({20, 20, 0}, t); const f64 hz = z.kaldirilanHacimMm3(); FIKO_KONTROL(hd > 0 && hz > 0); // Iki backend ayni hacmi ±%10 dogrulukla vermeli (kanonik dogruluk karsilastirmasi). FIKO_YAKIN(hz, hd, hd * 0.10); } // ============================================================================ // SIM -> KUTUK ENTEGRASYON-YAKINI (cam_simulasyon_penceresi oyma yolu) // ---------------------------------------------------------------------------- // Sim penceresi: cam::Takim -> TakimGeo (takimGeoYap) + SimNokta dizisi -> // swept/takimUygula batch. Bu testler UI'siz o veri akisini dogrular. // ============================================================================ // (E1) cam::Takim -> TakimGeo donusumu: tip/cap/kose/eksen dogru tasinir. FIKO_TEST(sim_takim_geo_donusum) { cam::Takim parmak; parmak.tip = cam::TakimTip::ParmakFreze; parmak.cap = 12.0; parmak.boy = 40.0; TakimGeo tg = takimGeoYap(parmak); FIKO_KONTROL(tg.tip == TakimGeo::Tip::Duz); FIKO_YAKIN(tg.cap, 12.0, 1e-6); cam::Takim kuresel; kuresel.tip = cam::TakimTip::KureselFreze; kuresel.cap = 8.0; TakimGeo tk = takimGeoYap(kuresel); FIKO_KONTROL(tk.tip == TakimGeo::Tip::Kuresel); FIKO_YAKIN(tk.cap, 8.0, 1e-6); // Eksen birim (gecersizse (0,0,1) fallback) — sonlu olmali. FIKO_KONTROL(std::isfinite(tg.eksen.z) && std::isfinite(tk.eksen.z)); } // (E2) SimNokta dizisi -> batch swept oyma: kaldirilan hacim > 0, sinir sonlu. // Sim penceresi kutukBatchOy mantiginin cekirdek karsiligi (isleme hamleleri swept). FIKO_TEST(sim_batch_oyma_hacim) { Dexel3Motoru m; m.kutukKur(kutuStok(), kutuSinir(), 0.5); cam::Takim t; t.tip = cam::TakimTip::ParmakFreze; t.cap = 6.0; TakimGeo tg = takimGeoYap(t); tg.boy = 5.0; // uc z=15 -> ust yuzeyde 5mm oluk // SimNokta konumlari (ust yuzeyde dikdortgen tarama, isleme hamleleri). std::vector yol = { {8, 10, 15}, {32, 10, 15}, {32, 20, 15}, {8, 20, 15}, {8, 30, 15}, {32, 30, 15}}; // Batch: onceki nokta -> guncel nokta swept (ilk nokta konumlama). bool sonVar = false; Vec3d son{}; for (const Vec3d& p : yol) { if (sonVar) m.sweptUygula(son, p, tg); son = p; sonVar = true; } const f64 hac = m.kaldirilanHacimMm3(); FIKO_KONTROL(hac > 0.0); // batch oyma sonrasi hacim > 0 FIKO_KONTROL(std::isfinite(hac)); // Mesh cikar: sinir sonlu (NaN fit gotcha yok), ucgen var. MeshVeri mesh; m.meshCikar(mesh); FIKO_KONTROL(mesh.ucgenSayi() > 0); FIKO_KONTROL(std::isfinite(mesh.sinir.asgari.x) && std::isfinite(mesh.sinir.azami.z)); }