#include #include #include #include #include #include #include #include #include "fiko/geometri/brep.hpp" #include "fiko/geometri/kalite.hpp" #include "fiko/core/gunluk.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::geometri; namespace { // Diverjans teoremiyle isaretli hacim: ucgenleme kapali + disari donuk mu? f64 isaretliHacim(const MeshVeri& v) { f64 toplam = 0; for (size_t i = 0; i + 2 < v.indeksler.size(); i += 3) { const auto& a = v.vertexler[v.indeksler[i]].konum; const auto& b = v.vertexler[v.indeksler[i + 1]].konum; const auto& c = v.vertexler[v.indeksler[i + 2]].konum; const Vec3d va{a[0], a[1], a[2]}, vb{b[0], b[1], b[2]}, vc{c[0], c[1], c[2]}; toplam += va.nokta(vb.capraz(vc)) / 6.0; } return toplam; } } FIKO_TEST(brep_kutu_hacim_alan) { const BrepGovde g = kutu(2, 3, 4); FIKO_KONTROL(g.gecerliMi()); FIKO_YAKIN(g.hacim(), 24.0, 1e-6); FIKO_YAKIN(g.alan(), 2 * (2 * 3 + 3 * 4 + 2 * 4), 1e-6); } FIKO_TEST(brep_stl_export) { const BrepGovde g = kutu(2, 3, 4); namespace fs = std::filesystem; std::error_code ec; const std::string yol = (fs::temp_directory_path() / "fiko_test_kutu.stl").string(); const std::string yolA = (fs::temp_directory_path() / "fiko_test_kutu_a.stl").string(); fs::remove(yol, ec); fs::remove(yolA, ec); // Binary STL: yazılmalı + dosya var + anlamlı boyut (kutu = 12 üçgen → ~684 bayt). FIKO_KONTROL(stlKaydet({&g}, yol, /*ikili*/ true, 0.1)); FIKO_KONTROL(fs::exists(yol) && fs::file_size(yol) > 100); // ASCII STL: yazılmalı + dosya var (ASCII daha büyük). FIKO_KONTROL(stlKaydet({&g}, yolA, /*ikili*/ false, 0.1)); FIKO_KONTROL(fs::exists(yolA) && fs::file_size(yolA) > 100); // Geçersiz girdi: boş liste → false (dosya yazma yok). FIKO_KONTROL(!stlKaydet({}, yol, true, 0.1)); fs::remove(yol, ec); fs::remove(yolA, ec); } FIKO_TEST(brep_iges_export) { const BrepGovde g = kutu(2, 3, 4); namespace fs = std::filesystem; std::error_code ec; const std::string yol = (fs::temp_directory_path() / "fiko_test_kutu.iges").string(); fs::remove(yol, ec); FIKO_KONTROL(igesKaydet({&g}, yol)); FIKO_KONTROL(fs::exists(yol) && fs::file_size(yol) > 100); FIKO_KONTROL(!igesKaydet({}, yol)); // boş liste → false fs::remove(yol, ec); } FIKO_TEST(brep_obj_export) { const BrepGovde g = kutu(2, 3, 4); namespace fs = std::filesystem; std::error_code ec; const std::string yol = (fs::temp_directory_path() / "fiko_test_kutu.obj").string(); fs::remove(yol, ec); FIKO_KONTROL(objKaydet({&g}, yol)); FIKO_KONTROL(fs::exists(yol) && fs::file_size(yol) > 50); // v/f satırları var FIKO_KONTROL(!objKaydet({}, yol)); // boş liste → false fs::remove(yol, ec); } FIKO_TEST(brep_kutle_ozellikleri) { const BrepGovde g = kutu(2, 3, 4); // hacim 24 const KutleOzellik k = kutleOzellikleri(g); // varsayılan çelik 7.85e-6 kg/mm³ FIKO_KONTROL(k.gecerli); FIKO_YAKIN(k.hacim, 24.0, 1e-6); FIKO_YAKIN(k.kutle, 24.0 * 7.85e-6, 1e-12); // Asal eksenler birim vektör (nokta çarpımı kendisiyle = 1). FIKO_YAKIN(k.asalEksen1.nokta(k.asalEksen1), 1.0, 1e-9); FIKO_YAKIN(k.asalEksen2.nokta(k.asalEksen2), 1.0, 1e-9); FIKO_YAKIN(k.asalEksen3.nokta(k.asalEksen3), 1.0, 1e-9); // Kutu 2×3×4 asal atalet (CoG, geometrik): V(b²+c²)/12 → {26,40,50}, toplam 116. const f64 geoToplam = (k.asalAtalet.x + k.asalAtalet.y + k.asalAtalet.z) / 7.85e-6; FIKO_YAKIN(geoToplam, 116.0, 1e-2); // Geçersiz gövde → gecerli=false. FIKO_KONTROL(!kutleOzellikleri(BrepGovde{}).gecerli); } FIKO_TEST(brep_cad_diff) { const BrepGovde a = kutu(2, 2, 2); // hacim 8 const BrepGovde a2 = kutu(2, 2, 2); // özdeş const KarsilastirmaSonuc ozdes = karsilastir(a, a2); FIKO_KONTROL(ozdes.gecerli && ozdes.ozdesMi); FIKO_YAKIN(ozdes.aFazla, 0.0, 1e-4); FIKO_YAKIN(ozdes.bFazla, 0.0, 1e-4); FIKO_YAKIN(ozdes.ortak, 8.0, 1e-3); // A ⊂ B: kutu(2,2,2) ⊂ kutu(4,2,2) (aynı köşe/merkez) → A'da fazla yok, B'de fazla 8. const BrepGovde b = kutu(4, 2, 2); // hacim 16 const KarsilastirmaSonuc fark = karsilastir(a, b); FIKO_KONTROL(fark.gecerli && !fark.ozdesMi); FIKO_YAKIN(fark.aFazla, 0.0, 1e-3); // A ⊂ B FIKO_YAKIN(fark.bFazla, 8.0, 1e-3); // 16 − 8 FIKO_YAKIN(fark.ortak, 8.0, 1e-3); // ortak = A FIKO_KONTROL(!karsilastir(BrepGovde{}, a).gecerli); // geçersiz girdi } FIKO_TEST(brep_orto_izdusum) { const BrepGovde g = kutu(2, 3, 4); // X=2, Y=3, Z=4 // Ön görünüm (-Y bakış) → kesit X×Z = 2×4 boyutlu. const Izdusum2D on = ortoIzdusum(g, Gorunum::On); FIKO_KONTROL(on.gecerli); FIKO_KONTROL(!on.gorunur.empty()); // görünür kenarlar üretildi f64 minX = 1e18, maxX = -1e18, minY = 1e18, maxY = -1e18; for (const auto& pl : on.gorunur) for (const auto& p : pl) { minX = std::min(minX, p.x); maxX = std::max(maxX, p.x); minY = std::min(minY, p.y); maxY = std::max(maxY, p.y); } const f64 w = maxX - minX, h = maxY - minY; // Kesit 2×4 (izdüşüm eksen sırasından bağımsız: küçük=2, büyük=4). FIKO_YAKIN(std::min(w, h), 2.0, 1e-3); FIKO_YAKIN(std::max(w, h), 4.0, 1e-3); // Üst görünüm de geçerli + kenar üretir (kesit X×Y = 2×3). const Izdusum2D ust = ortoIzdusum(g, Gorunum::Ust); FIKO_KONTROL(ust.gecerli && !ust.gorunur.empty()); // Geçersiz gövde. FIKO_KONTROL(!ortoIzdusum(BrepGovde{}, Gorunum::On).gecerli); } FIKO_TEST(brep_dxf_export) { const BrepGovde g = kutu(2, 3, 4); namespace fs = std::filesystem; std::error_code ec; const std::string yol = (fs::temp_directory_path() / "fiko_test_kutu.dxf").string(); fs::remove(yol, ec); FIKO_KONTROL(dxfKaydet(g, Gorunum::On, yol)); FIKO_KONTROL(fs::exists(yol) && fs::file_size(yol) > 50); // LINE entity'leri FIKO_KONTROL(!dxfKaydet(BrepGovde{}, Gorunum::On, yol)); // geçersiz gövde → false fs::remove(yol, ec); } FIKO_TEST(brep_izdusum_alani) { const BrepGovde g = kutu(2, 3, 4); // X=2, Y=3, Z=4 // Y yönü (ön) izdüşümü → X×Z kesiti = 2×4 = 8. FIKO_YAKIN(izdusumAlani(g, {0, 1, 0}), 8.0, 1e-6); // Z yönü (üst) → X×Y = 2×3 = 6. FIKO_YAKIN(izdusumAlani(g, {0, 0, 1}), 6.0, 1e-6); // X yönü (yan) → Y×Z = 3×4 = 12. FIKO_YAKIN(izdusumAlani(g, {1, 0, 0}), 12.0, 1e-6); // Yön uzunluğundan bağımsız (normalize). FIKO_YAKIN(izdusumAlani(g, {0, 5, 0}), 8.0, 1e-6); // Geçersiz gövde / sıfır yön → 0. FIKO_YAKIN(izdusumAlani(BrepGovde{}, {0, 1, 0}), 0.0, 1e-12); FIKO_YAKIN(izdusumAlani(g, {0, 0, 0}), 0.0, 1e-12); } FIKO_TEST(brep_topoloji_ozeti) { const BrepGovde g = kutu(2, 3, 4); const TopolojiOzet t = topolojiOzeti(g); FIKO_KONTROL(t.gecerliGovde && t.gecerli); // BRepCheck geçerli FIKO_KONTROL(t.vertexSayi == 8); // kutu: 8 köşe FIKO_KONTROL(t.kenarSayi == 12); // 12 kenar FIKO_KONTROL(t.yuzSayi == 6); // 6 yüz FIKO_KONTROL(t.kabukSayi == 1 && t.katiSayi == 1); // Geçersiz gövde → tümü sıfır, gecerliGovde false. const TopolojiOzet bos = topolojiOzeti(BrepGovde{}); FIKO_KONTROL(!bos.gecerliGovde && bos.vertexSayi == 0); } FIKO_TEST(brep_mesafe) { const BrepGovde a = kutu(2, 2, 2); // merkezli: X ∈ [-1, 1] Donusumd kaydir; kaydir.konum = {5, 0, 0}; const BrepGovde b = donusumUygula(kutu(2, 2, 2), kaydir); // X ∈ [4, 6] FIKO_YAKIN(mesafe(a, b), 3.0, 1e-6); // boşluk = 4 − 1 = 3 FIKO_YAKIN(mesafe(a, a), 0.0, 1e-6); // aynı gövde → çakışma → 0 FIKO_KONTROL(mesafe(BrepGovde{}, a) < 0); // geçersiz girdi → -1 } FIKO_TEST(brep_kenar_uzunlugu) { // Kutu 2×3×4: 4 kenar×2 (X) + 4×3 (Y) + 4×4 (Z) = 8+12+16 = 36. FIKO_YAKIN(kenarUzunlugu(kutu(2, 3, 4)), 36.0, 1e-6); // Küp 2×2×2: 12 kenar × 2 = 24. FIKO_YAKIN(kenarUzunlugu(kutu(2, 2, 2)), 24.0, 1e-6); FIKO_YAKIN(kenarUzunlugu(BrepGovde{}), 0.0, 1e-12); // geçersiz → 0 } FIKO_TEST(brep_yuz_tipleri) { // Kutu: 6 düzlemsel yüz. const YuzTipOzet k = yuzTipleri(kutu(2, 2, 2)); FIKO_KONTROL(k.duzlemsel == 6 && k.silindirik == 0); // Silindir: 2 düzlemsel kapak + 1 silindirik yan. const YuzTipOzet s = yuzTipleri(silindir(5, 10)); FIKO_KONTROL(s.duzlemsel == 2 && s.silindirik == 1); // Küre: 1 küresel yüz. const YuzTipOzet ku = yuzTipleri(kure(5)); FIKO_KONTROL(ku.kuresel == 1); // Koni: 1 düzlemsel taban + 1 konik yan. const YuzTipOzet ko = yuzTipleri(koni(5, 10)); FIKO_KONTROL(ko.duzlemsel == 1 && ko.konik == 1); } FIKO_TEST(brep_silindir_yaricaplari) { // Silindir(yarıçap 5): tek silindirik yüz → {5}. const auto s = silindirYaricaplari(silindir(5, 10)); FIKO_KONTROL(s.size() == 1); FIKO_YAKIN(s[0], 5.0, 1e-6); // Kutu: silindirik yüz yok → boş. FIKO_KONTROL(silindirYaricaplari(kutu(2, 2, 2)).empty()); FIKO_KONTROL(silindirYaricaplari(BrepGovde{}).empty()); // geçersiz } FIKO_TEST(brep_sinir_boyutu) { // Kutu 2×3×4 → AABB {2, 3, 4} (Bnd_Box küçük tolerans payı için gevşek tolerans). const Vec3d b = sinirBoyutu(kutu(2, 3, 4)); FIKO_YAKIN(b.x, 2.0, 1e-2); FIKO_YAKIN(b.y, 3.0, 1e-2); FIKO_YAKIN(b.z, 4.0, 1e-2); // Küre yarıçap 5 → AABB {10, 10, 10}. const Vec3d k = sinirBoyutu(kure(5)); FIKO_YAKIN(k.x, 10.0, 1e-2); FIKO_YAKIN(k.y, 10.0, 1e-2); FIKO_YAKIN(k.z, 10.0, 1e-2); // Geçersiz → {0,0,0}. const Vec3d s = sinirBoyutu(BrepGovde{}); FIKO_KONTROL(s.x == 0 && s.y == 0 && s.z == 0); } FIKO_TEST(brep_sinir_silindir) { // Z-eksenli silindir(yarıçap 5, boy 10) → Z boyunca sınır silindiri = kendisi. const SilindirSinir c = sinirSilindir(silindir(5, 10), {0, 0, 0}, {0, 0, 1}); FIKO_YAKIN(c.yaricap, 5.0, 1e-3); FIKO_YAKIN(c.uzunluk, 10.0, 1e-3); // Kutu 2×2×2 Z boyunca → yarıçap = köşe XY mesafesi = √2, uzunluk = 2. const SilindirSinir k = sinirSilindir(kutu(2, 2, 2), {0, 0, 0}, {0, 0, 1}); FIKO_YAKIN(k.yaricap, 1.41421356, 1e-4); FIKO_YAKIN(k.uzunluk, 2.0, 1e-3); // Geçersiz gövde / sıfır eksen → sıfır. FIKO_KONTROL(sinirSilindir(BrepGovde{}, {0, 0, 0}, {0, 0, 1}).yaricap == 0); FIKO_KONTROL(sinirSilindir(silindir(5, 10), {0, 0, 0}, {0, 0, 0}).yaricap == 0); } FIKO_TEST(brep_kure_silindir_koni_hacim) { const f64 pi = std::numbers::pi; FIKO_YAKIN(kure(1.5).hacim(), 4.0 / 3.0 * pi * 1.5 * 1.5 * 1.5, 1e-6); FIKO_YAKIN(silindir(1, 2).hacim(), pi * 2, 1e-6); FIKO_YAKIN(koni(1, 3).hacim(), pi, 1e-6); } FIKO_TEST(brep_boolean_birlesim_cikarma) { // Iki 1x1x1 kup, yarim ortusme -> birlesim 1.5, cikarma 0.5, kesisim 0.5 const BrepGovde a = kutu(1, 1, 1); Donusumd kaydir; kaydir.konum = {0.5, 0, 0}; const BrepGovde b = donusumUygula(kutu(1, 1, 1), kaydir); FIKO_YAKIN(birlesim(a, b).hacim(), 1.5, 1e-6); FIKO_YAKIN(cikarma(a, b).hacim(), 0.5, 1e-6); FIKO_YAKIN(kesisim(a, b).hacim(), 0.5, 1e-6); } FIKO_TEST(brep_cikinti_kaydir) { // Plaka (20×20×2, üst yüz z=1) + üstünde çıkıntı (4×4×4, z∈[1,5]) fuse → tek katı. // Çıkıntıyı taban düzlemi (z=1) boyunca +6 X kaydır → hacim korunur (rijit), CoG X kayar. const BrepGovde plaka = kutu(20, 20, 2); // z ∈ [-1, 1], üst yüz z=1 Donusumd yukari; yukari.konum = {0, 0, 3}; // 4×4×4 kutu z∈[-2,2] → z∈[1,5] const BrepGovde cikinti = donusumUygula(kutu(4, 4, 4), yukari); const BrepGovde katı = birlesim(plaka, cikinti); FIKO_KONTROL(katı.gecerliMi()); const f64 hacim0 = katı.hacim(); // 20*20*2 + 4*4*4 = 800 + 64 = 864 FIKO_YAKIN(hacim0, 864.0, 1e-4); const BrepGovde tasindi = cikintiKaydir(katı, {0, 0, 1}, {0, 0, 1}, {6, 0, 0}, {0, 0, 5}); FIKO_KONTROL(tasindi.gecerliMi()); FIKO_YAKIN(tasindi.hacim(), 864.0, 1e-3); // rijit kaydırma → hacim değişmez // Çıkıntı X+6 taşındı → toplam CoG X = (800*0 + 64*6)/864 ≈ 0.4444 (plaka merkezde kaldı). const KutleOzellik ko = kutleOzellikleri(tasindi); FIKO_KONTROL(ko.gecerli); FIKO_YAKIN(ko.agirlikMerkezi.x, 64.0 * 6.0 / 864.0, 1e-2); } FIKO_TEST(brep_cikinti_taban_otomatik) { // Plaka + çıkıntı fuse; çıkıntının üst yüzünden taban düzlemi (z=1) OTOMATİK bulunmalı. const BrepGovde plaka = kutu(20, 20, 2); // üst yüz z=1 Donusumd yukari; yukari.konum = {0, 0, 3}; const BrepGovde katı = birlesim(plaka, donusumUygula(kutu(4, 4, 4), yukari)); // çıkıntı z∈[1,5] FIKO_KONTROL(katı.gecerliMi()); // Çıkıntının üst yüzü: normal +Z, merkez z≈5 olan düz yüzü bul. u32 ustYuz = 0; for (u32 i = 1; i <= 30 && !ustYuz; ++i) { YuzBilgi yb; if (katı.yuzBilgi(i, yb) && yb.duzlemMi && yb.normal.birim().z > 0.9 && yb.merkez.z > 4.0) ustYuz = i; } FIKO_KONTROL(ustYuz != 0); const CikintiTabanSonuc t = cikintiTabanBul(katı, ustYuz); FIKO_KONTROL(t.gecerli); FIKO_YAKIN(t.nokta.z, 1.0, 1e-4); // taban düzlemi çıkıntının dibinde (z=1) FIKO_YAKIN(t.normal.z, 1.0, 1e-4); // normal +Z FIKO_KONTROL(!t.tamGovde); // kaynamış (bölge tüm gövde değil) FIKO_KONTROL(t.bolgeYuzler.size() >= 5); // üst + 4 duvar } FIKO_TEST(brep_cikinti_standalone_govde) { // Tek başına kutu (fuse yok) → tamGovde=true (çıkıntı değil, ayrı katı → düğüm ötele yolu). const BrepGovde kt = kutu(4, 4, 4); u32 ustYuz = 0; for (u32 i = 1; i <= 6 && !ustYuz; ++i) { YuzBilgi yb; if (kt.yuzBilgi(i, yb) && yb.duzlemMi && yb.normal.birim().z > 0.9) ustYuz = i; } FIKO_KONTROL(ustYuz != 0); const CikintiTabanSonuc t = cikintiTabanBul(kt, ustYuz); FIKO_KONTROL(t.gecerli); FIKO_KONTROL(t.tamGovde); // 6 yüz, bölge=5 (üst+4 duvar) ≥ 6-1 → standalone } FIKO_TEST(brep_cikinti_taban_kavisli_gecersiz) { // Graceful-fail: düz OLMAYAN (küre) yüzde cikintiTabanBul geçersiz döner (çökme yok). Gizmo // döndürme/Blok-Kaydır bu durumda jesti iptal edip "açı verilemiyor" uyarısı verir (kullanıcı-kritik). const BrepGovde k = kure(5); const CikintiTabanSonuc t = cikintiTabanBul(k, 1); // küre yüzeyi → duzlemMi false FIKO_KONTROL(!t.gecerli); const CikintiTabanSonuc t0 = cikintiTabanBul(k, 0); // ordinal 0 → geçersiz FIKO_KONTROL(!t0.gecerli); } FIKO_TEST(brep_blok_kaydir_otomatik_taban) { // "Blok Kaydır" KOMUT YOLU zinciri: cikintiTabanBul (OTOMATİK taban) → cikintiKaydir. // Boss'u kendi tabanı boyunca +X kaydır → hacim korunur (rijit), sonuç geçerli. const BrepGovde plaka = kutu(20, 20, 2); // üst yüz z=1 Donusumd yukari; yukari.konum = {0, 0, 3}; const BrepGovde katı = birlesim(plaka, donusumUygula(kutu(4, 4, 4), yukari)); // çıkıntı z∈[1,5] FIKO_KONTROL(katı.gecerliMi()); const f64 hacim0 = katı.hacim(); // 864 // Çıkıntının üst yüzü (normal +Z, merkez z≈5). u32 ust = 0; Vec3d ustMerkez; for (u32 i = 1; i <= 30 && !ust; ++i) { YuzBilgi yb; if (katı.yuzBilgi(i, yb) && yb.duzlemMi && yb.normal.birim().z > 0.9 && yb.merkez.z > 4.0) { ust = i; ustMerkez = yb.merkez; } } FIKO_KONTROL(ust != 0); const CikintiTabanSonuc ts = cikintiTabanBul(katı, ust); // OTOMATİK taban (komut böyle bulur) FIKO_KONTROL(ts.gecerli && !ts.tamGovde); FIKO_YAKIN(ts.nokta.z, 1.0, 1e-4); // Komut: yön taban düzlemine izdüşür (teğet); burada +X zaten teğet. seed = üst yüz merkezi. const BrepGovde d = cikintiKaydir(katı, ts.nokta, ts.normal, {6, 0, 0}, ustMerkez); FIKO_KONTROL(d.gecerliMi()); FIKO_YAKIN(d.hacim(), hacim0, 1e-3); // rijit kaydırma → hacim değişmez } FIKO_TEST(brep_yuz_dondur_dikey_eksen) { // yuzDondur (döndürme yayı gerçek geometri): boss'u kendi tabanı (z=1) üstünde DİKEY eksen (Z, // boss merkezinden) etrafında 30° RİJİT döndür → hacim korunur, bağlantı kopmaz (footprint döner // ama taban düzleminde kalır → Fuse temiz). cikintiKaydir'ın rotasyon ikizi. const BrepGovde plaka = kutu(20, 20, 2); // üst yüz z=1 Donusumd yukari; yukari.konum = {0, 0, 3}; const BrepGovde katı = birlesim(plaka, donusumUygula(kutu(4, 4, 4), yukari)); // çıkıntı z∈[1,5] FIKO_KONTROL(katı.gecerliMi()); const f64 hacim0 = katı.hacim(); // 864 // Dikey eksen (0,0,1) boss merkezinden, taban z=1, seed = boss üst merkezi (0,0,5). const BrepGovde d = yuzDondur(katı, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, 30.0, {0, 0, 5}); FIKO_KONTROL(d.gecerliMi()); FIKO_YAKIN(d.hacim(), hacim0, 1e-3); // rijit döndürme (dikey eksen) → hacim değişmez // Sıfır açı / eksensiz → no-op (geçersiz gövde; uygulanmaz, jest güvenli). const BrepGovde n = yuzDondur(katı, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, 0.0, {0, 0, 5}); FIKO_KONTROL(!n.gecerliMi()); } FIKO_TEST(brep_yuz_dondur_tek_kutu_ayrismaz) { // A1 teşhis repro (Fikri "hep hata veriyor"): ÇIKINTISIZ tek kutuda taban = ÜST yüz → // düzlemin üstünde parça yok → motor GÜVENLE boş döner (çökme yok). App bu durumda // artık somut neden yazar ("taban bulunamadı / ayrışmadı" — worker s.hata köprüsü). const BrepGovde k = kutu(20, 20, 10); // üst yüz z=5 const BrepGovde d = yuzDondur(k, {0, 0, 5}, {0, 0, 1}, {0, 0, 5}, {0, 0, 1}, 15.0, {0, 0, 6}); FIKO_KONTROL(!d.gecerliMi()); // Taban ORTADAN geçerse üst yarı ayrışır → döndürme ÇALIŞIR (davranış belgesi: // "çıkıntı" = düzlem üstündeki ayrık parça; kullanıcı yüz eğme bekliyorsa Draft yolu). const BrepGovde o = yuzDondur(k, {0, 0, 0}, {0, 0, 1}, {0, 0, 0}, {0, 0, 1}, 20.0, {0, 0, 4}); FIKO_KONTROL(o.gecerliMi()); } FIKO_TEST(brep_yuzdraft_taban_notral) { // "Yüze açı verme" (gizmo döndürme yayı) fix'i: draft NÖTR = çıkıntı taban düzlemi (bbox merkez // DEĞİL). Boss duvarını taban (z=1) nötrüyle 10° drafla → geçerli + hacim değişir (duvar eğilir). const BrepGovde plaka = kutu(20, 20, 2); // üst yüz z=1 Donusumd yukari; yukari.konum = {0, 0, 3}; const BrepGovde katı = birlesim(plaka, donusumUygula(kutu(4, 4, 4), yukari)); // çıkıntı z∈[1,5] FIKO_KONTROL(katı.gecerliMi()); const f64 hacim0 = katı.hacim(); // Boss DUVARI: düz + düşey (|normal.z|~0) + taban üstünde (merkez.z>1.5). u32 duvar = 0; for (u32 i = 1; i <= 40 && !duvar; ++i) { YuzBilgi yb; if (katı.yuzBilgi(i, yb) && yb.duzlemMi && std::abs(yb.normal.birim().z) < 0.1 && yb.merkez.z > 1.5) duvar = i; } FIKO_KONTROL(duvar != 0); // Nötr = taban düzlemi (nokta z=1, normal +Z); çekme +Z. Duvar tabandan döner. const BrepGovde d = yuzDraft(katı, {duvar}, 10.0, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, false); FIKO_KONTROL(d.gecerliMi()); FIKO_KONTROL(std::abs(d.hacim() - hacim0) > 1e-3); // draft geometriyi değiştirdi (duvar eğildi) } FIKO_TEST(brep_ucgenleme_kapali_ve_disari) { const BrepGovde g = kutu(2, 2, 2); const MeshVeri v = g.ucgenle({1, 1, 1}); FIKO_KONTROL(!v.vertexler.empty()); FIKO_YAKIN(isaretliHacim(v), 8.0, 0.01); FIKO_KONTROL(v.sinir.boyut().yaklasikEsit({2, 2, 2}, 1e-4f)); const MeshVeri k = kure(1).ucgenle({1, 1, 1}, 0.002); FIKO_YAKIN(isaretliHacim(k), 4.0 / 3.0 * std::numbers::pi, 0.05); } FIKO_TEST(brep_3d_pah_tum_kenarlar) { // 2x2x2 kutu (hacim 8), 12 kenar. Hepsine 0.5 pah → geçerli + hacim azalır. const BrepGovde g = kutu(2, 2, 2); std::vector kenarlar; for (u32 i = 1; i <= 12; ++i) kenarlar.push_back(i); const BrepGovde p = pahla(g, kenarlar, 0.5); FIKO_KONTROL(p.gecerliMi()); FIKO_KONTROL(p.hacim() > 0.0 && p.hacim() < 8.0); // köşe malzemesi kalktı } FIKO_TEST(brep_3d_yuvarlat_tek_kenar) { // Tek kenara r=0.4 yuvarlatma → geçerli + hacim biraz azalır (dış köşe). const BrepGovde g = kutu(2, 2, 2); const BrepGovde y = yuvarlat(g, {1}, 0.4); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(y.hacim() > 0.0 && y.hacim() < 8.0); } FIKO_TEST(ucgenle_kaba_ince_ayni_shape_bagimsiz) { // Orbit LOD regresyonu: İNCE tessellation'dan SONRA aynı gövdeden KABA istenirse // OCCT IncrementalMesh mevcut (daha ince) üçgenlemeyi "yeterli" sayıp ATLAR → // "kaba" mesh sessizce ince meshin kopyası olur (LOD çalışmaz, dev modelde orbit // kasar). ucgenle açık-kaliteOrani'da bağımsız kopya üzerinde mesh'lemeli. const BrepGovde g = kure(1.0); const MeshVeri ince = g.ucgenle({1, 1, 1}); // merkezi (ince) kalite const MeshVeri kaba = g.ucgenle({1, 1, 1}, 0.05); // açık ÇOK kaba sapma FIKO_KONTROL(!ince.indeksler.empty() && !kaba.indeksler.empty()); // Gerçek kaba: en az yarı yarıya az üçgen (küre pratikte ~10× az olur). FIKO_KONTROL(kaba.indeksler.size() * 2 < ince.indeksler.size()); // Kaba istek, orijinalin İNCE üçgenlemesini BOZMAMALI (tekrar ince istek ince kalmalı). const MeshVeri ince2 = g.ucgenle({1, 1, 1}); FIKO_KONTROL(ince2.indeksler.size() >= ince.indeksler.size()); } FIKO_TEST(brep_3d_local_op_compound_tabanda) { // PartDesign feature-gövdesi regresyonu: boolean (Fuse) sonucu TopoDS_Compound // sarılı gelir; local-op'lar (fillet/pah/push-pull) compound tabanda BAŞARISIZDI → // tekSolidCoz unwrap ile artık çalışmalı. İki üstüste kutu fuse → tek-solid compound. const BrepGovde a = kutu(2, 2, 2); const BrepGovde b = kutu(1, 1, 4); // aynı köşeden yükselen ince kolon (kesişir) const BrepGovde f = birlesim(a, b); FIKO_KONTROL(f.gecerliMi()); // Fillet: herhangi bir kenara r=0.3 → geçerli sonuç + hacim azalır (eskiden boş dönerdi). const BrepGovde y = yuvarlat(f, {1}, 0.3); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(y.hacim() > 0.0 && y.hacim() < f.hacim()); // Pah: aynı kenara 0.3 → geçerli. const BrepGovde p = pahla(f, {1}, 0.3); FIKO_KONTROL(p.gecerliMi()); // Push/pull: bir DÜZ yüzü 1.0 dışarı uzat → hacim artar (eskiden BRepFeat başarısızdı). bool ittiCekti = false; for (u32 yo = 1; yo <= 40 && !ittiCekti; ++yo) { geometri::YuzBilgi yb; if (!f.yuzBilgi(yo, yb) || !yb.duzlemMi) continue; const BrepGovde u = yuzItCek(f, yo, 1.0, nullptr); if (u.gecerliMi() && u.hacim() > f.hacim() + 1e-6) ittiCekti = true; } FIKO_KONTROL(ittiCekti); } FIKO_TEST(brep_3d_yuvarlat_degisken) { // Variable Radius Fillet: tek kenara başı r1=0.2 / sonu r2=0.5 → geçerli + hacim azalır. const BrepGovde g = kutu(2, 2, 2); const BrepGovde y = yuvarlatDegisken(g, /*kenar*/ 1, /*r1*/ 0.2, /*r2*/ 0.5); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(y.hacim() > 0.0 && y.hacim() < 8.0); // Değişken (r1≠r2) yay, sabit r=0.2'den fazla ama r=0.5'ten az malzeme kaldırır. const BrepGovde sabitDus = yuvarlat(g, {1}, 0.2); const BrepGovde sabitYuk = yuvarlat(g, {1}, 0.5); FIKO_KONTROL(sabitDus.gecerliMi() && sabitYuk.gecerliMi()); FIKO_KONTROL(y.hacim() < sabitDus.hacim() && y.hacim() > sabitYuk.hacim()); // Geçersiz girdi: sıfır ordinal / negatif yarıçap / geçersiz gövde → geçersiz gövde. FIKO_KONTROL(!yuvarlatDegisken(g, 0, 0.2, 0.5).gecerliMi()); FIKO_KONTROL(!yuvarlatDegisken(g, 1, 0.0, 0.5).gecerliMi()); FIKO_KONTROL(!yuvarlatDegisken(BrepGovde{}, 1, 0.2, 0.5).gecerliMi()); } FIKO_TEST(brep_3d_pah_gecersiz_girdi) { const BrepGovde g = kutu(2, 2, 2); FIKO_KONTROL(!pahla(g, {}, 0.5).gecerliMi()); // boş kenar listesi FIKO_KONTROL(!pahla(g, {1}, 0.0).gecerliMi()); // sıfır mesafe FIKO_KONTROL(!yuvarlat(BrepGovde{}, {1}, 0.5).gecerliMi()); // geçersiz gövde } FIKO_TEST(brep_kalinlastir_hacim) { // 2x2x2 kutu (hacim 8). Pozitif kalınlık → dışa büyür (hacim artar); negatif → küçülür. const BrepGovde g = kutu(2, 2, 2); const BrepGovde buyuk = kalinlastir(g, 0.5); FIKO_KONTROL(buyuk.gecerliMi() && buyuk.hacim() > 8.0); // dışa offset → hacim arttı const BrepGovde kucuk = kalinlastir(g, -0.5); FIKO_KONTROL(kucuk.gecerliMi() && kucuk.hacim() < 8.0 && kucuk.hacim() > 0.0); FIKO_KONTROL(!kalinlastir(BrepGovde{}, 0.5).gecerliMi()); // geçersiz gövde FIKO_KONTROL(!kalinlastir(g, 0.0).gecerliMi()); // sıfır mesafe } FIKO_TEST(brep_kabuk_ic_bosalt) { // Kabuk (MakeThickSolid): 10³ kutu, üst yüz açık, 1mm cidar → geçerli katı, içi boşaldığı // için hacim dolu kutudan (1000) BELİRGİN az. kalinlastir'in aksine yüz KALDIRIR. const BrepGovde g = kutu(10, 10, 10); const f64 v0 = g.hacim(); u32 ust = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (g.yuzBilgi(o, yb) && yb.duzlemMi && yb.normal.z > 0.99) { ust = o; break; } } FIKO_KONTROL(ust != 0); const BrepGovde k = kabuk(g, {ust}, 1.0); FIKO_KONTROL(k.gecerliMi()); FIKO_KONTROL(k.hacim() > 1e-3); // katı (boş değil) FIKO_KONTROL(k.hacim() < v0 - 1.0); // içi boşaldı → dolu kutudan belirgin az FIKO_KONTROL(!kabuk(BrepGovde{}, {ust}, 1.0).gecerliMi()); // geçersiz gövde FIKO_KONTROL(!kabuk(g, {}, 1.0).gecerliMi()); // yüz seçilmedi FIKO_KONTROL(!kabuk(g, {ust}, 0.0).gecerliMi()); // sıfır kalınlık } FIKO_TEST(brep_yuz_sil_acik_shell) { // Yüz Sil (BRepTools_ReShape): 10³ kutu üst yüzünü sil → onarma YOK → 5 yüzlü açık shell. // Yüz Kaldır'ın (Defeaturing, komşu uzatıp katıyı korur) aksine solid DEĞİL → doluMu()==false, // gecerliMi()==true. Kalan yüz sayısı 6→5. Kaynak renk kalan yüzlere sıralı korunur. const BrepGovde g = kutu(10, 10, 10); FIKO_KONTROL(topolojiOzeti(g).yuzSayi == 6); u32 ust = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (g.yuzBilgi(o, yb) && yb.duzlemMi && yb.normal.z > 0.99) { ust = o; break; } } FIKO_KONTROL(ust != 0); const BrepGovde s = yuzuSil(g, {ust}); FIKO_KONTROL(s.gecerliMi()); // geçerli (açık) gövde FIKO_KONTROL(!s.doluMu()); // solid değil → açık shell FIKO_KONTROL(topolojiOzeti(s).yuzSayi == 5); // bir yüz silindi FIKO_KONTROL(!yuzuSil(BrepGovde{}, {ust}).gecerliMi()); // geçersiz gövde FIKO_KONTROL(!yuzuSil(g, {}).gecerliMi()); // yüz seçilmedi } FIKO_TEST(brep_draft_yuz_egim) { // Draft (BRepOffsetAPI_DraftAngle): 10³ kutu +x yüzü, 8° eğim, çekme +z, nötr=alt düzlem. // Yüz eğimlenip taper olunca hacim BELİRGİN değişir; geçerli katı kalır. const BrepGovde g = kutu(10, 10, 10); const f64 v0 = g.hacim(); u32 yanX = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (g.yuzBilgi(o, yb) && yb.duzlemMi && yb.normal.x > 0.99) { yanX = o; break; } } FIKO_KONTROL(yanX != 0); const BrepGovde d = yuzDraft(g, {yanX}, 8.0, {0, 0, 1}, {0, 0, -5}, {0, 0, 1}, false); FIKO_KONTROL(d.gecerliMi()); FIKO_KONTROL(d.hacim() > 1e-3); FIKO_KONTROL(std::abs(d.hacim() - v0) > 0.5); // yüz eğimlendi → hacim belirgin değişti FIKO_KONTROL(!yuzDraft(BrepGovde{}, {yanX}, 8.0, {0, 0, 1}, {0, 0, -5}, {0, 0, 1}, false).gecerliMi()); FIKO_KONTROL(!yuzDraft(g, {}, 8.0, {0, 0, 1}, {0, 0, -5}, {0, 0, 1}, false).gecerliMi()); // yüz yok FIKO_KONTROL(!yuzDraft(g, {yanX}, 0.0, {0, 0, 1}, {0, 0, -5}, {0, 0, 1}, false).gecerliMi()); // sıfır açı } FIKO_TEST(brep_fillet_yuz_yuz) { // Yüz-Yüz fillet: iki KOMŞU yüzün ortak kenarına R (konveks kenar yuvarlanır → hacim azalır). // Karşılıklı yüzler ortak kenar paylaşmaz → geçersiz (ayrık-yüz dalı). const BrepGovde g = kutu(10, 10, 10); const f64 v0 = g.hacim(); u32 ustZ = 0, yanX = 0, yanXneg = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.duzlemMi) continue; if (yb.normal.z > 0.99) ustZ = o; else if (yb.normal.x > 0.99) yanX = o; else if (yb.normal.x < -0.99) yanXneg = o; } FIKO_KONTROL(ustZ && yanX && yanXneg); const BrepGovde f = yuvarlatYuzYuz(g, ustZ, yanX, 1.5); // komşu → ortak kenar filleti FIKO_KONTROL(f.gecerliMi()); FIKO_KONTROL(f.hacim() > 1e-3 && f.hacim() < v0 - 1e-3); // konveks kenar yuvarlandı FIKO_KONTROL(!yuvarlatYuzYuz(g, yanX, yanXneg, 1.5).gecerliMi()); // karşılıklı → ortak kenar yok FIKO_KONTROL(!yuvarlatYuzYuz(g, ustZ, ustZ, 1.5).gecerliMi()); // aynı yüz FIKO_KONTROL(!yuvarlatYuzYuz(g, ustZ, yanX, 0.0).gecerliMi()); // sıfır R FIKO_KONTROL(!yuvarlatYuzYuz(BrepGovde{}, ustZ, yanX, 1.5).gecerliMi()); // geçersiz gövde } FIKO_TEST(brep_fillet_tritangent_guard) { // Tritangent guard'ları: OCCT MakeFillet'e ULAŞMADAN kötü girdiyi reddeder (çökme koruması). // Pozitif hâli kutuda üretilemez: oto-R = ortak kenar↔kaldır-yüz mesafesi; kutuda bu ya 0 // (uç nokta komşu yüze değer) ya tam-genişlik (karşı yüz) → geçerli fillet imkânsız → zengin // geometri gerektirir. Bu yüzden yalnız deterministik guard dalları kilitlenir. const BrepGovde g = kutu(10, 10, 10); u32 yanX = 0, yanY = 0, yanXneg = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.duzlemMi) continue; if (yb.normal.x > 0.99) yanX = o; else if (yb.normal.y > 0.99) yanY = o; else if (yb.normal.x < -0.99) yanXneg = o; } FIKO_KONTROL(yanX && yanY && yanXneg); FIKO_KONTROL(!yuvarlatTritangent(BrepGovde{}, yanX, yanY, yanXneg).gecerliMi()); // geçersiz gövde FIKO_KONTROL(!yuvarlatTritangent(g, yanX, yanX, yanXneg).gecerliMi()); // tut1==tut2 FIKO_KONTROL(!yuvarlatTritangent(g, yanX, yanY, yanX).gecerliMi()); // tut==kaldır FIKO_KONTROL(!yuvarlatTritangent(g, 0, yanY, yanXneg).gecerliMi()); // sıfır ordinal FIKO_KONTROL(!yuvarlatTritangent(g, yanX, yanXneg, yanY).gecerliMi()); // karşılıklı tut → ortak kenar yok } FIKO_TEST(brep_prizma_pad_hacim) { // XY duzleminde 4x6 dikdortgen kontur, +Z yonunde 5 mm cikinti → 120 mm³. std::vector> konturlar = { {{-2, -3, 0}, {2, -3, 0}, {2, 3, 0}, {-2, 3, 0}}}; const BrepGovde g = prizma(konturlar, {0, 0, 1}, 5.0); FIKO_KONTROL(g.gecerliMi()); FIKO_YAKIN(g.hacim(), 4.0 * 6.0 * 5.0, 1e-4); } FIKO_TEST(brep_prizma_delik_ve_simetrik) { // Dis 10x10 kare + ic 2x2 delik → alan 96; 3 mm cikinti → 288 mm³. std::vector> konturlar = { {{-5, -5, 0}, {5, -5, 0}, {5, 5, 0}, {-5, 5, 0}}, {{-1, -1, 0}, {-1, 1, 0}, {1, 1, 0}, {1, -1, 0}}}; const BrepGovde g = prizma(konturlar, {0, 0, 1}, 3.0); FIKO_KONTROL(g.gecerliMi()); FIKO_YAKIN(g.hacim(), 96.0 * 3.0, 1e-3); // Simetrik: hacim ayni, ama profil merkezlenir (z=-2..+2, toplam 4x2x2=16). std::vector> kare = {{{-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}}}; const BrepGovde s = prizma(kare, {0, 0, 1}, 4.0, /*simetrik*/ true); FIKO_KONTROL(s.gecerliMi()); FIKO_YAKIN(s.hacim(), 2.0 * 2.0 * 4.0, 1e-4); } FIKO_TEST(brep_prizma_pocket_boolean) { // 10x10x10 kutu (dunyada z 0..10) − ust yuzden 4x4 prizma 3 mm cep. Donusumd kaydir; kaydir.konum = {0, 0, 5}; // kutu merkezi z=5 → z 0..10 const BrepGovde blok = donusumUygula(kutu(10, 10, 10), kaydir); FIKO_YAKIN(blok.hacim(), 1000.0, 1e-3); // Ust yuzeyden (z=10) asagi 3 mm cep araci: profil z=10, yon -Z. std::vector> profil = { {{-2, -2, 10}, {2, -2, 10}, {2, 2, 10}, {-2, 2, 10}}}; const BrepGovde araci = prizma(profil, {0, 0, -1}, 3.0); FIKO_KONTROL(araci.gecerliMi()); const BrepGovde cep = cikarma(blok, araci); FIKO_KONTROL(cep.gecerliMi()); FIKO_YAKIN(cep.hacim(), 1000.0 - 4.0 * 4.0 * 3.0, 1e-3); } FIKO_TEST(brep_prizma_gecersiz_girdi) { FIKO_KONTROL(!prizma({}, {0, 0, 1}, 5.0).gecerliMi()); // kontur yok FIKO_KONTROL(!prizma({{{0, 0, 0}, {1, 0, 0}}}, {0, 0, 1}, 5.0).gecerliMi()); // <3 nokta std::vector> kare = {{{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}}}; FIKO_KONTROL(!prizma(kare, {0, 0, 1}, 0.0).gecerliMi()); // sifir derinlik FIKO_KONTROL(!prizma(kare, {0, 0, 0}, 5.0).gecerliMi()); // sifir yon } FIKO_TEST(brep_loft_iki_kare_kesit) { // İki kare kesit (z=0 → 4x4, z=10 → 6x6) arası çok-kesitli katı → dolu hacim. // Her kesit çizgi (Cizgi) edge'li ProfilKontur; loftKati ThruSections ile solid üretir. auto kareKesit = [](f64 h, f64 z) { const Vec3d p[4] = {{-h, -h, z}, {h, -h, z}, {h, h, z}, {-h, h, z}}; ProfilKontur k; for (int i = 0; i < 4; ++i) { ProfilEgri e; e.tip = ProfilEgri::Tip::Cizgi; e.p0 = p[i]; e.p1 = p[(i + 1) % 4]; k.push_back(e); } return k; }; const std::vector kesitler = {kareKesit(2.0, 0.0), kareKesit(3.0, 10.0)}; const BrepGovde g = loftKati(kesitler, /*kapali*/ true); FIKO_KONTROL(g.gecerliMi()); // Prizmatoid hacmi: h/6·(A_alt + 4·A_orta + A_ust) = 10/6·(16 + 4·25 + 36) ≈ 253.3. // Smooth interpolasyon küçük sapabilir → geniş bant + kesin pozitiflik. FIKO_KONTROL(g.hacim() > 150.0 && g.hacim() < 400.0); // Geçersiz: tek kesit → loft üretilemez. FIKO_KONTROL(!loftKati({kareKesit(2.0, 0.0)}, true).gecerliMi()); } FIKO_TEST(brep_step_yaz_oku) { const BrepGovde g = kutu(5, 6, 7); const std::string yol = "test_gecici.step"; const std::vector liste = {&g}; FIKO_KONTROL(stepKaydet(liste, yol)); const auto yuklenen = stepYukle(yol); FIKO_KONTROL(yuklenen.size() == 1); FIKO_YAKIN(yuklenen[0].govde.hacim(), 210.0, 1e-3); std::remove(yol.c_str()); } namespace { // Hiyerarsi agacindaki tum yaprak govdelerin hacim toplami f64 hiyerarsiHacim(const std::vector& dugumler) { f64 t = 0; for (const auto& d : dugumler) { if (d.govdeVar) t += d.govde.hacim(); t += hiyerarsiHacim(d.altlar); } return t; } } FIKO_TEST(brep_step_hiyerarsi_oku) { // Yazma tarafi hiyerarsi uretmez; en azindan yaprak govde + hacim korunmali. const BrepGovde g = kutu(5, 6, 7); const std::string yol = "test_gecici_hiy.step"; const std::vector liste = {&g}; FIKO_KONTROL(stepKaydet(liste, yol)); const auto agac = stepYukleHiyerarsi(yol); FIKO_KONTROL(!agac.empty()); FIKO_YAKIN(hiyerarsiHacim(agac), 210.0, 1e-3); std::remove(yol.c_str()); } // ---- GSD Dalga 1: Wireframe (gercek OCCT B-Rep) + temel yuzey ---- FIKO_TEST(gsd_cizgi_uzunluk) { const BrepGovde e = cizgiIkiNokta({0, 0, 0}, {3, 4, 0}); FIKO_KONTROL(e.gecerliMi()); KenarBilgi b; FIKO_KONTROL(e.kenarBilgi(1, b)); // 1-tabanli tek kenar FIKO_KONTROL(b.dogruMu); FIKO_YAKIN(b.uzunluk, 5.0, 1e-9); } FIKO_TEST(gsd_cizgi_yon_uzunluk) { const BrepGovde e = cizgiYonUzunluk({1, 0, 0}, {0, 0, 2}, 7.0); // +Z yon, uzunluk 7 FIKO_KONTROL(e.gecerliMi()); KenarBilgi b; FIKO_KONTROL(e.kenarBilgi(1, b)); FIKO_YAKIN(b.uzunluk, 7.0, 1e-9); } FIKO_TEST(gsd_cember_merkez_yaricap) { const BrepGovde c = cemberMerkezR({0, 0, 0}, {0, 0, 1}, 2.5); FIKO_KONTROL(c.gecerliMi()); KenarBilgi b; FIKO_KONTROL(c.kenarBilgi(1, b)); FIKO_KONTROL(b.cemberMi); FIKO_YAKIN(b.yaricap, 2.5, 1e-9); FIKO_YAKIN(b.merkez.x, 0.0, 1e-9); FIKO_YAKIN(b.merkez.y, 0.0, 1e-9); } FIKO_TEST(gsd_cember_uc_nokta) { // Birim cember uzerinde 3 nokta → merkez orijin, yaricap 1. const BrepGovde c = cemberUcNokta({1, 0, 0}, {0, 1, 0}, {-1, 0, 0}); FIKO_KONTROL(c.gecerliMi()); KenarBilgi b; FIKO_KONTROL(c.kenarBilgi(1, b)); FIKO_KONTROL(b.cemberMi); FIKO_YAKIN(b.yaricap, 1.0, 1e-9); } FIKO_TEST(gsd_cember_uc_nokta_dogrusal_gecersiz) { const BrepGovde c = cemberUcNokta({0, 0, 0}, {1, 0, 0}, {2, 0, 0}); // dogrusal FIKO_KONTROL(!c.gecerliMi()); // cokme yok, gecersiz govde } FIKO_TEST(gsd_spline_noktalardan_gecer) { const std::vector pts = {{0, 0, 0}, {1, 2, 0}, {3, 1, 0}, {5, 3, 0}}; const BrepGovde s = splineBSpline(pts); FIKO_KONTROL(s.gecerliMi()); KenarBilgi b; FIKO_KONTROL(s.kenarBilgi(1, b)); // Interpolasyon: uc noktalar giristeki ilk/son ile cakismali. FIKO_YAKIN(b.bas.x, 0.0, 1e-6); FIKO_YAKIN(b.bas.y, 0.0, 1e-6); FIKO_YAKIN(b.son.x, 5.0, 1e-6); FIKO_YAKIN(b.son.y, 3.0, 1e-6); } FIKO_TEST(gsd_yuzey_extrude_alan) { // 4 birim uzunlukta dogru profili +Z boyunca 3 birim uzat → 4x3=12 birimkare serit. const std::vector profil = {{0, 0, 0}, {4, 0, 0}}; const BrepGovde y = yuzeyPrizma(profil, /*kapali*/ false, {0, 0, 1}, 3.0); FIKO_KONTROL(y.gecerliMi()); FIKO_YAKIN(y.alan(), 12.0, 1e-6); } FIKO_TEST(gsd_yuzey_revolve_silindir_alan) { // Eksen +Z (orijin), profil eksene paralel dogru (x=2, z:0..5) → tam donel // silindir yan yuzeyi: 2*pi*r*h = 2*pi*2*5. const std::vector profil = {{2, 0, 0}, {2, 0, 5}}; const BrepGovde y = yuzeyDondur(profil, /*kapali*/ false, {0, 0, 0}, {0, 0, 1}, 360.0); FIKO_KONTROL(y.gecerliMi()); const f64 pi = std::numbers::pi; FIKO_YAKIN(y.alan(), 2 * pi * 2 * 5, 1e-3); } // ---- Part Design DALGA 2: dondurKati (Shaft/Groove) ---- FIKO_TEST(part_dondur_kati_disk_hacim) { // XZ düzleminde 2x2 dikdörtgen profil (x:1..3, z:0..2), +Z ekseni etrafında tam // döndür → içi boş halka (torus benzeri) katı. Pappus: hacim = 2*pi*R̄*A, // R̄=merkez yarıçapı=2, A=alan=4 → 2*pi*2*4 = 16*pi. const std::vector> kontur = { {{1, 0, 0}, {3, 0, 0}, {3, 0, 2}, {1, 0, 2}}}; const BrepGovde k = dondurKati(kontur, {0, 0, 0}, {0, 0, 1}, 360.0); FIKO_KONTROL(k.gecerliMi()); const f64 pi = std::numbers::pi; FIKO_YAKIN(k.hacim(), 16.0 * pi, 1e-2); } FIKO_TEST(part_dondur_kati_yari_aci) { // Aynı profil 180° döndür → yarım halka, hacim yarısı (8*pi). const std::vector> kontur = { {{1, 0, 0}, {3, 0, 0}, {3, 0, 2}, {1, 0, 2}}}; const BrepGovde k = dondurKati(kontur, {0, 0, 0}, {0, 0, 1}, 180.0); FIKO_KONTROL(k.gecerliMi()); const f64 pi = std::numbers::pi; FIKO_YAKIN(k.hacim(), 8.0 * pi, 1e-2); } FIKO_TEST(part_dondur_kati_gecersiz_aci) { const std::vector> kontur = { {{1, 0, 0}, {3, 0, 0}, {3, 0, 2}, {1, 0, 2}}}; const BrepGovde k = dondurKati(kontur, {0, 0, 0}, {0, 0, 1}, 0.0); // aci=0 FIKO_KONTROL(!k.gecerliMi()); // cokme yok, gecersiz govde } // ---- Part Design DALGA 2: delikAraci (Hole) ---- FIKO_TEST(part_delik_araci_basit_silindir_hacim) { // Basit delik: Ø6 (r=3) x derinlik 10 → silindir hacmi pi*r²*h = pi*9*10 = 90*pi. HoleParam hp; hp.tip = DelikTip::Basit; hp.cap = 6.0; hp.derinlik = 10.0; const BrepGovde d = delikAraci({0, 0, 0}, {0, 0, -1}, hp); FIKO_KONTROL(d.gecerliMi()); const f64 pi = std::numbers::pi; FIKO_YAKIN(d.hacim(), 90.0 * pi, 1e-2); } FIKO_TEST(part_delik_araci_counterbore_daha_buyuk) { // Counterbore araci basit silindirden hacimce buyuk olmali (ek genis silindir). HoleParam basit; basit.cap = 6.0; basit.derinlik = 10.0; const f64 vBasit = delikAraci({0, 0, 0}, {0, 0, -1}, basit).hacim(); HoleParam cb = basit; cb.tip = DelikTip::Counterbore; cb.cbCap = 12.0; cb.cbDerinlik = 4.0; const f64 vCb = delikAraci({0, 0, 0}, {0, 0, -1}, cb).hacim(); FIKO_KONTROL(vCb > vBasit + 1.0); } FIKO_TEST(part_delik_araci_tapered_daralan_hacim) { // Konik delik (agizda r, dipe dogru daralir) → basit silindirden hacimce KUCUK olmali. HoleParam basit; basit.cap = 8.0; basit.derinlik = 12.0; const f64 vBasit = delikAraci({0, 0, 0}, {0, 0, -1}, basit).hacim(); HoleParam tp = basit; tp.tip = DelikTip::Tapered; tp.taperAci = 10.0; // 10° eksenden → dipte yaricap kucuk const BrepGovde d = delikAraci({0, 0, 0}, {0, 0, -1}, tp); FIKO_KONTROL(d.gecerliMi()); FIKO_KONTROL(d.hacim() < vBasit - 1.0); // konik → daha az malzeme cikar } FIKO_TEST(part_delik_araci_counterdrill_kombinasyon) { // Counterdrill = counterbore + gecis konisi → basit silindirden hacimce buyuk. HoleParam basit; basit.cap = 6.0; basit.derinlik = 14.0; const f64 vBasit = delikAraci({0, 0, 0}, {0, 0, -1}, basit).hacim(); HoleParam cd = basit; cd.tip = DelikTip::Counterdrill; cd.cbCap = 12.0; cd.cbDerinlik = 4.0; cd.csCap = 12.0; cd.csAci = 90.0; const BrepGovde d = delikAraci({0, 0, 0}, {0, 0, -1}, cd); FIKO_KONTROL(d.gecerliMi()); FIKO_KONTROL(d.hacim() > vBasit + 1.0); // fatura + havsa gecis → daha fazla } FIKO_TEST(part_delik_araci_gecersiz_cap) { HoleParam hp; hp.cap = 0.0; // gecersiz hp.derinlik = 10.0; const BrepGovde d = delikAraci({0, 0, 0}, {0, 0, -1}, hp); FIKO_KONTROL(!d.gecerliMi()); // cokme yok } FIKO_TEST(kesit_kapak_kutu_alan) { // 20×20×20 kutuyu merkezden XY-normal duzlemle kes → kapak alani 400 mm². const BrepGovde g = kutu(20, 20, 20); const auto ucgen = brepKesitKapak(g, {0, 0, 0}, {0, 0, 1}); FIKO_KONTROL(ucgen.size() >= 6 && ucgen.size() % 3 == 0); f64 alan = 0; for (size_t i = 0; i + 2 < ucgen.size(); i += 3) { const Vec3d ab{ucgen[i + 1].x - ucgen[i].x, ucgen[i + 1].y - ucgen[i].y, ucgen[i + 1].z - ucgen[i].z}; const Vec3d ac{ucgen[i + 2].x - ucgen[i].x, ucgen[i + 2].y - ucgen[i].y, ucgen[i + 2].z - ucgen[i].z}; const Vec3d cp = ab.capraz(ac); alan += 0.5 * std::sqrt(cp.x * cp.x + cp.y * cp.y + cp.z * cp.z); FIKO_KONTROL(std::abs(ucgen[i].z) < 1e-6); // tum noktalar duzlem ustunde } FIKO_YAKIN(alan, 400.0, 1e-3); } FIKO_TEST(kesit_kapak_delikli_ve_kesmeyen) { // Delikli govde: kapak alani = dis - delik. Kesmeyen duzlem → bos. const BrepGovde dis = kutu(20, 20, 20); const BrepGovde delik = silindir(4, 30); const BrepGovde g = cikarma(dis, delik); FIKO_KONTROL(g.gecerliMi()); const auto ucgen = brepKesitKapak(g, {0, 0, 0}, {0, 0, 1}); FIKO_KONTROL(!ucgen.empty()); f64 alan = 0; for (size_t i = 0; i + 2 < ucgen.size(); i += 3) { const Vec3d ab{ucgen[i + 1].x - ucgen[i].x, ucgen[i + 1].y - ucgen[i].y, ucgen[i + 1].z - ucgen[i].z}; const Vec3d ac{ucgen[i + 2].x - ucgen[i].x, ucgen[i + 2].y - ucgen[i].y, ucgen[i + 2].z - ucgen[i].z}; const Vec3d cp = ab.capraz(ac); alan += 0.5 * std::sqrt(cp.x * cp.x + cp.y * cp.y + cp.z * cp.z); } FIKO_YAKIN(alan, 400.0 - std::numbers::pi * 16.0, 0.5); // mesh sapmasi payi const auto bos = brepKesitKapak(g, {0, 0, 100}, {0, 0, 1}); FIKO_KONTROL(bos.empty()); // duzlem parcayi kesmiyor → cokme yok, bos } // ---- Renk propagasyonu (pah/boolean per-yuz rengi korunur) ---------------- namespace { // Mesh vertexlerinde belirli bir renk (tolerans icinde) var mi? bool renkVarMi(const MeshVeri& m, Vec3f r) { for (const auto& v : m.vertexler) if (std::abs(v.renk[0] - r.x) < 0.1f && std::abs(v.renk[1] - r.y) < 0.1f && std::abs(v.renk[2] - r.z) < 0.1f) return true; return false; } } // namespace FIKO_TEST(brep_3d_pah_renk_korunur) { BrepGovde g = kutu(2, 2, 2); // 6 yuz // Her yuze ayri renk: 1=kirmizi ... 3=mavi. g.yuzRenkleriAta({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 1, 0}, {1, 0, 1}, {0, 1, 1}}); FIKO_KONTROL(g.yuzRenkliMi()); const BrepGovde p = pahla(g, {1}, 0.4); // tek kenara pah FIKO_KONTROL(p.gecerliMi()); FIKO_KONTROL(p.yuzRenkliMi()); // renk dustu DEGIL, tasindi const MeshVeri m = p.ucgenle({0.5f, 0.5f, 0.5f}); FIKO_KONTROL(renkVarMi(m, {1, 0, 0})); // kirmizi korundu FIKO_KONTROL(renkVarMi(m, {0, 0, 1})); // mavi korundu // Tum yuzler renklendi (pah yuzeyi komsudan) → tekduze taban (0.5) hic gorunmez. FIKO_KONTROL(!renkVarMi(m, {0.5f, 0.5f, 0.5f})); } FIKO_TEST(brep_boolean_renk_korunur) { BrepGovde a = kutu(2, 2, 2); a.yuzRenkleriAta(std::vector(6, Vec3f{1, 0, 0})); // tumu kirmizi Donusumd k; k.konum = {1.5, 0, 0}; BrepGovde b = donusumUygula(kutu(2, 2, 2), k); b.yuzRenkleriAta(std::vector(6, Vec3f{0, 0, 1})); // tumu mavi const BrepGovde u = birlesim(a, b); FIKO_KONTROL(u.gecerliMi() && u.yuzRenkliMi()); const MeshVeri m = u.ucgenle({0.5f, 0.5f, 0.5f}); FIKO_KONTROL(renkVarMi(m, {1, 0, 0})); // a'dan kirmizi FIKO_KONTROL(renkVarMi(m, {0, 0, 1})); // b'den mavi } FIKO_TEST(gosterim_kalite_ucgen_yogunlugu) { // Egri yuzey (silindir) acisal sapmaya duyarli → seviye ucgen sayisini degistirir. const BrepGovde g = silindir(1.0, 2.0); kaliteSeviyeAta(KaliteSeviye::Dusuk); const size_t dusuk = g.ucgenle({1, 1, 1}).indeksler.size(); kaliteSeviyeAta(KaliteSeviye::Ultra); const size_t ultra = g.ucgenle({1, 1, 1}).indeksler.size(); FIKO_KONTROL(ultra > dusuk); // Ultra daha yogun tessellation kaliteSeviyeAta(KaliteSeviye::Yuksek); // varsayilana geri don (diger testleri etkileme) } FIKO_TEST(brep_bayt_ucgensiz_round_trip) { BrepGovde g = kure(5.0); (void)g.ucgenle({1, 1, 1}, 0.001); // yogun mesh gomulmesin (BinTools triangles=false) const std::string bayt = govdeBaytYaz(g); FIKO_KONTROL(!bayt.empty()); const BrepGovde geri = govdeBaytOku(bayt); FIKO_KONTROL(geri.gecerliMi()); FIKO_YAKIN(geri.hacim(), g.hacim(), 1e-6); // geometri korunur, boyut kucuk } // ---- Sketch-on-Surface (WRAP) — sketchYuzeSar ---- namespace { // Govdedeki ilk silindirik yuzun 1-tabanli ordinali (yoksa 0). u32 silindirYuzOrd(const BrepGovde& g) { for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; // ordinal bitti → yuz yok if (yb.silindirMi) return o; } return 0; } // Mesh vertexlerinin tumu Z eksenine 'r' mesafede mi (silindir yuzeyi uzerinde)? bool hepsiSilindirdeMi(const MeshVeri& m, f64 r, f64 tol) { if (m.vertexler.empty()) return false; for (const auto& v : m.vertexler) if (std::abs(std::hypot((f64)v.konum[0], (f64)v.konum[1]) - r) > tol) return false; return true; } } // namespace FIKO_TEST(sketch_yuze_sar_silindir_kare) { const BrepGovde g = silindir(5.0, 10.0); FIKO_KONTROL(g.gecerliMi()); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); // Merkezli 4×4 kare (sketch mm) — 4 cizgi, uc-uca kapali. ProfilKontur2d k; const auto ciz = [&](f64 x0, f64 y0, f64 x1, f64 y1) { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cizgi; e.p0 = {x0, y0}; e.p1 = {x1, y1}; k.push_back(e); }; ciz(-2, -2, 2, -2); ciz(2, -2, 2, 2); ciz(2, 2, -2, 2); ciz(-2, 2, -2, -2); const BrepGovde s = sketchYuzeSar(g, ord, k); FIKO_KONTROL(s.gecerliMi()); // Silindir gelistirilebilir (developable) → alan IZOMETRIK korunur = 4×4 = 16. FIKO_YAKIN(s.alan(), 16.0, 0.5); // Sarili yuz TAM silindir uzerinde (r=5). FIKO_KONTROL(hepsiSilindirdeMi(s.ucgenle({1, 1, 1}), 5.0, 1e-3)); } FIKO_TEST(sketch_yuze_sar_silindir_cember) { const BrepGovde g = silindir(5.0, 10.0); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); ProfilKontur2d k; ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cember; e.merkez = {0, 0}; e.yaricap = 2.0; k.push_back(e); const BrepGovde s = sketchYuzeSar(g, ord, k); FIKO_KONTROL(s.gecerliMi()); FIKO_YAKIN(s.alan(), std::numbers::pi * 4.0, 0.6); // π·r² = 4π ≈ 12.566 FIKO_KONTROL(hepsiSilindirdeMi(s.ucgenle({1, 1, 1}), 5.0, 1e-3)); } namespace { // Merkezli 2·yariKenar kare kontur (sketch mm) — 4 çizgi, uç-uca kapalı. ProfilKontur2d kareKontur(f64 yariKenar) { ProfilKontur2d k; const f64 h = yariKenar; const auto ciz = [&](f64 x0, f64 y0, f64 x1, f64 y1) { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cizgi; e.p0 = {x0, y0}; e.p1 = {x1, y1}; k.push_back(e); }; ciz(-h, -h, h, -h); ciz(h, -h, h, h); ciz(h, h, -h, h); ciz(-h, h, -h, -h); return k; } } // namespace FIKO_TEST(yuze_kabart_silindir_fuse_hacim_artar) { const BrepGovde g = silindir(5.0, 10.0); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde s = yuzeKabart(g, ord, {kareKontur(1.0)}, 1.0, true); // dışa kabart (boss) FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(s.hacim() > v0 + 1e-3); // malzeme eklendi } FIKO_TEST(yuze_kabart_silindir_cut_hacim_azalir) { const BrepGovde g = silindir(5.0, 10.0); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde s = yuzeKabart(g, ord, {kareKontur(1.0)}, 1.0, false); // oy (pocket) FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(s.hacim() < v0 - 1e-3); // malzeme çıkarıldı } FIKO_TEST(yuze_kabart_silindir_delikli_boss) { const BrepGovde g = silindir(5.0, 10.0); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde dolu = yuzeKabart(g, ord, {kareKontur(2.0)}, 1.0, true); // dolu kare boss FIKO_KONTROL(dolu.gecerliMi()); ProfilKontur2d cemberDelik; // iç çember (r=1) = delik { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cember; e.merkez = {0, 0}; e.yaricap = 1.0; cemberDelik.push_back(e); } const BrepGovde delikli = yuzeKabart(g, ord, {kareKontur(2.0), cemberDelik}, 1.0, true); FIKO_KONTROL(delikli.gecerliMi()); FIKO_KONTROL(delikli.hacim() > v0 + 1e-3); // yine malzeme ekler (halka boss) FIKO_KONTROL(delikli.hacim() < dolu.hacim() - 1e-3); // delik → dolu boss'tan AZ malzeme } FIKO_TEST(yuze_kabart_duz_yuz) { // emboss DÜZ yüz (en yaygın: düz yüzeye yazı/logo) const BrepGovde g = kutu(6, 6, 6); u32 ord = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.duzlemMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde boss = yuzeKabart(g, ord, {kareKontur(1.0)}, 1.0, true); // düz yüze boss FIKO_KONTROL(boss.gecerliMi()); FIKO_KONTROL(boss.hacim() > v0 + 1e-3); const BrepGovde oyuk = yuzeKabart(g, ord, {kareKontur(1.0)}, 1.0, false); // düz yüze oyuk FIKO_KONTROL(oyuk.gecerliMi()); FIKO_KONTROL(oyuk.hacim() < v0 - 1e-3); } FIKO_TEST(yuze_kabart_kure_fuse) { // emboss silindir dışında: KÜRE yüzeyi (WRAP genellik) const BrepGovde g = kure(5.0); u32 ord = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.kureMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde s = yuzeKabart(g, ord, {kareKontur(0.8)}, 0.8, true); // dışa kabart FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(s.hacim() > v0 + 1e-3); } FIKO_TEST(yuze_kabart_koni_fuse) { // emboss KONİ yüzeyi (WRAP genellik) const BrepGovde g = koni(5.0, 10.0); u32 ord = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.koniMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde s = yuzeKabart(g, ord, {kareKontur(0.8)}, 0.8, true); FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(s.hacim() > v0 + 1e-3); } // ---- profil2dDunyaya + Sketch→Katı (düz yüz Pad/Cep) geometri pipeline'ı ---- FIKO_TEST(profil2d_dunyaya_kare_dogru) { // 2×2 kare (yariKenar=1), düzlem z=5, u=+x, v=+y → dünya köşeleri z=5, xy sketch ile aynı. const ProfilKontur k = profil2dDunyaya(kareKontur(1.0), {0, 0, 5}, {1, 0, 0}, {0, 1, 0}); FIKO_KONTROL(k.size() == 4); FIKO_KONTROL(k[0].tip == ProfilEgri::Tip::Cizgi); FIKO_YAKIN(k[0].p0.z, 5.0, 1e-9); FIKO_YAKIN(k[0].p0.x, -1.0, 1e-9); FIKO_YAKIN(k[0].p0.y, -1.0, 1e-9); } FIKO_TEST(profil2d_dunyaya_cember_eksen_normal) { ProfilKontur2d c2; // r=2 çember, merkez (0,0) { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cember; e.merkez = {0, 0}; e.yaricap = 2.0; c2.push_back(e); } const ProfilKontur k = profil2dDunyaya(c2, {0, 0, 3}, {1, 0, 0}, {0, 1, 0}); FIKO_KONTROL(k.size() == 1 && k[0].tip == ProfilEgri::Tip::Cember); FIKO_YAKIN(k[0].merkez.z, 3.0, 1e-9); FIKO_YAKIN(k[0].eksen.z, 1.0, 1e-9); // düzlem normali = +z FIKO_YAKIN(k[0].yaricap, 2.0, 1e-9); } FIKO_TEST(sketch_kati_pad_hacim_artar) { // düz üst yüze (z=+3) kare profil → dışa Pad (fuse) const BrepGovde g = kutu(6, 6, 6); // orijinde ortalı → üst yüz z=+3 const f64 v0 = g.hacim(); // 216 const ProfilKontur kare = profil2dDunyaya(kareKontur(1.0), {0, 0, 3}, {1, 0, 0}, {0, 1, 0}); const BrepGovde prizma = prizmaMultiEgri({kare}, {0, 0, 1}, 2.0, 0.0); // +z boyunca 2 mm boss FIKO_KONTROL(prizma.gecerliMi()); const BrepGovde pad = birlesim(g, prizma); FIKO_KONTROL(pad.gecerliMi()); FIKO_YAKIN(pad.hacim(), v0 + 8.0, 1e-3); // 2×2 kare × 2 yükseklik = 8 mm³ eklenir } FIKO_TEST(sketch_kati_cep_hacim_azalir) { // düz üst yüzden içe Cep (cut) const BrepGovde g = kutu(6, 6, 6); const f64 v0 = g.hacim(); const ProfilKontur kare = profil2dDunyaya(kareKontur(1.0), {0, 0, 3}, {1, 0, 0}, {0, 1, 0}); const BrepGovde prizma = prizmaMultiEgri({kare}, {0, 0, 1}, 0.05, 2.0); // yüzü aşıp içe 2 mm FIKO_KONTROL(prizma.gecerliMi()); const BrepGovde cep = cikarma(g, prizma); FIKO_KONTROL(cep.gecerliMi()); FIKO_KONTROL(cep.hacim() < v0 - 7.0); // ~2×2×2 = 8 mm³ oyulur (koplanar pay hariç) } FIKO_TEST(kure_push_pull_yaricap) { const BrepGovde g = kure(5.0); FIKO_KONTROL(g.gecerliMi()); u32 ord = 0; // küresel yüz ordinali (yuzBilgi.kureMi) for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.kureMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const BrepGovde buyuk = yuzItCek(g, ord, 1.0, nullptr); // R5 → R6 (dışa) FIKO_KONTROL(buyuk.gecerliMi()); FIKO_YAKIN(buyuk.hacim(), 4.0 / 3.0 * std::numbers::pi * 216.0, 3.0); // (4/3)π·6³ const BrepGovde kucuk = yuzItCek(g, ord, -1.0, nullptr); // R5 → R4 (içe) FIKO_KONTROL(kucuk.gecerliMi()); FIKO_YAKIN(kucuk.hacim(), 4.0 / 3.0 * std::numbers::pi * 64.0, 3.0); // (4/3)π·4³ } FIKO_TEST(silindir_push_pull_yaricap) { // silindir dış yüz radyal it/çek → R büyür/küçülür const BrepGovde g = silindir(5.0, 10.0); // R5·h10 → hacim π·25·10 FIKO_KONTROL(g.gecerliMi()); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); const BrepGovde buyuk = yuzItCek(g, ord, 2.0, nullptr); // R5 → R7 (dışa) FIKO_KONTROL(buyuk.gecerliMi()); FIKO_YAKIN(buyuk.hacim(), std::numbers::pi * 49.0 * 10.0, 5.0); // π·7²·10 const BrepGovde kucuk = yuzItCek(g, ord, -2.0, nullptr); // R5 → R3 (içe) FIKO_KONTROL(kucuk.gecerliMi()); FIKO_YAKIN(kucuk.hacim(), std::numbers::pi * 9.0 * 10.0, 5.0); // π·3²·10 } FIKO_TEST(sketch_extrude_cember_silindir_tespit) { // sketch daire→extrude → silindir yüz TESPİT + it/çek ProfilKontur2d c2; // daire r=3 (sketch profili) { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cember; e.merkez = {0, 0}; e.yaricap = 3.0; c2.push_back(e); } const ProfilKontur k = profil2dDunyaya(c2, {0, 0, 0}, {1, 0, 0}, {0, 1, 0}); // XY düzlem const BrepGovde sil = prizmaMultiEgri({k}, {0, 0, 1}, 10.0, 0.0); // Z boyunca 10 → silindir FIKO_KONTROL(sil.gecerliMi()); const u32 ord = silindirYuzOrd(sil); // yan yüz silindirMi olarak tespit ediliyor mu? FIKO_KONTROL(ord != 0); // 0 ise SurfaceOfExtrusion (kök neden) const BrepGovde buyuk = yuzItCek(sil, ord, 2.0, nullptr); // R3 → R5 FIKO_KONTROL(buyuk.gecerliMi()); FIKO_YAKIN(buyuk.hacim(), std::numbers::pi * 25.0 * 10.0, 5.0); } FIKO_TEST(yuvarlat_yuz_geri_harita) { // fillet KESİN provenance: bevel 0, kırpılan komşular eski ordinal const BrepGovde kutuG = kutu(10, 10, 10); std::vector remap; const BrepGovde sonuc = yuvarlat(kutuG, {1}, 2.0, &remap); FIKO_KONTROL(sonuc.gecerliMi()); u32 yuzSayi = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!sonuc.yuzBilgi(o, yb, false)) break; ++yuzSayi; } FIKO_KONTROL(remap.size() == yuzSayi); // her sonuç yüzüne bir kayıt int sifir = 0; std::vector gorulen(7, false); for (int v : remap) { if (v == 0) { ++sifir; continue; } FIKO_KONTROL(v >= 1 && v <= 6); // kutu 6 yüz — eski ordinal aralığında FIKO_KONTROL(!gorulen[(size_t)v]); // tekrarsız (her eski yüz en çok bir kez) gorulen[(size_t)v] = true; } FIKO_KONTROL(sifir == 1); // tek kenar fillet'i tek bevel yüzü üretir; kalan hepsi eşlenik } FIKO_TEST(yuz_itcek_silindir_geri_harita) { // radyal it/çek provenance: uzayan kapaklar ESKİ sahibinde const BrepGovde g = silindir(5.0, 10.0); const u32 ord = silindirYuzOrd(g); FIKO_KONTROL(ord != 0); std::vector remap; const BrepGovde buyuk = yuzItCek(g, ord, 2.0, &remap); FIKO_KONTROL(buyuk.gecerliMi()); int sifir = 0, eslenen = 0; for (int v : remap) (v == 0) ? ++sifir : ++eslenen; FIKO_KONTROL(sifir >= 1); // yeni silindir duvarı bu işlemin (sahiplenilir) FIKO_KONTROL(eslenen >= 2); // GENİŞLEYEN alt/üst kapaklar eski ordinaline eşlenik kalır } FIKO_TEST(yuz_itcek_coklu_iki_yuz) { // DM çok-seçim: iki KARŞIT yüz aynı mesafeyle dışa const BrepGovde g = kutu(2, 2, 2); u32 y1 = 0, y2 = 0; Vec3d n1{}; for (u32 yo = 1; yo <= 6; ++yo) { YuzBilgi yb; if (!g.yuzBilgi(yo, yb) || !yb.duzlemMi) continue; if (!y1) { y1 = yo; n1 = yb.normal; continue; } if (n1.nokta(yb.normal) < -0.9) { y2 = yo; break; } } FIKO_KONTROL(y1 != 0 && y2 != 0); std::vector remap; const BrepGovde s = yuzItCekCoklu(g, {y1, y2}, 1.0, &remap); FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(std::abs(s.hacim() - 16.0) < 1e-3); // 2×2×2 → 4×2×2 (her yüz +1) // Kompoze remap: itilen her yüzün İLK girdi ordinali sonuçta sahiplenilir (feature-düzenleme // ve renk mirası bu haritaya dayanır). bool s1 = false, s2 = false; for (int v : remap) { if ((u32)v == y1) s1 = true; if ((u32)v == y2) s2 = true; } FIKO_KONTROL(s1 && s2); // Tek elemanlı çağrı = yuzItCek (davranış birebir); boş liste → geçersiz. const BrepGovde tek = yuzItCekCoklu(g, {y1}, 1.0, nullptr); const BrepGovde ref = yuzItCek(g, y1, 1.0, nullptr); FIKO_KONTROL(tek.gecerliMi() && std::abs(tek.hacim() - ref.hacim()) < 1e-6); FIKO_KONTROL(!yuzItCekCoklu(g, {}, 1.0, nullptr).gecerliMi()); } FIKO_TEST(brep_duzlemle_bol_kesit) { // Kesit (Split): kutuyu z=0 düzlemiyle böl. Sözleşme: NORMAL yönündeki yarı ATILIR // (kesit düzlemi normali = bakış yönü), ters=true → o yarı kalır. Hacim tam yarıya iner, // CoG kalan tarafa kayar; iki yarının toplamı orijinali verir (kayıp/örtüşme yok). const BrepGovde g = kutu(10, 10, 10); // z ∈ [-5,5], hacim 1000 FIKO_YAKIN(g.hacim(), 1000.0, 1e-6); const BrepGovde alt = duzlemleBol(g, {0, 0, 0}, {0, 0, 1}, false); // +z atılır → alt yarı FIKO_KONTROL(alt.gecerliMi()); FIKO_YAKIN(alt.hacim(), 500.0, 1e-3); const KutleOzellik ka = kutleOzellikleri(alt); FIKO_KONTROL(ka.gecerli); FIKO_YAKIN(ka.agirlikMerkezi.z, -2.5, 1e-2); // alt yarının merkezi z=-2.5 const BrepGovde ust = duzlemleBol(g, {0, 0, 0}, {0, 0, 1}, true); // ters → üst yarı FIKO_KONTROL(ust.gecerliMi()); FIKO_YAKIN(ust.hacim(), 500.0, 1e-3); const KutleOzellik ku = kutleOzellikleri(ust); FIKO_KONTROL(ku.gecerli); FIKO_YAKIN(ku.agirlikMerkezi.z, 2.5, 1e-2); FIKO_YAKIN(alt.hacim() + ust.hacim(), 1000.0, 1e-3); // iki yarı = tam gövde // Merkezden kaçık düzlem + eğik normal de çalışır (yarı-yarıya olmak zorunda değil). const BrepGovde kacik = duzlemleBol(g, {0, 0, 2}, {0, 0, 1}, false); // z<2 kalır FIKO_KONTROL(kacik.gecerliMi()); FIKO_YAKIN(kacik.hacim(), 700.0, 1e-3); // 10×10×7 // Gövdeye DEĞMEYEN düzlem → kesmez: tüm gövde tutulur (normal tarafında parça yok). const BrepGovde uzak = duzlemleBol(g, {0, 0, 50}, {0, 0, 1}, false); FIKO_KONTROL(uzak.gecerliMi()); FIKO_YAKIN(uzak.hacim(), 1000.0, 1e-3); // Dejenere girdi → geçersiz (çökme yok). FIKO_KONTROL(!duzlemleBol(g, {0, 0, 0}, {0, 0, 0}, false).gecerliMi()); } FIKO_TEST(yuz_tasi_coklu_karsit_yuz) { // DM çok-seçim TAŞI (Plasticity multi-face move): tek vektör N yüze. KARŞIT iki yüze (+X/−X) // AYNI vektörü (1,0,0) uygulamak = kutuyu +X'e ötelemek: +X yüzü dışa (fuse, normalBileşen>0), // −X yüzü içe (cut, normalBileşen<0) → hacim KORUNUR, CoG +1 kayar. Tek çağrıda hem fuse hem // cut dalını ve ardışık adımların ordinal ileri-eşlemesini kapsar. const BrepGovde g = kutu(2, 2, 2); // x,y,z ∈ [-1,1], hacim 8 u32 artiX = 0, eksiX = 0; for (u32 yo = 1; yo <= 6; ++yo) { YuzBilgi yb; if (!g.yuzBilgi(yo, yb) || !yb.duzlemMi) continue; const Vec3d n = yb.normal.birim(); if (n.x > 0.9) artiX = yo; else if (n.x < -0.9) eksiX = yo; } FIKO_KONTROL(artiX != 0 && eksiX != 0); const BrepGovde s = yuzTasiCoklu(g, {artiX, eksiX}, {1.0, 0.0, 0.0}); FIKO_KONTROL(s.gecerliMi()); FIKO_YAKIN(s.hacim(), 8.0, 1e-3); // rijit öteleme → hacim değişmez const KutleOzellik ko = kutleOzellikleri(s); FIKO_KONTROL(ko.gecerli); FIKO_YAKIN(ko.agirlikMerkezi.x, 1.0, 1e-2); // x ∈ [0,2] → CoG x=1 FIKO_YAKIN(ko.agirlikMerkezi.y, 0.0, 1e-2); // öteki eksenler dokunulmadı // Tek elemanlı çağrı = yuzTasi BİREBİR (yuzItCekCoklu ile aynı sözleşme); boş liste → geçersiz. const BrepGovde tek = yuzTasiCoklu(g, {artiX}, {0.0, 0.0, 4.0}); const BrepGovde ref = yuzTasi(g, artiX, {0.0, 0.0, 4.0}); FIKO_KONTROL(tek.doluMu() == ref.doluMu()); if (tek.doluMu()) FIKO_YAKIN(tek.hacim(), ref.hacim(), 1e-6); FIKO_KONTROL(!yuzTasiCoklu(g, {}, {1.0, 0.0, 0.0}).gecerliMi()); // Yüze paralel yön (dejenere) → tüm adımlar başarısız → geçersiz (hata yağmuru değil). FIKO_KONTROL(!yuzTasiCoklu(g, {artiX}, {0.0, 1.0, 0.0}).gecerliMi()); } FIKO_TEST(yuz_itcek_coklu_dort_yan) { // DM çok-seçim SAĞLAMLIK: 4 YAN yüzü birlikte dışa çek // Kutunun 4 yan yüzü (±X, ±Y) aynı mesafeyle dışa → 4×4×2 blok. Ardışık it/çek'te her // adım kalan yüzleri IsSame/geometrik ile İLERİ taşır; hepsinin sahipliği kompoze remap'te. const BrepGovde g = kutu(2, 2, 2); std::vector yan; for (u32 yo = 1; yo <= 6; ++yo) { YuzBilgi yb; if (g.yuzBilgi(yo, yb) && yb.duzlemMi && std::abs(yb.normal.z) < 0.1) yan.push_back(yo); // ±X/±Y } FIKO_KONTROL(yan.size() == 4); std::vector remap; const BrepGovde s = yuzItCekCoklu(g, yan, 1.0, &remap); FIKO_KONTROL(s.gecerliMi()); FIKO_KONTROL(std::abs(s.hacim() - 32.0) < 1e-2); // 4×4×2 = 32 (her yan +1mm iki eksende) // 4 yan yüzün HEPSİ kompoze remap'te sahiplenilmeli (renk/feature mirası korunur). int sahip = 0; for (u32 y : yan) for (int v : remap) if ((u32)v == y) { ++sahip; break; } FIKO_KONTROL(sahip == 4); } FIKO_TEST(yuz_geometrik_esle_zincir) { // renk zinciri SAĞLAMLIK: ard arda 3 op sonrası eşleme tam // it/çek → fillet → pah zinciri: her adımda değişmeyen yüzler yüzey-kimliği ile eski // ordinaline bağlanmalı (yalnız yeni-üretilen yüzler 0). "Birkaç işlemde tek renk" kökünün // zincir-boyu regresyon koruması (tek-op yuz_geometrik_esle_ayni_yuzey'in ötesinde). BrepGovde a = kutu(10, 10, 10); u32 ust = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (a.yuzBilgi(o, yb) && yb.duzlemMi && yb.normal.z > 0.9) { ust = o; break; } } FIKO_KONTROL(ust != 0); const BrepGovde b = yuzItCek(a, ust, 2.0, nullptr); // üst yüzü çek FIKO_KONTROL(b.gecerliMi()); const BrepGovde c = yuvarlat(b, {1}, 1.0); // bir kenara fillet FIKO_KONTROL(c.gecerliMi()); // Her ardışık adımda: değişmeyen yüzlerin ÇOĞU eşlenmeli (0 sayısı düşük — yalnız yeni yüzler). const auto h1 = yuzGeometrikEsle(a, b); const auto h2 = yuzGeometrikEsle(b, c); const auto sifirSay = [](const std::vector& h) { int n = 0; for (int v : h) if (!v) ++n; return n; }; FIKO_KONTROL(sifirSay(h1) <= 1); // it/çek: yalnız ötelenen üst yüz "yeni" olabilir (yan duvarlar eşlenir) FIKO_KONTROL(sifirSay(h2) == 1); // fillet: yalnız bevel yüzü yeni } FIKO_TEST(yuz_geometrik_esle_ayni_yuzey) { // renk zinciri kökü: kırpılan komşu YÜZEY-KİMLİĞİ ile eşlenmeli // Fillet kenara komşu yüzleri KIRPAR (merkez kayar, alan değişir) — eski merkez+alan // eşlemesi onları 0'a düşürüp rengi kaybettiriyordu ("birkaç işlemde tek renk" kökü). // Yüzey kimliği (aynı düzlem) kademesi kırpılanları eski ordinaline bağlar; bevel 0 kalır. const BrepGovde g = kutu(2, 2, 2); const BrepGovde y = yuvarlat(g, {1}, 0.4); FIKO_KONTROL(y.gecerliMi()); const auto h = yuzGeometrikEsle(g, y); int sifir = 0; std::vector gorulen(7, false); for (int v : h) { if (v == 0) { ++sifir; continue; } FIKO_KONTROL(v >= 1 && v <= 6); gorulen[(size_t)v] = true; } FIKO_KONTROL(sifir == 1); // yalnız bevel yüzeyi yeni (hiçbir eski yüzeyle çakışmaz) int eskiKapsanan = 0; for (size_t i = 1; i <= 6; ++i) if (gorulen[i]) ++eskiKapsanan; FIKO_KONTROL(eskiKapsanan == 6); // kırpılanlar dahil TÜM eski yüzler eşlendi (renk korunur) } FIKO_TEST(yuz_bilgi_silindir_normal_isaret) { // yuzBilgi normal işareti: mil→radyal-DIŞ, delik→İÇE // Extrude-daire duvarı (SurfaceOfExtrusion, ham orientation REVERSED olabilir): işaret ham // orientation-flip'ten değil GERÇEK yüzey normalinden gelmeli — DM ok yönü/delik tespiti buna bağlı. ProfilKontur2d c2; { ProfilEgri2d e; e.tip = ProfilEgri2d::Tip::Cember; e.merkez = {0, 0}; e.yaricap = 3.0; c2.push_back(e); } const ProfilKontur k = profil2dDunyaya(c2, {0, 0, 0}, {1, 0, 0}, {0, 1, 0}); const BrepGovde sil = prizmaMultiEgri({k}, {0, 0, 1}, 10.0, 0.0); FIKO_KONTROL(sil.gecerliMi()); const u32 ord = silindirYuzOrd(sil); FIKO_KONTROL(ord != 0); YuzBilgi yb; FIKO_KONTROL(sil.yuzBilgi(ord, yb) && yb.silindirMi); { const Vec3d eks = yb.eksen.birim(); const Vec3d rel = yb.merkez - yb.eksenNokta; const Vec3d rad = rel - eks * rel.nokta(eks); FIKO_KONTROL(yb.normal.nokta(rad) > 0.0); // mil dış duvarı → dışa } const BrepGovde delikli = cikarma(kutu(10, 10, 10), silindir(2.0, 12.0)); FIKO_KONTROL(delikli.gecerliMi()); u32 delOrd = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi y; if (!delikli.yuzBilgi(o, y)) break; if (y.silindirMi) { delOrd = o; break; } } FIKO_KONTROL(delOrd != 0); YuzBilgi yd; FIKO_KONTROL(delikli.yuzBilgi(delOrd, yd)); const Vec3d eks2 = yd.eksen.birim(); const Vec3d rel2 = yd.merkez - yd.eksenNokta; const Vec3d rad2 = rel2 - eks2 * rel2.nokta(eks2); FIKO_KONTROL(yd.normal.nokta(rad2) < 0.0); // delik duvarı → içe } FIKO_TEST(yuz_kaldir_pah_geri_alir) { // CATIA Remove Face: pah yüzünü kaldır → köşe restore const BrepGovde kutuG = kutu(10, 10, 10); const f64 v0 = kutuG.hacim(); // 1000 const BrepGovde pahli = pahla(kutuG, {1}, 2.0); // bir kenara 2mm pah FIKO_KONTROL(pahli.gecerliMi()); const f64 v1 = pahli.hacim(); FIKO_KONTROL(v1 < v0 - 1e-3); // pah köşe malzemesi çıkardı u32 pahOrd = 0; // pah yüzü = eksen-hizasız düz yüz (normal ±X/±Y/±Z değil) for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!pahli.yuzBilgi(o, yb)) break; if (!yb.duzlemMi) continue; const Vec3d n = yb.normal; const bool eksenHizali = std::abs(std::abs(n.x) - 1) < 1e-3 || std::abs(std::abs(n.y) - 1) < 1e-3 || std::abs(std::abs(n.z) - 1) < 1e-3; if (!eksenHizali) { pahOrd = o; break; } } FIKO_KONTROL(pahOrd != 0); const BrepGovde geri = yuzKaldir(pahli, {pahOrd}); FIKO_KONTROL(geri.gecerliMi()); FIKO_KONTROL(geri.hacim() > v1 + 1e-3); // pah kaldırıldı → komşular uzadı → malzeme geri FIKO_YAKIN(geri.hacim(), v0, 1.0); // ~orijinal kutu (köşe restore) } FIKO_TEST(yuz_komsu_yuzler_kutu) { // topolojik komşuluk: üst yüz 4 yanla kenar paylaşır, altla PAYLAŞMAZ const BrepGovde g = kutu(4, 4, 4); u32 ust = 0, alt = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.duzlemMi) continue; if (yb.normal.z > 0.99) ust = o; else if (yb.normal.z < -0.99) alt = o; } FIKO_KONTROL(ust != 0 && alt != 0); const auto komsu = g.yuzKomsuYuzler(ust); FIKO_KONTROL(komsu.size() == 4); // 4 yan yüz (kutu üst yüzü 4 kenar paylaşır) bool altVar = false, ustVar = false; for (u32 o : komsu) { if (o == alt) altVar = true; if (o == ust) ustVar = true; } FIKO_KONTROL(!altVar); // KARŞIT (alt) yüz kenar paylaşmaz → komşu DEĞİL FIKO_KONTROL(!ustVar); // kendisi listede yok (tekrarsız, kendisi hariç) // Geçersiz ordinal / gövde → boş. FIKO_KONTROL(g.yuzKomsuYuzler(0).empty()); FIKO_KONTROL(BrepGovde{}.yuzKomsuYuzler(1).empty()); } FIKO_TEST(benzer_yuzler_delik_capi) { // pattern seçimi: "aynı çaptaki tüm delikler" tek jestle // İki R2 delik + bir R3 delik açılmış kutu. R2 deliğin silindirik yüzünden benzerYuzler // İKİ R2 duvarını bulmalı, R3'ü DIŞLAMALI (konum bağımsız — pattern-tabanlı toplu düzenleme). BrepGovde g = kutu(20, 20, 10); g = cikarma(g, diziKonum(silindir(2.0, 12.0), {{-5, 0, 0}, {5, 0, 0}})); // iki R2 delik g = cikarma(g, diziKonum(silindir(3.0, 12.0), {{0, 6, 0}})); // bir R3 delik FIKO_KONTROL(g.gecerliMi()); u32 r2Ord = 0; f64 r2 = 0; for (u32 o = 1; o <= 128; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.silindirMi && std::abs(yb.yaricap - 2.0) < 1e-3) { r2Ord = o; r2 = yb.yaricap; break; } } FIKO_KONTROL(r2Ord != 0); const auto benzer = g.benzerYuzler(r2Ord); int r2Sayi = 0, digerSilindir = 0; for (u32 o : benzer) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.silindirMi) continue; if (std::abs(yb.yaricap - r2) < 1e-3) ++r2Sayi; else ++digerSilindir; } FIKO_KONTROL(r2Sayi == 2); // her iki R2 delik duvarı seçilir FIKO_KONTROL(digerSilindir == 0); // R3 delik ASLA dahil değil (farklı çap) } FIKO_TEST(benzer_yuzler_duzlem_alan) { // benzerYuzler DÜZLEM (alan-oran) dalı — silindir testinin ikizi // 4×4×10 kutu: üst/alt = 16 alan (2 yüz), 4 yan = 40 alan. Üst yüzden benzerYuzler → yalnız // aynı-alan (16) yüzler (üst+alt), yanları (40) DIŞLAR. Yandan → 4 yan (40). const BrepGovde g = kutu(4, 4, 10); u32 ust = 0, yan = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.duzlemMi) continue; if (yb.normal.z > 0.99) ust = o; // üst (16 alan) else if (std::abs(yb.normal.z) < 0.1 && !yan) yan = o; // bir yan (40 alan) } FIKO_KONTROL(ust != 0 && yan != 0); const auto ustBenzer = g.benzerYuzler(ust); int a16 = 0, digerAlan = 0; for (u32 o : ustBenzer) { YuzBilgi yb; if (!g.yuzBilgi(o, yb) || !yb.duzlemMi) continue; if (std::abs(yb.alan - 16.0) < 0.5) ++a16; else ++digerAlan; } FIKO_KONTROL(a16 == 2); // üst + alt (aynı alan 16) FIKO_KONTROL(digerAlan == 0); // yan yüzler (40) ASLA dahil değil (farklı boyut) FIKO_KONTROL(g.benzerYuzler(yan).size() == 4); // 4 yan yüz (hepsi 40 alan) } FIKO_TEST(benzer_yuzler_kure_koni) { // benzerYuzler EĞRİ dalları (küre=tip2, koni=tip3) — silindir/düzlem testlerinin ikizi. // Küre: küresel yüzden benzerYuzler → sonuç YALNIZ küresel yüz(ler); tür-dışı (seam/düzlem) sızmaz. { const BrepGovde g = kure(5.0); u32 ord = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.kureMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const auto b = g.benzerYuzler(ord); FIKO_KONTROL(!b.empty()); bool kendisi = false; for (u32 o : b) { YuzBilgi yb; FIKO_KONTROL(g.yuzBilgi(o, yb)); FIKO_KONTROL(yb.kureMi); if (o == ord) kendisi = true; } FIKO_KONTROL(kendisi); // tip2 kendini içerir, çapraz-tür DIŞLANIR } // Koni: konik yüzden benzerYuzler → sonuç YALNIZ konik yüz(ler); taban düzlemi DIŞLANIR. { const BrepGovde g = koni(5.0, 10.0); u32 ord = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.koniMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const auto b = g.benzerYuzler(ord); FIKO_KONTROL(!b.empty()); bool kendisi = false; for (u32 o : b) { YuzBilgi yb; FIKO_KONTROL(g.yuzBilgi(o, yb)); FIKO_KONTROL(yb.koniMi); if (o == ord) kendisi = true; } FIKO_KONTROL(kendisi); // tip3 kendini içerir, taban düzlemi sızmaz } } FIKO_TEST(benzer_kenarlar_cember_yaricap) { // pattern: "aynı R'deki tüm çember kenarları" // İki R2 + bir R3 delikli kutu → R2 deliğin ağız çemberinden benzerKenarlar tüm R2 çember // kenarlarını (her deliğin iki ağzı) bulmalı, R3'ü DIŞLAMALI. BrepGovde g = kutu(20, 20, 10); g = cikarma(g, diziKonum(silindir(2.0, 12.0), {{-5, 0, 0}, {5, 0, 0}})); g = cikarma(g, diziKonum(silindir(3.0, 12.0), {{0, 6, 0}})); FIKO_KONTROL(g.gecerliMi()); u32 r2Ord = 0; for (u32 o = 1; o <= 256; ++o) { KenarBilgi kb; if (!g.kenarBilgi(o, kb)) break; if (kb.cemberMi && std::abs(kb.yaricap - 2.0) < 1e-3) { r2Ord = o; break; } } FIKO_KONTROL(r2Ord != 0); const auto benzer = g.benzerKenarlar(r2Ord); int r2 = 0, diger = 0; for (u32 o : benzer) { KenarBilgi kb; if (!g.kenarBilgi(o, kb) || !kb.cemberMi) continue; if (std::abs(kb.yaricap - 2.0) < 1e-3) ++r2; else ++diger; } FIKO_KONTROL(r2 >= 2); // en az iki R2 çember (iki delik ağzı; delik başına 2 → 4 olabilir) FIKO_KONTROL(diger == 0); // R3 çember ASLA dahil değil } FIKO_TEST(benzer_kenarlar_dogru_uzunluk) { // benzerKenarlar DOĞRU (uzunluk) dalı — çember testinin ikizi // 4×4×10 kutu: uzunluk-4 (üst+alt kare) ve uzunluk-10 (dikey) kenarlar. DOĞRULUK özelliği // (dup-bağımsız): benzerKenarlar SADECE aynı-uzunluk kenar döndürür, farklı uzunluğu DIŞLAR. // NOT: kenar ordinal uzayı ham TopExp (paylaşılan kenar 2 yüzden 2 kez) → sayı 2× ama filtre // doğruluğu bundan bağımsız; bu yüzden tam sayı yerine "çapraz-kontaminasyon yok"u kilitliyoruz. const BrepGovde g = kutu(4, 4, 10); u32 k4 = 0, k10 = 0; for (u32 o = 1; o <= 64; ++o) { KenarBilgi kb; if (!g.kenarBilgi(o, kb) || !kb.dogruMu) continue; if (std::abs(kb.uzunluk - 4.0) < 1e-3 && !k4) k4 = o; else if (std::abs(kb.uzunluk - 10.0) < 1e-3 && !k10) k10 = o; } FIKO_KONTROL(k4 != 0 && k10 != 0); const auto b4 = g.benzerKenarlar(k4); FIKO_KONTROL(!b4.empty()); int u4 = 0, uDiger = 0; for (u32 o : b4) { KenarBilgi kb; if (!g.kenarBilgi(o, kb)) continue; if (kb.dogruMu && std::abs(kb.uzunluk - 4.0) < 1e-3) ++u4; else ++uDiger; } FIKO_KONTROL(u4 == (int)b4.size()); // dönen HER kenar uzunluk-4 (filtre doğru) FIKO_KONTROL(uDiger == 0); // uzunluk-10 (veya başka) ASLA dahil değil // uzunluk-10 kenardan → yalnız uzunluk-10 (uzunluk-4'ü dışlar → iki küme AYRIK). const auto b10 = g.benzerKenarlar(k10); FIKO_KONTROL(!b10.empty()); for (u32 o : b10) { KenarBilgi kb; if (!g.kenarBilgi(o, kb) || !kb.dogruMu) continue; FIKO_KONTROL(std::abs(kb.uzunluk - 10.0) < 1e-3); // hepsi uzunluk-10 } } FIKO_TEST(kenar_zinciri_egri_teget) { // CATIA tangency propagation: fillet yayı zinciri koparmaz // Kutu kenarına fillet → bevel'in uç YAYLARI komşu düz kenarlara TEĞET bağlanır. // Eski MVP eğri başlangıçta {kendisi} dönerdi; yeni uç-teğet zinciri yay+2 doğruyu bağlar. const BrepGovde g = yuvarlat(kutu(10, 10, 10), {1}, 2.0); FIKO_KONTROL(g.gecerliMi()); bool zincirBuldu = false; for (u32 o = 1; o <= 64 && !zincirBuldu; ++o) { KenarBilgi kb; if (!g.kenarBilgi(o, kb)) break; if (kb.dogruMu) continue; // eğri (yay) kenardan başla const auto z = g.kenarZinciri(o); if (z.size() < 3) continue; int dogru = 0; for (u32 k : z) { KenarBilgi kz; if (g.kenarBilgi(k, kz) && kz.dogruMu) ++dogru; } if (dogru >= 2) zincirBuldu = true; // yay + iki teğet doğru kenar tek zincirde } FIKO_KONTROL(zincirBuldu); // Düz kenar davranışı korunur: 90° köşede zincir DURUR (küpte tek kenar döner). const BrepGovde k = kutu(4, 4, 4); FIKO_KONTROL(k.kenarZinciri(1).size() == 1); } FIKO_TEST(yuz_kaldir_renk_temeli) { // DM Delete=Yüz Kaldır (async) renk yolu temeli: // Defeaturing history taşımaz → renkler worker sigortasıyla yuzGeometrikEsle üzerinden // yeniden kurulur. Kaldırma komşuları UZATIR (restore) — yüzey-kimliği kademesi uzayan // yüzleri eski ordinaline bağlamalı ki renk/yuzOz kaybolmasın. const BrepGovde kutuG = kutu(10, 10, 10); const BrepGovde pahli = pahla(kutuG, {1}, 2.0); FIKO_KONTROL(pahli.gecerliMi()); u32 pahOrd = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!pahli.yuzBilgi(o, yb)) break; if (!yb.duzlemMi) continue; const Vec3d n = yb.normal; const bool eksenHizali = std::abs(std::abs(n.x) - 1) < 1e-3 || std::abs(std::abs(n.y) - 1) < 1e-3 || std::abs(std::abs(n.z) - 1) < 1e-3; if (!eksenHizali) { pahOrd = o; break; } } FIKO_KONTROL(pahOrd != 0); const BrepGovde geri = yuzKaldir(pahli, {pahOrd}); FIKO_KONTROL(geri.gecerliMi()); const auto h = yuzGeometrikEsle(pahli, geri); FIKO_KONTROL(!h.empty()); int sifir = 0; for (int v : h) if (!v) ++sifir; FIKO_KONTROL(sifir == 0); // restore edilen TÜM yüzler eşlenir (uzayanlar dahil) → renk tam korunur } FIKO_TEST(yuz_kaldir_delik_doldurur) { // Remove Face en yaygın: silindirik deliği kaldır → doldur const BrepGovde delikli = cikarma(kutu(10, 10, 10), silindir(2.0, 12.0)); // Z boyunca delik FIKO_KONTROL(delikli.gecerliMi()); const f64 vDelik = delikli.hacim(); // 1000 - π·4·10 ≈ 874.3 FIKO_KONTROL(vDelik < 1000.0 - 1e-3); u32 delOrd = 0; // silindirik delik yüzü for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!delikli.yuzBilgi(o, yb)) break; if (yb.silindirMi) { delOrd = o; break; } } FIKO_KONTROL(delOrd != 0); const BrepGovde dolu = yuzKaldir(delikli, {delOrd}); // deliği kaldır → komşular kapatır FIKO_KONTROL(dolu.gecerliMi()); FIKO_KONTROL(dolu.hacim() > vDelik + 1e-2); // delik dolduruldu → hacim arttı } FIKO_TEST(yuz_kopyala_yuzey_govde) { // Copy Face → açık yüzey gövdesi (GSD Yuzey), BREP-exact const BrepGovde k = kutu(2.0, 3.0, 4.0); // toplam yüzey alanı 2·(6+8+12)=52 FIKO_KONTROL(k.gecerliMi()); FIKO_YAKIN(k.alan(), 52.0, 1e-6); // Tek yüz kopyala → geçerli açık yüzey; alan kutu yüz alanlarından biri (6/8/12). const BrepGovde y1 = yuzKopyala(k, {1}); FIKO_KONTROL(y1.gecerliMi()); const f64 a1 = y1.alan(); FIKO_KONTROL(a1 > 5.9 && a1 < 12.1); // Tüm yüzler → toplam alan korunur (tessellation yok, gerçek yüzey alanı). const BrepGovde hepsi = yuzKopyala(k, {1, 2, 3, 4, 5, 6}); FIKO_KONTROL(hepsi.gecerliMi()); FIKO_YAKIN(hepsi.alan(), 52.0, 1e-6); // Kopya BAĞIMSIZ: kaynak katı hâlâ geçerli + hacimli (paylaşımsız). FIKO_KONTROL(k.gecerliMi() && k.hacim() > 23.9); // 2·3·4=24 // Geçersiz girdi → geçersiz gövde (çökme yok). FIKO_KONTROL(!yuzKopyala(k, {}).gecerliMi()); FIKO_KONTROL(!yuzKopyala(k, {999}).gecerliMi()); } FIKO_TEST(yuzey_katilastir_kati) { // Thicken Surface: yüz kopyala → yüzey → kalınlaştır → katı const BrepGovde k = kutu(2.0, 3.0, 4.0); const BrepGovde yuz = yuzKopyala(k, {1}); // tek yüz → açık yüzey (GSD Yuzey) FIKO_KONTROL(yuz.gecerliMi()); const f64 a = yuz.alan(); // düz yüz alanı ∈ {6,8,12} FIKO_KONTROL(a > 5.9 && a < 12.1); // Kalınlaştır → katı: düz yüzey → hacim = alan × kalınlık (BREP-exact). const BrepGovde kati = yuzeyKatilastir(yuz, 0.5); FIKO_KONTROL(kati.gecerliMi()); FIKO_YAKIN(kati.hacim(), a * 0.5, 1e-4); // Negatif kalınlık → diğer yöne, yine geçerli katı (aynı hacim). const BrepGovde kati2 = yuzeyKatilastir(yuz, -0.5); FIKO_KONTROL(kati2.gecerliMi()); FIKO_YAKIN(kati2.hacim(), a * 0.5, 1e-4); // Sıfır kalınlık → geçersiz (çökme yok). FIKO_KONTROL(!yuzeyKatilastir(yuz, 0.0).gecerliMi()); } FIKO_TEST(kabuktan_kati_govde) { // Make Solid from Closed Shell: kapalı yüzeyi katıya çevir const BrepGovde k = kutu(2.0, 3.0, 4.0); // hacim 24 const BrepGovde shell = yuzKopyala(k, {1, 2, 3, 4, 5, 6}); // tüm yüzler → KAPALI shell FIKO_KONTROL(shell.gecerliMi()); const BrepGovde kati = kabuktanKati(shell); FIKO_KONTROL(kati.gecerliMi()); FIKO_YAKIN(kati.hacim(), 24.0, 1e-4); // kapalı shell → hacmi doldur (kutu hacmi) // Açık shell (tek yüz) → katı olamaz (geçersiz, çökme yok). const BrepGovde acik = yuzKopyala(k, {1}); FIKO_KONTROL(acik.gecerliMi()); FIKO_KONTROL(!kabuktanKati(acik).gecerliMi()); FIKO_KONTROL(!kabuktanKati({}).gecerliMi()); // geçersiz girdi } FIKO_TEST(yuzey_ile_bol_kati) { // Split Solid by Surface: katıyı GSD yüzeyle böl // kutu MERKEZ-origin: kutu(10)=[-5,5]³. Bölme yüzeyi = kutu(12,12,5) üst yüzü (z=2.5, [-6,6]² // → katıyı tam keser). z=2.5'te böl → [-5,2.5] (750) + [2.5,5] (250). const BrepGovde k = kutu(10.0, 10.0, 10.0); // hacim 1000 const BrepGovde bolCubuk = kutu(12.0, 12.0, 5.0); // üst yüzü z=2.5 u32 topOrd = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!bolCubuk.yuzBilgi(o, yb)) break; if (yb.duzlemMi && yb.normal.z > 0.9f && yb.merkez.z > 2.4 && yb.merkez.z < 2.6) { topOrd = o; break; } } FIKO_KONTROL(topOrd != 0); const BrepGovde yuzey = yuzKopyala(bolCubuk, {topOrd}); // bölme yüzeyi (açık) FIKO_KONTROL(yuzey.gecerliMi()); const std::vector parcalar = yuzeyIleBol(k, yuzey); FIKO_KONTROL(parcalar.size() == 2); // z<2.5 ve z>2.5 → iki katı f64 toplam = 0; for (const auto& p : parcalar) { FIKO_KONTROL(p.gecerliMi()); toplam += p.hacim(); } FIKO_YAKIN(toplam, 1000.0, 1e-3); // hacim korunur (BREP-exact bölme) for (const auto& p : parcalar) FIKO_KONTROL(p.hacim() > 200.0 && p.hacim() < 800.0); // 750/250 FIKO_KONTROL(yuzeyIleBol(k, {}).empty()); // geçersiz girdi → boş } FIKO_TEST(tanjant_yuzler_fillet) { // Plasticity tangent-select: fillet komşularına G1-teğet yayılım const BrepGovde k = kutu(10.0, 10.0, 10.0); const BrepGovde f = yuvarlat(k, {1}, 2.0); // bir kenarı yuvarlat → silindirik fillet yüzü FIKO_KONTROL(f.gecerliMi()); u32 filletOrd = 0; // silindirik fillet yüzü for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!f.yuzBilgi(o, yb)) break; if (yb.silindirMi) { filletOrd = o; break; } } FIKO_KONTROL(filletOrd != 0); // Fillet'ten teğet yayılım → fillet + iki komşu düz yüz (fillet ikisine de teğet). const auto teget = f.tanjantYuzler(filletOrd, 1.0); FIKO_KONTROL(teget.size() >= 3); // fillet + ≥2 teğet komşu FIKO_KONTROL(std::find(teget.begin(), teget.end(), filletOrd) != teget.end()); // Karşı köşe düz yüz (fillet'e değmez, tüm kenarları keskin) → yalnız kendisi yayılmaz. // (En büyük ordinal düz bir yüz seç; teğet kümesi fillet'i İÇERMEMELI.) u32 duzUzak = 0; for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!f.yuzBilgi(o, yb)) break; if (yb.duzlemMi) duzUzak = o; } FIKO_KONTROL(duzUzak != 0); const auto tegetDuz = f.tanjantYuzler(duzUzak, 1.0); FIKO_KONTROL(std::find(tegetDuz.begin(), tegetDuz.end(), duzUzak) != tegetDuz.end()); // kendisi dahil } FIKO_TEST(yuzey_ofset_paralel) { // Offset Surface: açık yüzeyi normal boyunca paralel ötele const BrepGovde k = kutu(2.0, 3.0, 4.0); const BrepGovde yuz = yuzKopyala(k, {1}); // düz açık yüzey FIKO_KONTROL(yuz.gecerliMi()); const f64 a = yuz.alan(); const BrepGovde ofs = yuzeyOfset(yuz, 2.0); // 2mm paralel offset FIKO_KONTROL(ofs.gecerliMi()); FIKO_YAKIN(ofs.alan(), a, 1e-4); // düz yüzey offset → alan KORUNUR (izometrik ötelenme) const BrepGovde ofsN = yuzeyOfset(yuz, -1.5); // ters yön de geçerli FIKO_KONTROL(ofsN.gecerliMi()); FIKO_YAKIN(ofsN.alan(), a, 1e-4); FIKO_KONTROL(!yuzeyOfset(yuz, 0.0).gecerliMi()); // sıfır → geçersiz } FIKO_TEST(yuvarlat_kose_clamp) { // köşe/kesişim: sığmayan R → clamp retry (tamamen başarısız değil) const BrepGovde g = kutu(10, 10, 10); const BrepGovde s = yuvarlat(g, {1}, 20.0); // R=20 >> kutu → tek-deneme geçersiz olurdu FIKO_KONTROL(s.gecerliMi()); // clamp retry ile GEÇERLİ (fix'ten önce başarısızdı) FIKO_KONTROL(s.hacim() < g.hacim() - 1e-3); // fillet malzeme çıkardı const BrepGovde p = pahla(g, {1}, 20.0); // pah da clamp retry (chamfer) FIKO_KONTROL(p.gecerliMi()); FIKO_KONTROL(p.hacim() < g.hacim() - 1e-3); } FIKO_TEST(yuz_tasi_egik) { // Move Face: düz yüzü EĞİK yönde ötele (push/pull genellemesi) const BrepGovde g = kutu(10, 10, 10); u32 ustOrd = 0; // üst yüz (normal ≈ +Z) for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.duzlemMi && yb.normal.z > 0.99) { ustOrd = o; break; } } FIKO_KONTROL(ustOrd != 0); const BrepGovde s = yuzTasi(g, ustOrd, {2.0, 0.0, 3.0}); // eğik dışa taşı FIKO_KONTROL(s.gecerliMi()); FIKO_YAKIN(s.hacim(), 1300.0, 5.0); // +normal bileşen(3)×alan(100)=300 // Yüze PARALEL yön (normal bileşen ≈ 0) dejenere → geçersiz. "Yüz Taşı" komutu bu // durumda yüz normaline düşer (kenar-yön fallback ilkesi) — geometri sözleşmesi doğrulanır. const BrepGovde paralel = yuzTasi(g, ustOrd, {5.0, 0.0, 0.0}); // üst yüze paralel (X) FIKO_KONTROL(!paralel.gecerliMi()); // Saf normal yön (komutun fallback'i) her zaman geçerli olmalı. const BrepGovde normalTasi = yuzTasi(g, ustOrd, {0.0, 0.0, 4.0}); FIKO_KONTROL(normalTasi.gecerliMi()); FIKO_YAKIN(normalTasi.hacim(), 1400.0, 1.0); // 100×(10+4) } FIKO_TEST(koni_push_pull_hacim) { const BrepGovde g = koni(5.0, 10.0); FIKO_KONTROL(g.gecerliMi()); u32 ord = 0; // konik yüz ordinali (yuzBilgi.koniMi) for (u32 o = 1; o <= 64; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb)) break; if (yb.koniMi) { ord = o; break; } } FIKO_KONTROL(ord != 0); const f64 v0 = g.hacim(); const BrepGovde buyuk = yuzItCek(g, ord, 1.0, nullptr); // konik yüz dışa (radyal +1) FIKO_KONTROL(buyuk.gecerliMi()); FIKO_KONTROL(buyuk.hacim() > v0 + 1e-2); // malzeme eklendi const BrepGovde kucuk = yuzItCek(g, ord, -1.0, nullptr); // içe (radyal -1) FIKO_KONTROL(kucuk.gecerliMi()); FIKO_KONTROL(kucuk.hacim() < v0 - 1e-2); // malzeme çıkarıldı } FIKO_TEST(kalici_kimlik_dogum_ve_ters) { // KYA Faz 1: doğum-etiketleme + ters arama + idempotent BrepGovde g = kutu(10, 10, 10); FIKO_KONTROL(g.gecerliMi()); FIKO_KONTROL(!g.kimlikliMi()); // başlatılmadan etiket yok g.kimlikleriBaslat(); FIKO_KONTROL(g.kimlikliMi()); u32 yuzN = 0; for (u32 o = 1; o <= 128; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb, false)) break; ++yuzN; } FIKO_KONTROL(yuzN == 6); // kutu = 6 yüz std::set gorulen; for (u32 o = 1; o <= yuzN; ++o) { const u64 kid = g.yuzKimlik(o); FIKO_KONTROL(kid != 0); // her yüz etiketli FIKO_KONTROL(gorulen.insert(kid).second); // benzersiz (çakışma yok) FIKO_KONTROL(g.yuzKimlikOrd(kid) == o); // ters arama ordinali geri verir } FIKO_KONTROL(g.kenarKimlik(1) != 0); // kenarlar da etiketli FIKO_KONTROL(g.noktaKimlik(1) != 0); // noktalar da etiketli FIKO_KONTROL(g.yuzKimlikOrd(999999999ull) == 0); // olmayan etiket → 0 // İdempotent: yeniden başlat → mevcut etiketler değişmez (atanmışa dokunmaz) const u64 yuz1 = g.yuzKimlik(1); g.kimlikleriBaslat(); FIKO_KONTROL(g.yuzKimlik(1) == yuz1); } FIKO_TEST(kalici_kimlik_miras_propagasyon) { // KYA Faz 2: history ile etiket TAŞIma (global benzersiz) BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); const u64 aYuz2 = a.yuzKimlik(2), aYuz6 = a.yuzKimlik(6), aKenar1 = a.kenarKimlik(1); // "Sonuç" gövde (aynı geometri); yüz geri: 1..5→girdi 1..5 (geçti), yüz6→0 (op yarattı). BrepGovde b = kutu(10, 10, 10); b.kimlikMiras(a, {1, 2, 3, 4, 5, 0}); FIKO_KONTROL(b.yuzKimlik(2) == aYuz2); // aynı yüz → AYNI etiket (stabil) FIKO_KONTROL(b.yuzKimlik(6) != 0); // op yarattı → taze FIKO_KONTROL(b.yuzKimlik(6) != aYuz6); // girdinin 6.sından farklı (global-yeni) FIKO_KONTROL(b.kenarKimlik(1) == aKenar1); // özdeş geometri → kenar da geometrik miras std::set bS; for (u32 o = 1; o <= 6; ++o) FIKO_KONTROL(bS.insert(b.yuzKimlik(o)).second); // yüzler benzersiz // Yüz BÖLÜNMESİ: iki sonuç yüzü aynı girdiye → ilki miras, ikincisi taze (çakışma yok). BrepGovde c = kutu(10, 10, 10); c.kimlikMiras(a, {1, 1, 3, 4, 5, 6}); FIKO_KONTROL(c.yuzKimlik(1) == a.yuzKimlik(1)); // ilk kopya girdinin etiketini alır FIKO_KONTROL(c.yuzKimlik(2) != a.yuzKimlik(1)); // ikinci → taze (benzersizlik korunur) FIKO_KONTROL(c.yuzKimlik(2) != 0); } // REGRESYON (07-21): zincirin İLK feature'ında (boş belgede sketch→Pad) girdi gövdesi // GEÇERSİZDİR. kimlikMiras bu durumda `girdi.icerik_->sekil` dereferansı yapıp süreci // düşürüyordu (MSVC "resource deadlock would occur"); OCCT sarmalayıcıları yalnız // Standard_Failure yakaladığından istisna görünmeden kaçıyor, kullanıcıya DONMA olarak // yansıyordu. Beklenen: miras yok → her öğe TAZE ve BENZERSİZ etiket alır, çökme yok. FIKO_TEST(kalici_kimlik_gecersiz_girdi_cokmez) { const BrepGovde bos; // hiç kurulmamış gövde (icerik_ yok) FIKO_KONTROL(!bos.gecerliMi()); BrepGovde g = kutu(10, 10, 10); FIKO_KONTROL(g.gecerliMi()); g.kimlikMiras(bos, {}); // ÇÖKMEMELİ (eski kod burada düşüyordu) FIKO_KONTROL(g.kimlikliMi()); std::set gorulen; for (u32 o = 1; o <= 6; ++o) { const u64 kid = g.yuzKimlik(o); FIKO_KONTROL(kid != 0); // her yüz etiketli FIKO_KONTROL(gorulen.insert(kid).second); // benzersiz FIKO_KONTROL(g.yuzKimlikOrd(kid) == o); // ters arama tutarlı } FIKO_KONTROL(g.kenarKimlik(1) != 0); // kenarlar da taze etiketli FIKO_KONTROL(g.noktaKimlik(1) != 0); // noktalar da taze etiketli // Geri-harita DOLU ama girdi yine geçersiz (provenansKaydet'in gerçek çağrı biçimi). BrepGovde h = kutu(4, 4, 4); h.kimlikMiras(bos, {1, 2, 3, 4, 5, 6}); FIKO_KONTROL(h.kimlikliMi()); FIKO_KONTROL(h.yuzKimlik(1) != 0 && h.yuzKimlik(6) != 0); FIKO_KONTROL(h.yuzKimlik(1) != g.yuzKimlik(1)); // etiketler GLOBAL benzersiz kalır // Geçersiz SONUÇ gövdesi: sessiz no-op (eski davranış korunur). BrepGovde bos2; bos2.kimlikMiras(g, {1}); FIKO_KONTROL(!bos2.kimlikliMi()); } FIKO_TEST(kalici_kimlik_gercek_fillet_propagasyon) { // KYA: GERÇEK op (fillet) + gerçek geri-harita BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); std::vector aKid; // a'nın yüz KID'leri (ordinal-1) for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; aKid.push_back(a.yuzKimlik(o)); } FIKO_KONTROL(aKid.size() == 6); BrepGovde f = yuvarlat(a, {1}, 2.0); // bir kenarı yuvarlat → 6 trim + 1 fillet yüz FIKO_KONTROL(f.gecerliMi()); const std::vector geri = geometri::yuzGeometrikEsle(a, f); // provenansKaydet ölçütü f.kimlikMiras(a, geri); const std::set aSet(aKid.begin(), aKid.end()); std::set alinan; // hangi girdi ordinali mirası ALDI (bölünme guard'ı) std::set hepsi; int eslesen = 0, taze = 0; for (std::size_t j = 0; j < geri.size(); ++j) { const u64 k = f.yuzKimlik((u32)(j + 1)); FIKO_KONTROL(k != 0); FIKO_KONTROL(hepsi.insert(k).second); // TÜM sonuç yüz KID'leri benzersiz const int g = geri[j]; if (g > 0 && (std::size_t)g <= aKid.size() && alinan.insert(g).second) { FIKO_KONTROL(k == aKid[g - 1]); // aynı yüz → AYNI etiket (gerçek geometri, STABİL) ++eslesen; } else { FIKO_KONTROL(aSet.find(k) == aSet.end()); // op yarattı / bölünme fazlası → taze (a'da yok) ++taze; } } FIKO_KONTROL(eslesen >= 3); // çoğu yüz korunur (fillet komşu duvarları trimler ama kimliği taşınır) FIKO_KONTROL(taze >= 1); // en az fillet yüzü yeni etiket } FIKO_TEST(kalici_kimlik_topolojik_kenar) { // KYA: kenar = bitişik yüz-KID çifti → ÖTELENEN kenar stabil BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); u32 ust = 0; // üst yüz (+z normal) for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && yb.normal.z > 0.9) { ust = o; break; } } FIKO_KONTROL(ust != 0); std::set ustKenarKid; // a: üst yüze komşu kenarların KID'leri (kutu üst yüz = 4 kenar) for (u32 o = 1;; ++o) { KenarBilgi kb; if (!a.kenarBilgi(o, kb)) break; const auto komsu = a.kenarKomsuYuzler(o); if (std::find(komsu.begin(), komsu.end(), ust) != komsu.end()) ustKenarKid.insert(a.kenarKimlik(o)); } FIKO_KONTROL(ustKenarKid.size() >= 4); // ≥4 (paylaşılan kenar TopExp'te ordinal başına çift sayılır) const int hedef = (int)ustKenarKid.size(); BrepGovde m = yuzTasi(a, ust, {0, 0, 5}); // üst yüzü +z taşı → üst kenarlar ÖTELENİR (orta değişir) FIKO_KONTROL(m.gecerliMi()); // Sentetik geri-harita (history simülasyonu): kutu yüzleri benzersiz eksen-normalli → normalle eşle. auto yn = [](const BrepGovde& g, u32 o) { YuzBilgi yb; g.yuzBilgi(o, yb, false); return yb.normal; }; u32 mYuz = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!m.yuzBilgi(o, yb, false)) break; ++mYuz; } u32 aYuz = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; ++aYuz; } std::vector geri(mYuz, 0); for (u32 j = 1; j <= mYuz; ++j) { const Vec3d nmj = yn(m, j); for (u32 i = 1; i <= aYuz; ++i) if ((yn(a, i) - nmj).uzunlukKare() < 1e-6) { geri[j - 1] = (int)i; break; } } m.kimlikMiras(a, geri); std::set mKenarKid; for (u32 o = 1;; ++o) { KenarBilgi kb; if (!m.kenarBilgi(o, kb)) break; mKenarKid.insert(m.kenarKimlik(o)); } int korunan = 0; for (u64 k : ustKenarKid) if (mKenarKid.count(k)) ++korunan; FIKO_KONTROL(korunan == hedef); // TÜM üst-kenar KID'leri korundu (saf geometri 0 verirdi — kenar ötelendi) } FIKO_TEST(kalici_kimlik_topolojik_nokta) { // KYA: nokta = bitişik yüz-KID kümesi → ÖTELENEN köşe stabil BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); u32 ust = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && yb.normal.z > 0.9) { ust = o; break; } } FIKO_KONTROL(ust != 0); // a: üst yüzün TÜM köşe (vertex) KID'leri — bunlar taşımada ötelenecek. std::set aNoktaKid; // a'nın tüm vertex KID'leri (kümesi; ordinal çift-sayımı normalize) for (u32 o = 1;; ++o) { Vec3d p; if (!a.noktaKonum(o, p)) break; aNoktaKid.insert(a.noktaKimlik(o)); } FIKO_KONTROL(aNoktaKid.size() >= 8); // kutu = 8 fiziksel köşe (ordinal başına tekrar olabilir) BrepGovde m = yuzTasi(a, ust, {0, 0, 5}); // üst yüzü +z → üst köşeler ÖTELENİR FIKO_KONTROL(m.gecerliMi()); auto yn = [](const BrepGovde& g, u32 o) { YuzBilgi yb; g.yuzBilgi(o, yb, false); return yb.normal; }; u32 mYuz = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!m.yuzBilgi(o, yb, false)) break; ++mYuz; } u32 aYuz = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; ++aYuz; } std::vector geri(mYuz, 0); // sentetik history: kutu yüzleri benzersiz eksen-normalli for (u32 j = 1; j <= mYuz; ++j) { const Vec3d nmj = yn(m, j); for (u32 i = 1; i <= aYuz; ++i) if ((yn(a, i) - nmj).uzunlukKare() < 1e-6) { geri[j - 1] = (int)i; break; } } m.kimlikMiras(a, geri); std::set mNoktaKid; for (u32 o = 1;; ++o) { Vec3d p; if (!m.noktaKonum(o, p)) break; mNoktaKid.insert(m.noktaKimlik(o)); } int korunan = 0; for (u64 k : aNoktaKid) if (mNoktaKid.count(k)) ++korunan; FIKO_KONTROL(korunan == (int)aNoktaKid.size()); // TÜM köşe KID'leri korundu (üst köşeler ötelendiği hâlde) } FIKO_TEST(kalici_kimlik_boolean_stabil) { // KYA: BOOLEAN sonrası kimlik korunumu (CATIA'nın zayıf noktası) BrepGovde a = kutu(10, 10, 10); // [-5,5]³ a.kimlikleriBaslat(); u64 solKid = 0; // a'nın -x yüzü (birleşimden ETKİLENMEZ — b +x tarafta) for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && yb.normal.x < -0.9) { solKid = a.yuzKimlik(o); break; } } FIKO_KONTROL(solKid != 0); Donusumd kaydir; kaydir.konum = {7, 0, 0}; BrepGovde b = donusumUygula(kutu(6, 6, 6), kaydir); // X∈[4,10], Y/Z∈[-3,3] → a ile +x'te örtüşür BrepGovde birlik = birlesim(a, b); FIKO_KONTROL(birlik.gecerliMi()); const std::vector geri = geometri::yuzGeometrikEsle(a, birlik); birlik.kimlikMiras(a, geri); std::set bKid; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!birlik.yuzBilgi(o, yb, false)) break; bKid.insert(birlik.yuzKimlik(o)); } FIKO_KONTROL(bKid.count(solKid) == 1); // -x yüz KID'i KORUNDU (boolean topolojik-naming'i bozmadı) int korunan = 0; // a'nın kaç yüzü birleşimde etiketini korudu (b yalnız +x yüzü tüketir → ~5) for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (bKid.count(a.yuzKimlik(o))) ++korunan; } FIKO_KONTROL(korunan >= 3); } FIKO_TEST(kalici_kimlik_cut_stabil) { // KYA: ÇIKARMA (Cut) — hayatta-kalan yüz korunur + yeni yüz taze BrepGovde a = kutu(10, 10, 10); // [-5,5]³ a.kimlikleriBaslat(); u64 altKid = 0; // a'nın -z (alt) yüzü — köşe-çentikten UZAK, çıkarmadan etkilenmez for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && yb.normal.z < -0.9) { altKid = a.yuzKimlik(o); break; } } FIKO_KONTROL(altKid != 0); Donusumd kaydir; kaydir.konum = {5, 5, 5}; BrepGovde b = donusumUygula(kutu(6, 6, 6), kaydir); // [2,8]³ → a'nın +x+y+z köşesini oyar BrepGovde oyuk = cikarma(a, b); FIKO_KONTROL(oyuk.gecerliMi()); const std::vector geri = geometri::yuzGeometrikEsle(a, oyuk); oyuk.kimlikMiras(a, geri); std::set aSet; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; aSet.insert(a.yuzKimlik(o)); } std::set oKid; int yeni = 0, yeniTaze = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!oyuk.yuzBilgi(o, yb, false)) break; const u64 kid = oyuk.yuzKimlik(o); FIKO_KONTROL(kid != 0); FIKO_KONTROL(oKid.insert(kid).second); // TÜM sonuç yüz KID'leri benzersiz if ((std::size_t)(o - 1) < geri.size() && geri[o - 1] == 0) { // op'un yarattığı çentik duvarı ++yeni; if (aSet.find(kid) == aSet.end()) ++yeniTaze; // a'da olmayan TAZE etiket almalı } } FIKO_KONTROL(oKid.count(altKid) == 1); // -z yüz KID'i KORUNDU (çentik uzakta) FIKO_KONTROL(yeni >= 1); // çıkarma en az bir yeni yüz üretti (çentik duvarı) FIKO_KONTROL(yeniTaze == yeni); // her yeni yüz a'da olmayan taze KID aldı (çakışma yok) } FIKO_TEST(kalici_kimlik_zincir_iki_op) { // KYA: İKİ ardışık op (feature zinciri) boyunca KID persistansı auto yn = [](const BrepGovde& g, u32 o) { YuzBilgi yb; g.yuzBilgi(o, yb, false); return yb.normal; }; auto normalGeri = [&](const BrepGovde& src, const BrepGovde& dst) { // kutu yüzleri benzersiz normalli u32 ns = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!src.yuzBilgi(o, yb, false)) break; ++ns; } u32 nd = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!dst.yuzBilgi(o, yb, false)) break; ++nd; } std::vector geri(nd, 0); for (u32 j = 1; j <= nd; ++j) { const Vec3d nj = yn(dst, j); for (u32 i = 1; i <= ns; ++i) if ((yn(src, i) - nj).uzunlukKare() < 1e-6) { geri[j - 1] = (int)i; break; } } return geri; }; auto yuzOrdNormal = [&](const BrepGovde& g, Vec3d n) -> u32 { for (u32 o = 1;; ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && (yb.normal - n).uzunlukKare() < 1e-6) return o; } return 0; }; BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); const u64 altKid = a.yuzKimlik(yuzOrdNormal(a, {0, 0, -1})); // -z (alt) yüz — iki op'tan da uzak FIKO_KONTROL(altKid != 0); // op1: üst yüzü +z taşı BrepGovde r1 = yuzTasi(a, yuzOrdNormal(a, {0, 0, 1}), {0, 0, 4}); FIKO_KONTROL(r1.gecerliMi()); r1.kimlikMiras(a, normalGeri(a, r1)); FIKO_KONTROL(r1.yuzKimlikOrd(altKid) != 0); // op1 sonrası alt KID korundu // op2: r1'in +x yan yüzünü taşı (zincirin ikinci adımı — girdi = r1) BrepGovde r2 = yuzTasi(r1, yuzOrdNormal(r1, {1, 0, 0}), {4, 0, 0}); FIKO_KONTROL(r2.gecerliMi()); r2.kimlikMiras(r1, normalGeri(r1, r2)); FIKO_KONTROL(r2.yuzKimlikOrd(altKid) != 0); // İKİ op sonrası alt KID HÂLÂ aynı (zincir-sabit) FIKO_KONTROL(r2.yuzKimlik(r2.yuzKimlikOrd(altKid)) == altKid); // tam eşitlik (etiket bozulmadı) } FIKO_TEST(kalici_kimlik_shell_stabil) { // KYA: SHELL (kabuk) — topolojiyi sert değiştirir (iç yüzler ekler) BrepGovde a = kutu(10, 10, 10); a.kimlikleriBaslat(); u32 ust = 0, alt = 0; for (u32 o = 1; o <= 6; ++o) { YuzBilgi yb; if (!a.yuzBilgi(o, yb, false)) break; if (yb.duzlemMi && yb.normal.z > 0.9) ust = o; if (yb.duzlemMi && yb.normal.z < -0.9) alt = o; } FIKO_KONTROL(ust != 0 && alt != 0); const u64 altKid = a.yuzKimlik(alt); // dış -z yüz (kabuk sonrası dış yüzey aynen kalır) BrepGovde k = kabuk(a, {ust}, 1.0); // üstü aç → içi oyulur, iç duvarlar + ağız yüzleri yeni FIKO_KONTROL(k.gecerliMi()); const std::vector geri = geometri::yuzGeometrikEsle(a, k); k.kimlikMiras(a, geri); std::set kKid; u32 yeni = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!k.yuzBilgi(o, yb, false)) break; const u64 kid = k.yuzKimlik(o); FIKO_KONTROL(kid != 0); FIKO_KONTROL(kKid.insert(kid).second); // TÜM yüz KID'leri benzersiz (iç+dış hepsi) if ((std::size_t)(o - 1) < geri.size() && geri[o - 1] == 0) ++yeni; // iç duvar/ağız = yeni } FIKO_KONTROL(kKid.count(altKid) == 1); // dış -z yüz KID KORUNDU (kabuk dış yüzeyi değiştirmez) FIKO_KONTROL(yeni >= 1); // kabuk yeni iç yüz(ler) üretti } FIKO_TEST(kalici_kimlik_pattern_benzersiz) { // KYA: DİZİ (pattern) — duplike geometride KID çakışması YOK BrepGovde a = kutu(10, 10, 10); // [-5,5]³ a.kimlikleriBaslat(); BrepGovde p = diziDik(a, {1, 0, 0}, 20.0, 2, {0, 1, 0}, 0.0, 1); // X'te 2 kopya (x=0 ve +20, örtüşmez) FIKO_KONTROL(p.gecerliMi()); const std::vector geri = geometri::yuzGeometrikEsle(a, p); p.kimlikMiras(a, geri); std::set pKid; u32 yuzSay = 0; for (u32 o = 1;; ++o) { YuzBilgi yb; if (!p.yuzBilgi(o, yb, false)) break; ++yuzSay; const u64 kid = p.yuzKimlik(o); FIKO_KONTROL(kid != 0); FIKO_KONTROL(pKid.insert(kid).second); // HER yüz benzersiz KID — 2. kopya 1. ile ÇAKIŞMAZ } FIKO_KONTROL(yuzSay == 12); // 2 kutu × 6 yüz (benzersizlik guard duplikasyonda da tutuyor) } FIKO_TEST(kalici_kimlik_capraz_govde_benzersiz) { // KYA: yükleme + yeni gövde → KID ÇAKIŞMAZ (belge-geneli temel) BrepGovde a = kutu(10, 10, 10); a.kimlikleriYukle({1000, 1001, 1002, 1003, 1004, 1005}, {}, {}); // "dosyadan" → global sayaç ≥1006'ya çekilir FIKO_KONTROL(a.yuzKimlik(1) == 1000 && a.yuzKimlik(6) == 1005); std::set aSet; for (u32 o = 1; o <= 6; ++o) aSet.insert(a.yuzKimlik(o)); BrepGovde b = kutu(5, 5, 5); // YENİ gövde, etiketlenir b.kimlikleriBaslat(); for (u32 o = 1; o <= 6; ++o) { const u64 bk = b.yuzKimlik(o); FIKO_KONTROL(bk > 1005); // yükleme global'i ileri çekti → yeni etiketler üstünde FIKO_KONTROL(aSet.find(bk) == aSet.end()); // B'nin hiçbir yüz KID'i A'da YOK (çakışma yok) } } // ───────────────────────────────────────────────────────────────────────────── // ÖLÇÜM DEĞER DOĞRULUĞU (web üretim = analitik yer gerçeği) // Native ölçüm değer kaynakları (kenarBilgi/yuzBilgi/mesafe) exact OCCT'den okur → // analitik değerlerle birebir eşleşmeli. Web üretimde aynı değerleri verdiği için // bu testler "web ile aynı değer" doğrulamasıdır. // ───────────────────────────────────────────────────────────────────────────── // Silindirik yüzün yarıçapı (→ çap ölçümü) ve yan alanı EXACT olmalı. FIKO_TEST(olcum_silindir_yaricap_alan_exact) { const BrepGovde s = silindir(5, 10); // R=5, H=10 const TopolojiOzet t = topolojiOzeti(s); int silOrd = 0; YuzBilgi yb; for (int o = 1; o <= t.yuzSayi; ++o) { YuzBilgi cur; if (s.yuzBilgi(o, cur) && cur.silindirMi) { silOrd = o; yb = cur; break; } } FIKO_KONTROL(silOrd != 0); FIKO_YAKIN(yb.yaricap, 5.0, 1e-9); // çap = 10.000 FIKO_YAKIN(yb.alan, 2.0 * std::numbers::pi * 5.0 * 10.0, 1e-6); // yan alan = 100π } // Dairesel kenarın yarıçapı ve çevresi (→ yay/çember ölçümü) EXACT olmalı. FIKO_TEST(olcum_cember_kenar_exact) { const BrepGovde s = silindir(5, 10); const TopolojiOzet t = topolojiOzeti(s); int cemOrd = 0; KenarBilgi kb; for (int o = 1; o <= t.kenarSayi; ++o) { KenarBilgi cur; if (s.kenarBilgi(o, cur) && cur.cemberMi) { cemOrd = o; kb = cur; break; } } FIKO_KONTROL(cemOrd != 0); FIKO_YAKIN(kb.yaricap, 5.0, 1e-9); FIKO_YAKIN(kb.uzunluk, 2.0 * std::numbers::pi * 5.0, 1e-6); // çevre = 10π } // Kutu kenar uzunluğu ve yüz alanı EXACT (düz geometri, web ile birebir). FIKO_TEST(olcum_kutu_kenar_alan_exact) { const BrepGovde g = kutu(40, 40, 40); const TopolojiOzet t = topolojiOzeti(g); int duzOrd = 0; YuzBilgi yb; for (int o = 1; o <= t.yuzSayi; ++o) { YuzBilgi cur; if (g.yuzBilgi(o, cur) && cur.duzlemMi) { duzOrd = o; yb = cur; break; } } FIKO_KONTROL(duzOrd != 0); FIKO_YAKIN(yb.alan, 1600.0, 1e-6); KenarBilgi kb; FIKO_KONTROL(g.kenarBilgi(1, kb)); FIKO_YAKIN(kb.uzunluk, 40.0, 1e-9); } // EXACT mesafe (mesafe()=BRepExtrema, web-doğru) vs ölçüm sisteminin ÖRNEKLENMİŞ nokta // yolu. İki paralel silindir (eksen Z, R=5), eksenler X'te 20 → analitik mesafe = 10.000. // ÖLÇÜLDÜ (07-17): İNCE mesh ile örnekleme sapması ~0 (nokta=170) → sampling hipotezi // ÇÜRÜDÜ; native normal koşulda web ile eşleşiyor. Sapma ancak KABA LOD mesh'te veya çok // büyük yüzde (yuzNoktalari ~400 nokta cap) büyür — bu test ince mesh referansını kilitler. FIKO_TEST(olcum_mesafe_exact_vs_ornekleme_silindir) { const BrepGovde loc = silindir(5, 10); Donusumd dA, dB; dB.konum = {20, 0, 0}; const BrepGovde b = donusumUygula(silindir(5, 10), dB); // (1) EXACT — web-doğru yer gerçeği. FIKO_YAKIN(mesafe(loc, b), 10.0, 1e-6); // (2) Ölçüm sisteminin YOLU: silindirik yüzün yerel örnek noktaları + Dugum dönüşümü // (refCoz W() ile birebir), sonra en-yakın çift. const TopolojiOzet t = topolojiOzeti(loc); int silOrd = 0; for (int o = 1; o <= t.yuzSayi; ++o) { YuzBilgi cur; if (loc.yuzBilgi(o, cur) && cur.silindirMi) { silOrd = o; break; } } FIKO_KONTROL(silOrd != 0); const MeshVeri _mesh = loc.ucgenle({1, 1, 1}); // üçgenleme yerinde kur (yuzNoktalari okuyabilsin) const std::vector yerel = loc.yuzNoktalari(silOrd); FIKO_KONTROL(!yerel.empty()); f64 minKare = 1e30; for (const Vec3d& p : yerel) { const Vec3d wa = dA.noktaUygula(p); for (const Vec3d& q : yerel) { const Vec3d wb = dB.noktaUygula(q); minKare = std::min(minKare, (wa - wb).uzunlukKare()); } } const f64 ornekMesafe = std::sqrt(minKare); std::printf(" [OLCUM] exact=10.000000 ornekleme=%.6f sapma=%.6f mm (nokta=%zu)\n", ornekMesafe, ornekMesafe - 10.0, yerel.size()); // Heuristik minimumun ALTINA inemez (örnek noktalar gerçek yüzeyde). FIKO_KONTROL(ornekMesafe >= 10.0 - 1e-6); // İnce mesh referansı: sapma < 0.02mm (ölçülen ~0). Bu bozulursa (kaba mesh vb.) // ölçüm web'den sapmaya başlar → o zaman olcum'u BRepExtrema exact yola taşı (bayrakla). FIKO_KONTROL(ornekMesafe <= 10.0 + 0.02); // KABA MESH KARAKTERİZASYONU: "sometimes wrong"ın asıl mekanizması hipotezi. LOD/kaba // tessellation'da yuzNoktalari kabalaşır → örnekleme mesafesi FAZLA verir. Global kalite'yi // geçici kaba yapıp ÖLÇ (geri al). Sapma büyürse mekanizma doğrulanır. { KaliteAyar eski = kalite(); kalite().linOran = 0.08; kalite().yuzAngRad = 0.7; kalite().kenarAngRad = 0.7; // ~40° — çok kaba BrepGovde kabaLoc = silindir(5, 10); const MeshVeri _k = kabaLoc.ucgenle({1, 1, 1}); const TopolojiOzet tt = topolojiOzeti(kabaLoc); int co = 0; for (int o = 1; o <= tt.yuzSayi; ++o) { YuzBilgi c; if (kabaLoc.yuzBilgi(o, c) && c.silindirMi) { co = o; break; } } const std::vector kn = kabaLoc.yuzNoktalari(co); f64 mk = 1e30; for (const Vec3d& p : kn) { const Vec3d wa = dA.noktaUygula(p); for (const Vec3d& q : kn) mk = std::min(mk, (wa - dB.noktaUygula(q)).uzunlukKare()); } const f64 kabaMesafe = kn.empty() ? -1.0 : std::sqrt(mk); std::printf(" [OLCUM-KABA] ornekleme=%.6f sapma=%.6f mm (nokta=%zu)\n", kabaMesafe, kabaMesafe - 10.0, kn.size()); kalite() = eski; // GLOBAL durumu geri al (test izolasyonu) FIKO_KONTROL(kn.empty() || kabaMesafe >= 10.0 - 1e-6); } } // benzerYuzler TEŞHİS (07-17, Fikri: "silindirik yüzeylerde başka yüzey seçiyor"): // Kutuda R=5 DELİK + gövdenin dışında R=5 BOSS. benzerYuzler sözleşmesi "tip+ölçü, // konum/oryantasyon BAĞIMSIZ" → deliği seçince BOSS'u da almalı (delik/çıkıntı ayrımı YOK). // Bu testin amacı davranışı ÖLÇMEK (bug mu, sözleşme mi?). FIKO_TEST(benzer_yuzler_delik_vs_boss_teshis) { Donusumd d1; // delik silindiri (Z boyunca, kutunun içinden) d1.konum = {0, 0, 0}; BrepGovde kutu20 = kutu(20, 20, 20); BrepGovde delikSil = donusumUygula(silindir(5, 40), d1); BrepGovde delikli = cikarma(kutu20, delikSil); // R=5 delik FIKO_KONTROL(delikli.gecerliMi()); Donusumd d2; // dışarıda R=5 boss (kutuya bitişik) d2.konum = {30, 0, 0}; BrepGovde boss = donusumUygula(silindir(5, 20), d2); BrepGovde tum = birlesim(delikli, boss); FIKO_KONTROL(tum.gecerliMi()); // Tüm R=5 silindirik yüzleri bul (delik + boss) const TopolojiOzet t = topolojiOzeti(tum); std::vector silR5; for (int o = 1; o <= t.yuzSayi; ++o) { YuzBilgi y; if (tum.yuzBilgi(o, y) && y.silindirMi && std::abs(y.yaricap - 5.0) < 1e-6) silR5.push_back(o); } std::printf(" [BENZER] R=5 silindirik yuz sayisi: %zu\n", silR5.size()); FIKO_KONTROL(silR5.size() >= 2); // en az delik + boss const std::vector es = tum.benzerYuzler(silR5[0], 1e-3); std::printf(" [BENZER] benzerYuzler(delik) -> %zu yuz dondu\n", es.size()); // SÖZLEŞME: tip+ölçü eşleşen HEPSİ (delik VE boss) → ayrım yok. Bu doğrulanırsa // "başka yüzey seçiyor" bir BUG değil, sözleşmenin sonucudur → çözüm: içbükey/dışbükey filtresi. FIKO_KONTROL(es.size() == silR5.size()); } // ---- GSD Wireframe genisletme (Dalga A1): polyline / helix / konik / kose ---- FIKO_TEST(gsd_polyline_kapali_kare) { const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; BrepGovde g = polyline(kare, true); FIKO_KONTROL(g.gecerliMi()); const TopolojiOzet t = topolojiOzeti(g); FIKO_KONTROL(t.kenarSayi == 4); // kapali kare → 4 kenar FIKO_YAKIN(kenarUzunlugu(g), 40.0, 1e-6); // cevre } FIKO_TEST(gsd_polyline_acik) { const std::vector yol = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}}; BrepGovde g = polyline(yol, false); FIKO_KONTROL(g.gecerliMi()); FIKO_KONTROL(topolojiOzeti(g).kenarSayi == 2); FIKO_YAKIN(kenarUzunlugu(g), 20.0, 1e-6); } FIKO_TEST(gsd_helix_uzunluk) { BrepGovde g = helix({0, 0, 0}, {0, 0, 1}, 5.0, 10.0, 3.0, true); FIKO_KONTROL(g.gecerliMi()); // Tur-basi 3d uzunluk = sqrt((2pi*R)^2 + adim^2); toplam = tur * o. const f64 turUz = std::sqrt(std::pow(2.0 * std::numbers::pi * 5.0, 2) + 100.0); FIKO_YAKIN(kenarUzunlugu(g), 3.0 * turUz, 1.0); // BuildCurves3d yaklasik } FIKO_TEST(gsd_helix_gecersiz) { FIKO_KONTROL(!helix({0, 0, 0}, {0, 0, 1}, 0.0, 10.0, 3.0).gecerliMi()); // R=0 FIKO_KONTROL(!helix({0, 0, 0}, {0, 0, 0}, 5.0, 10.0, 3.0).gecerliMi()); // eksen sifir } FIKO_TEST(gsd_konik_gecerli) { BrepGovde parabol = konik({0, 0, 0}, {5, 8, 0}, {10, 0, 0}, 0.5); FIKO_KONTROL(parabol.gecerliMi()); BrepGovde elips = konik({0, 0, 0}, {5, 8, 0}, {10, 0, 0}, 0.3); FIKO_KONTROL(elips.gecerliMi()); BrepGovde hiperbol = konik({0, 0, 0}, {5, 8, 0}, {10, 0, 0}, 0.8); FIKO_KONTROL(hiperbol.gecerliMi()); FIKO_KONTROL(!konik({0, 0, 0}, {0, 0, 0}, {10, 0, 0}, 0.5).gecerliMi()); // cakisik } FIKO_TEST(gsd_kose_teget_yay) { // 90 derece kose: (-10,0)->(0,0)->(0,10). d1=-X, d2=+Y, aci=90. Yay donusu = 90 der. BrepGovde g = kose({-10, 0, 0}, {0, 0, 0}, {0, 10, 0}, 2.0); FIKO_KONTROL(g.gecerliMi()); FIKO_YAKIN(kenarUzunlugu(g), 2.0 * std::numbers::pi * 0.5, 1e-3); // R*(pi-aci)=2*pi/2 FIKO_KONTROL(!kose({-10, 0, 0}, {0, 0, 0}, {10, 0, 0}, 2.0).gecerliMi()); // dogrusal } FIKO_TEST(gsd_yuzey_fill_kare_alan) { // 10x10 kapali kare profil → dolu duzlemsel yuzey, alan=100. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde y = yuzeyFill(kare); FIKO_KONTROL(y.gecerliMi()); FIKO_YAKIN(y.alan(), 100.0, 1e-6); FIKO_KONTROL(topolojiOzeti(y).yuzSayi == 1); FIKO_KONTROL(!yuzeyFill({{0, 0, 0}, {10, 0, 0}}).gecerliMi()); // <3 nokta } FIKO_TEST(gsd_yuzey_uzat_alan_buyur) { // 10x10 dolu yuzey → 4 yonde 2 birim uzat → alan buyumeli (planar → bspline → extend). const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde y = yuzeyFill(kare); FIKO_KONTROL(y.gecerliMi()); const BrepGovde u = yuzeyUzat(y, 2.0); FIKO_KONTROL(u.gecerliMi()); FIKO_KONTROL(u.alan() > y.alan() + 1.0); // uzatilmis → daha genis FIKO_KONTROL(!yuzeyUzat(BrepGovde{}, 2.0).gecerliMi()); // gecersiz girdi } FIKO_TEST(gsd_sinir_kare_cevre) { // 10x10 dolu yuzeyin sinir teli → cevre 40. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde y = yuzeyFill(kare); FIKO_KONTROL(y.gecerliMi()); const BrepGovde s = sinir(y); FIKO_KONTROL(s.gecerliMi()); FIKO_YAKIN(kenarUzunlugu(s), 40.0, 1e-6); FIKO_KONTROL(!sinir(BrepGovde{}).gecerliMi()); } FIKO_TEST(gsd_kesisim_egrisi_iki_kutu) { // Ust uste binen iki kutu → kesisim EGRISI (kenar) var; kati DEGIL. BrepGovde k1 = kutu(10, 10, 10); Donusumd d; d.konum = {5, 5, 5}; BrepGovde k2 = donusumUygula(kutu(10, 10, 10), d); const BrepGovde ke = kesisimEgrisi(k1, k2); FIKO_KONTROL(ke.gecerliMi()); FIKO_KONTROL(topolojiOzeti(ke).kenarSayi > 0); FIKO_KONTROL(topolojiOzeti(ke).katiSayi == 0); // egri, kati degil } FIKO_TEST(gsd_afin_hacim_carpani) { // Non-uniform afin: 10x10x10 kutu, oran (2,3,1) → hacim x6 = 6000. BrepGovde k = kutu(10, 10, 10); FIKO_YAKIN(k.hacim(), 1000.0, 1e-6); const BrepGovde a = afin(k, 2.0, 3.0, 1.0); FIKO_KONTROL(a.gecerliMi()); FIKO_YAKIN(a.hacim(), 6000.0, 1e-3); FIKO_KONTROL(!afin(k, 0.0, 1.0, 1.0).gecerliMi()); // dejenere oran } FIKO_TEST(gsd_supurme_yuzey_alan) { // Profil = 4 birim düz tel, yol = 3 birim dik tel → düz süpürme yüzeyi, alan ≈ 12. const std::vector profil = {{0, 0, 0}, {4, 0, 0}}; const std::vector yol = {{0, 0, 0}, {0, 0, 3}}; const BrepGovde y = supurmeYuzey(profil, false, yol); FIKO_KONTROL(y.gecerliMi()); FIKO_YAKIN(y.alan(), 12.0, 0.5); FIKO_KONTROL(topolojiOzeti(y).katiSayi == 0); // yüzey, katı değil FIKO_KONTROL(!supurmeYuzey(profil, false, {{0, 0, 0}}).gecerliMi()); // yol <2 } FIKO_TEST(gsd_supurme_yuzey_tel_ustyukleme) { // BREP-sadık üstyükleme: profil teli (4 birim, x) yol teli (3 birim, z) boyunca → alan ≈ 12. const BrepGovde profil = cizgiIkiNokta({0, 0, 0}, {4, 0, 0}); const BrepGovde yol = cizgiIkiNokta({0, 0, 0}, {0, 0, 3}); FIKO_KONTROL(profil.gecerliMi() && yol.gecerliMi()); const BrepGovde y = supurmeYuzey(profil, yol); FIKO_KONTROL(y.gecerliMi()); FIKO_YAKIN(y.alan(), 12.0, 0.5); FIKO_KONTROL(topolojiOzeti(y).katiSayi == 0); // yüzey, katı değil FIKO_KONTROL(!supurmeYuzey(profil, BrepGovde{}).gecerliMi()); // geçersiz yol } FIKO_TEST(gsd_birlestir_egriler_tek_edge) { // 2 segmentli polyline (toplam 20) → tek B-spline edge; uzunluk ≈ korunur. const std::vector yol = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}}; const BrepGovde p = polyline(yol, false); FIKO_KONTROL(p.gecerliMi()); FIKO_KONTROL(topolojiOzeti(p).kenarSayi == 2); const BrepGovde b = birlestirEgriler(p); FIKO_KONTROL(b.gecerliMi()); FIKO_KONTROL(topolojiOzeti(b).kenarSayi == 1); // tek egri FIKO_YAKIN(kenarUzunlugu(b), 20.0, 0.5); FIKO_KONTROL(!birlestirEgriler(BrepGovde{}).gecerliMi()); } FIKO_TEST(gsd_onar_gecerli_korur) { // Sağlam gövdeyi onar → geçerli kalır, hacim korunur (idempotent smoke). BrepGovde k = kutu(10, 10, 10); const BrepGovde o = onar(k, 1e-4); FIKO_KONTROL(o.gecerliMi()); FIKO_YAKIN(o.hacim(), 1000.0, 1e-3); FIKO_KONTROL(topolojiOzeti(o).yuzSayi == 6); FIKO_KONTROL(!onar(BrepGovde{}).gecerliMi()); } FIKO_TEST(gsd_yuzey_ile_bol_iki_parca) { // Merkezli 10³ kutu, z=0 düzleminde büyük dolu yüzeyle bölünür → 2 parça, her biri 500. BrepGovde k = kutu(10, 10, 10); const std::vector duzlem = {{-20, -20, 0}, {20, -20, 0}, {20, 20, 0}, {-20, 20, 0}}; const BrepGovde y = yuzeyFill(duzlem); FIKO_KONTROL(y.gecerliMi()); const std::vector parcalar = yuzeyIleBol(k, y); FIKO_KONTROL(parcalar.size() == 2); f64 toplam = 0; for (const BrepGovde& p : parcalar) { FIKO_KONTROL(p.gecerliMi()); toplam += p.hacim(); } FIKO_YAKIN(toplam, 1000.0, 1e-3); // hacim korunur } FIKO_TEST(gsd_kabuktan_kati_hacim) { // Kutunun tüm yüzlerini yüzeye çıkar (kapalı kabuk) → katıya çevir → hacim 1000. BrepGovde k = kutu(10, 10, 10); const BrepGovde kabuk = yuzKopyala(k, {1, 2, 3, 4, 5, 6}); FIKO_KONTROL(kabuk.gecerliMi()); FIKO_KONTROL(topolojiOzeti(kabuk).katiSayi == 0); // açık kabuk const BrepGovde kati = kabuktanKati(kabuk); FIKO_KONTROL(kati.gecerliMi()); FIKO_YAKIN(kati.hacim(), 1000.0, 1e-3); FIKO_KONTROL(topolojiOzeti(kati).katiSayi == 1); // artık katı } FIKO_TEST(gsd_tel_supur_silindir_alan) { // R=5 çember teli Z boyunca 10 süpür → silindirik yüzey, yan alan = 2πR·h = 100π. BrepGovde cember = cemberMerkezR({0, 0, 0}, {0, 0, 1}, 5.0, 360.0); FIKO_KONTROL(cember.gecerliMi()); const BrepGovde yuzey = telSupur(cember, {0, 0, 1}, 10.0); FIKO_KONTROL(yuzey.gecerliMi()); FIKO_YAKIN(yuzey.alan(), 2.0 * std::numbers::pi * 5.0 * 10.0, 1e-2); FIKO_KONTROL(topolojiOzeti(yuzey).katiSayi == 0); // açık yüzey FIKO_KONTROL(!telSupur(cember, {0, 0, 0}, 10.0).gecerliMi()); // yön sıfır } FIKO_TEST(gsd_kenar_cikar_ve_supur) { // 10x10 dolu yüzey (4 kenar). Bir kenarı çıkar → uzunluk 10; süpür → strip yüzey. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde y = yuzeyFill(kare); const BrepGovde k1 = kenarCikar(y, 1); FIKO_KONTROL(k1.gecerliMi()); FIKO_KONTROL(topolojiOzeti(k1).kenarSayi == 1); FIKO_YAKIN(kenarUzunlugu(k1), 10.0, 1e-6); const BrepGovde strip = telSupur(k1, {0, 0, 1}, 5.0); // kenarı Z'de süpür → 10x5 strip FIKO_KONTROL(strip.gecerliMi()); FIKO_YAKIN(strip.alan(), 50.0, 1e-6); FIKO_KONTROL(!kenarCikar(y, 99).gecerliMi()); // olmayan ordinal } FIKO_TEST(gsd_yuzey_sisir_kubbe) { // 20x20 düz yüzey (alan 400). Merkezde şişir → pürüzsüz kubbe, alan artar, geçerli. const std::vector kare = {{0, 0, 0}, {20, 0, 0}, {20, 20, 0}, {0, 20, 0}}; const BrepGovde duz = yuzeyFill(kare); FIKO_KONTROL(duz.gecerliMi()); FIKO_YAKIN(duz.alan(), 400.0, 1e-6); const BrepGovde kubbe = yuzeySisir(duz, {10, 10, 0}, 15.0, 5.0); FIKO_KONTROL(kubbe.gecerliMi()); FIKO_KONTROL(topolojiOzeti(kubbe).yuzSayi == 1); FIKO_KONTROL(kubbe.alan() > 400.5); // kubbe → yüzey alanı artar // İndir (negatif) da geçerli + alan artar (çukur da yüzey ekler). const BrepGovde cukur = yuzeySisir(duz, {10, 10, 0}, 15.0, -5.0); FIKO_KONTROL(cukur.gecerliMi()); FIKO_KONTROL(cukur.alan() > 400.5); FIKO_KONTROL(!yuzeySisir(duz, {10, 10, 0}, 0.0, 5.0).gecerliMi()); // yarıçap 0 } FIKO_TEST(gsd_yuzey_sisir_cok_hedef) { // 40x40 düz yüzey, iki ayrı noktada tepe → tek yüzeyde iki kubbe (multi-inflate). const std::vector kare = {{0, 0, 0}, {40, 0, 0}, {40, 40, 0}, {0, 40, 0}}; const BrepGovde duz = yuzeyFill(kare); FIKO_KONTROL(duz.gecerliMi()); const BrepGovde iki = yuzeySisirCok(duz, {{{10, 10, 0}, 5.0}, {{30, 30, 0}, 5.0}}, 8.0); FIKO_KONTROL(iki.gecerliMi()); FIKO_KONTROL(topolojiOzeti(iki).yuzSayi == 1); FIKO_KONTROL(iki.alan() > 400.5); // iki kubbe → alan artar // Tek-hedef çağrı = yuzeySisir ile aynı (delegasyon doğrulaması). const BrepGovde tek = yuzeySisirCok(duz, {{{20, 20, 0}, 4.0}}, 10.0); FIKO_YAKIN(tek.alan(), yuzeySisir(duz, {20, 20, 0}, 10.0, 4.0).alan(), 1e-6); FIKO_KONTROL(!yuzeySisirCok(duz, {}, 8.0).gecerliMi()); // boş hedef → geçersiz FIKO_KONTROL(!yuzeySisirCok(duz, {{{10, 10, 0}, 0.0}}, 8.0).gecerliMi()); // tüm miktar ~0 } FIKO_TEST(brep_kenardan_yuz_eg) { // Fikri DM: "kenardan tutup açı verme" — kutunun +X yan yüzü ALT kenarından 10° eğilir: // menteşe kenarı SABİT kalır, yüz normali eski normalle ~10° yapar, katı geçerli kalır. const BrepGovde k = kutu(20, 20, 10); // merkezli: x∈[-10,10], z∈[-5,5] // +X yüzünü ve onun alt (z=-5) kenarını ordinallerden bul (TopExp sırasına bağımlı olma). u32 yuz = 0, kenar = 0; const auto oz = topolojiOzeti(k); for (u32 f = 1; f <= (u32)oz.yuzSayi && !yuz; ++f) { YuzBilgi yb; if (k.yuzBilgi(f, yb, false) && yb.duzlemMi && std::abs(yb.normal.x) > 0.99 && yb.merkez.x > 9.0) yuz = f; } FIKO_KONTROL(yuz != 0); for (u32 e = 1; e <= (u32)oz.kenarSayi && !kenar; ++e) { KenarBilgi kb; if (k.kenarBilgi(e, kb) && kb.dogruMu && std::abs(kb.orta.x - 10.0) < 1e-6 && std::abs(kb.orta.z + 5.0) < 1e-6) kenar = e; } FIKO_KONTROL(kenar != 0); const BrepGovde e10 = kenardanYuzEg(k, kenar, yuz, 10.0); FIKO_KONTROL(e10.gecerliMi()); // Menteşe kenarı sabit: eğik gövdede x≈10,z≈-5 doğrusal kenar hâlâ var. bool menteseVar = false; const auto oz2 = topolojiOzeti(e10); for (u32 e = 1; e <= (u32)oz2.kenarSayi && !menteseVar; ++e) { KenarBilgi kb; if (e10.kenarBilgi(e, kb) && kb.dogruMu && std::abs(kb.orta.x - 10.0) < 1e-4 && std::abs(kb.orta.z + 5.0) < 1e-4) menteseVar = true; } FIKO_KONTROL(menteseVar); // Eğilen yüzün normali eski +X ile ~10° (yüzü yeniden bul: merkez x hâlâ en büyük). f64 enX = -1e9; Vec3d yeniN{}; for (u32 f = 1; f <= (u32)oz2.yuzSayi; ++f) { YuzBilgi yb; if (e10.yuzBilgi(f, yb, false) && yb.duzlemMi && yb.merkez.x > enX && std::abs(yb.normal.x) > 0.5) { enX = yb.merkez.x; yeniN = yb.normal.birim(); } } const f64 kos = std::abs(yeniN.x); // eski normal (±1,0,0) ile açı kosinüsü FIKO_YAKIN(std::acos(std::clamp(kos, 0.0, 1.0)) * 180.0 / std::numbers::pi, 10.0, 0.5); FIKO_KONTROL(std::abs(e10.hacim() - k.hacim()) > 1.0); // hacim gerçekten değişti // Dejenere/geçersiz girişler güvenli. FIKO_KONTROL(!kenardanYuzEg(k, kenar, yuz, 0.0).gecerliMi()); FIKO_KONTROL(!kenardanYuzEg(k, 0, yuz, 10.0).gecerliMi()); } FIKO_TEST(brep_kenar_tasi) { // Fikri DM: "kenardan çekince SADECE o kenar uzasın" — kutunun üst yüzü (+Z) sağ (x=+10) // kenarından 2mm dışarı çekilir: kenar (12,·,5)'e taşınır, üst yüz düzleminde uzar (sol // kenarı sabit), +X duvarı alt menteşesinden eğilir (alt kenarı sabit) → hacim + kama. const BrepGovde k = kutu(20, 20, 10); // x∈[-10,10], y∈[-10,10], z∈[-5,5] u32 yuz = 0, kenar = 0; const auto oz = topolojiOzeti(k); for (u32 f = 1; f <= (u32)oz.yuzSayi && !yuz; ++f) { YuzBilgi yb; if (k.yuzBilgi(f, yb, false) && yb.duzlemMi && std::abs(yb.normal.z) > 0.99 && yb.merkez.z > 4.0) yuz = f; // üst yüz } FIKO_KONTROL(yuz != 0); for (u32 e = 1; e <= (u32)oz.kenarSayi && !kenar; ++e) { KenarBilgi kb; if (k.kenarBilgi(e, kb) && kb.dogruMu && std::abs(kb.orta.x - 10.0) < 1e-6 && std::abs(kb.orta.z - 5.0) < 1e-6) kenar = e; // üst-sağ kenar (üst yüz ∩ +X duvarı) } FIKO_KONTROL(kenar != 0); const BrepGovde t2 = kenarTasi(k, kenar, yuz, 2.0); FIKO_KONTROL(t2.gecerliMi()); // Çekilen kenar (12,·,5)'te; üst yüzün SOL kenarı (-10,·,5) ve duvarın ALT kenarı (10,·,-5) sabit. bool tasindi = false, solSabit = false, altSabit = false; const auto oz2 = topolojiOzeti(t2); for (u32 e = 1; e <= (u32)oz2.kenarSayi; ++e) { KenarBilgi kb; if (!t2.kenarBilgi(e, kb) || !kb.dogruMu) continue; if (std::abs(kb.orta.x - 12.0) < 1e-4 && std::abs(kb.orta.z - 5.0) < 1e-4) tasindi = true; if (std::abs(kb.orta.x + 10.0) < 1e-4 && std::abs(kb.orta.z - 5.0) < 1e-4) solSabit = true; if (std::abs(kb.orta.x - 10.0) < 1e-4 && std::abs(kb.orta.z + 5.0) < 1e-4) altSabit = true; } FIKO_KONTROL(tasindi); FIKO_KONTROL(solSabit); FIKO_KONTROL(altSabit); FIKO_YAKIN(t2.hacim(), 4000.0 + 0.5 * 2.0 * 10.0 * 20.0, 2.0); // + kama ½·d·h·w = 200 FIKO_KONTROL(topolojiOzeti(t2).yuzSayi == 6); // dikişsiz: uzayan yüz TEK parça kalır // İçeri çekme: hacim kama kadar azalır; dejenere girişler güvenli. const BrepGovde ti = kenarTasi(k, kenar, yuz, -2.0); FIKO_KONTROL(ti.gecerliMi()); FIKO_YAKIN(ti.hacim(), 4000.0 - 200.0, 2.0); FIKO_KONTROL(!kenarTasi(k, kenar, yuz, 0.0).gecerliMi()); FIKO_KONTROL(!kenarTasi(k, 0, yuz, 2.0).gecerliMi()); // ZİNCİR (Fikri: "bir daha aynı kenara uzatamıyorum"): duvar İLK uzatmadan eğikken // ikinci uzatma da TAM mesafe gitmeli (atan(d/L) yaklaşımı burada sapıyordu). u32 yuz2 = 0, kenar2 = 0; for (u32 f = 1; f <= (u32)oz2.yuzSayi && !yuz2; ++f) { YuzBilgi yb; if (t2.yuzBilgi(f, yb, false) && yb.duzlemMi && std::abs(yb.normal.z) > 0.99 && yb.merkez.z > 4.0) yuz2 = f; } for (u32 e = 1; e <= (u32)oz2.kenarSayi && !kenar2; ++e) { KenarBilgi kb; if (t2.kenarBilgi(e, kb) && kb.dogruMu && std::abs(kb.orta.x - 12.0) < 1e-4 && std::abs(kb.orta.z - 5.0) < 1e-4) kenar2 = e; } FIKO_KONTROL(yuz2 != 0 && kenar2 != 0); const BrepGovde t3 = kenarTasi(t2, kenar2, yuz2, 3.0); FIKO_KONTROL(t3.gecerliMi()); bool zincir = false; const auto oz3 = topolojiOzeti(t3); for (u32 e = 1; e <= (u32)oz3.kenarSayi && !zincir; ++e) { KenarBilgi kb; if (t3.kenarBilgi(e, kb) && kb.dogruMu && std::abs(kb.orta.x - 15.0) < 1e-3 && std::abs(kb.orta.z - 5.0) < 1e-3) zincir = true; } FIKO_KONTROL(zincir); FIKO_YAKIN(t3.hacim(), 4200.0 + 0.5 * 3.0 * 10.0 * 20.0, 3.0); // + ikinci kama 300 } FIKO_TEST(gsd_yuzey_sisir_kirpma_korunur) { // Fikri 07-22: "dairesel yüzeyi şişirince KAREYE dönüşüyor" — şişirme MakeFace(bs) ile // yüzeyi UV dikdörtgeninden kurunca kırpma (trim) telleri atılıyordu. Üçgen yüzey şişince // ÜÇGEN kalmalı (3 kenar), dikdörtgene (4 kenar) dönmemeli; alan da patlamamalı. const std::vector ucgen = {{0, 0, 0}, {40, 0, 0}, {0, 40, 0}}; const BrepGovde duz = yuzeyFill(ucgen); FIKO_KONTROL(duz.gecerliMi()); const f64 alan0 = duz.alan(); // 800 const BrepGovde sis = yuzeySisir(duz, {13, 13, 0}, 12.0, 4.0); FIKO_KONTROL(sis.gecerliMi()); const auto oz = topolojiOzeti(sis); FIKO_KONTROL(oz.yuzSayi == 1); FIKO_KONTROL(oz.kenarSayi == 3); // kırpma korunur (kare olsa 4 olurdu) FIKO_KONTROL(sis.alan() > alan0 + 1e-6); // kubbe → alan artar FIKO_KONTROL(sis.alan() < alan0 * 1.5); // ama UV dikdörtgenine (2×) patlamaz } FIKO_TEST(gsd_yuzey_sisir_mesh_kalitesi) { // Fikri 07-22: "kenarlar güzel ama yüzey testere gibi" — kırpma korunduktan sonra mesh'in // sınır örneklemesi bozuksa (pcurve/3B eğri parametre uyumsuzluğu) mesh alanı BREP // alanından kaçar. ÖLÇÜM: üçgenleme alanı ≈ GProp alanı (%5 tolerans). const std::vector ucgen = {{0, 0, 0}, {40, 0, 0}, {0, 40, 0}}; const BrepGovde duz = yuzeyFill(ucgen); const auto meshAlanOlc = [](const BrepGovde& g) { const MeshVeri mv = g.ucgenle({1, 1, 1}); f64 s = 0.0; for (size_t i = 0; i + 2 < mv.indeksler.size(); i += 3) { const auto& a = mv.vertexler[mv.indeksler[i]].konum; const auto& b = mv.vertexler[mv.indeksler[i + 1]].konum; const auto& c = mv.vertexler[mv.indeksler[i + 2]].konum; const Vec3d ab{(f64)b[0] - a[0], (f64)b[1] - a[1], (f64)b[2] - a[2]}; const Vec3d ac{(f64)c[0] - a[0], (f64)c[1] - a[1], (f64)c[2] - a[2]}; s += 0.5 * std::sqrt(ab.capraz(ac).uzunlukKare()); } return s; }; const BrepGovde sis = yuzeySisir(duz, {13, 13, 0}, 12.0, 4.0); FIKO_KONTROL(sis.gecerliMi()); const f64 alan = sis.alan(); FIKO_KONTROL(std::abs(meshAlanOlc(sis) - alan) < alan * 0.05); // ZİNCİR (Fikri ekranı: testere üçgenler): şişmiş B-spline yüzeyi TEKRAR şişir — yüzey // zaten NURBS iken de mesh sınırı temiz kalmalı, girdi gövdesi de bozulmamalı. // 🚨 Ders: NurbsConvert zaten-NURBS yüzde yüzeyi NULL bırakıyordu (nurbsBagimsizKopya). const f64 alanIlk = alan; const BrepGovde sis2 = yuzeySisir(sis, {13, 13, 2}, 12.0, 3.0); FIKO_KONTROL(sis2.gecerliMi()); const auto oz2 = topolojiOzeti(sis2); FIKO_KONTROL(oz2.yuzSayi == 1 && oz2.kenarSayi == 3); const f64 alan2 = sis2.alan(); FIKO_KONTROL(alan2 > alanIlk + 1e-6); FIKO_KONTROL(std::abs(meshAlanOlc(sis2) - alan2) < alan2 * 0.05); FIKO_YAKIN(sis.alan(), alanIlk, alanIlk * 1e-9); // GİRDİ deforme edilmedi (paylaşım yok) // DAİRESEL kırpma (Fikri ekranı: kubbe kenarında testere dişleri): eğri pcurve'lü // yüzde mesh sınırı kenar eğrisiyle uyumlu kalmalı — dişler mesh alanını şişirir. const BrepGovde sil = silindir(20.0, 10.0); u32 kapak = 0; const auto ozs = topolojiOzeti(sil); for (u32 f = 1; f <= (u32)ozs.yuzSayi && !kapak; ++f) { YuzBilgi yk; if (sil.yuzBilgi(f, yk, false) && yk.duzlemMi && yk.normal.z > 0.99) kapak = f; } FIKO_KONTROL(kapak != 0); const BrepGovde disk = yuzKopyala(sil, {kapak}); FIKO_KONTROL(disk.gecerliMi()); // GUI kalıbı: yarıçap = dünyaYarıçap×1.1 (tüm yüzey), büyük miktar — sınır-teğet // bölgelerde mesh/kenar uyumu asıl burada zorlanır (Fikri ekranındaki dişler). const BrepGovde kubbe = yuzeySisir(disk, {0, 0, 5}, 22.0, 8.0); FIKO_KONTROL(kubbe.gecerliMi()); FIKO_KONTROL(topolojiOzeti(kubbe).yuzSayi == 1); const f64 kAlan = kubbe.alan(); FIKO_KONTROL(kAlan > disk.alan() + 1e-6); FIKO_KONTROL(std::abs(meshAlanOlc(kubbe) - kAlan) < kAlan * 0.05); // FILL yüzeyi (GUI yolu: sketch çemberi → Yüzey Doldur → şişir): BRepFill_Filling // B-spline üretir, sınırı ÇOK kenarlı — mesh/kenar uyumu asıl bu dokuda zorlanır. std::vector cember; for (int i = 0; i < 24; ++i) { const f64 a = 2.0 * std::numbers::pi * i / 24.0; cember.push_back({20.0 * std::cos(a), 20.0 * std::sin(a), 0.0}); } const BrepGovde dolu = yuzeyFill(cember); FIKO_KONTROL(dolu.gecerliMi()); const BrepGovde kubbe2 = yuzeySisir(dolu, {0, 0, 0}, 22.0, 8.0); FIKO_KONTROL(kubbe2.gecerliMi()); const f64 k2Alan = kubbe2.alan(); FIKO_KONTROL(k2Alan > dolu.alan() + 1e-6); FIKO_KONTROL(std::abs(meshAlanOlc(kubbe2) - k2Alan) < k2Alan * 0.05); // KİLİTLİ + dairesel kırpma (Fikri GUI'si — kubbe eteği diş diş): kilit UV-dikdörtgen // halkasını değil GÖRÜNÜR sınırı sabitlemeli; kenar z≈0'da kalmalı, etek taraklanmamalı. const auto kenarMaksZ2 = [](const BrepGovde& g2) { f64 mz = 0.0; const auto ozk = topolojiOzeti(g2); for (u32 k = 1; k <= (u32)ozk.kenarSayi; ++k) for (const Vec3d& p : g2.kenarNoktalari(k)) mz = std::max(mz, std::abs(p.z)); return mz; }; const BrepGovde kilitli = yuzeySisirCok(dolu, {{{0, 0, 0}, 6.0}}, 22.0, true, 1); FIKO_KONTROL(kilitli.gecerliMi()); // Kırpılmış sınırda pole kilidi kesin sıfır TUTAMAZ (sınır parametrik kenar değil; iç // pole bazları taşar) — ölçülen: maksZ≈0.15 (miktarın %2.5'i, görünmez), sıçrama≈0.007 // (pürüzsüz). Eski UV-halka kilidi kısmi kilitle DİŞ DİŞ tarıyordu (sıçrama büyük). f64 mz = 0.0, sicrama = 0.0; const auto ozk2 = topolojiOzeti(kilitli); for (u32 k = 1; k <= (u32)ozk2.kenarSayi; ++k) { const auto pts = kilitli.kenarNoktalari(k); for (size_t i = 0; i < pts.size(); ++i) { mz = std::max(mz, std::abs(pts[i].z)); if (i) sicrama = std::max(sicrama, std::abs(pts[i].z - pts[i - 1].z)); } } FIKO_KONTROL(mz < 0.3); // görünür kenar ~yerinde (miktarın %5'i) FIKO_KONTROL(sicrama < 0.05); // diş yok: kenar boyunca z pürüzsüz FIKO_KONTROL(kilitli.alan() > dolu.alan() + 1.0); // iç bölge yine şişti const f64 kiAlan = kilitli.alan(); FIKO_KONTROL(std::abs(meshAlanOlc(kilitli) - kiAlan) < kiAlan * 0.05); (void)kenarMaksZ2; } FIKO_TEST(gsd_yuzey_sisir_sinir_kilit) { // Fikri 07-22 şişir modu: hedef KENARA yakınken kilitsiz şişirme sınırı da kaldırır // (bağlılık kopar); sinirKilit=true → sınır kenar noktaları z≈0'da SABİT kalır, // iç bölge gerilerek uzar. kilitDerinlik=2 de geçerli sonuç verir. const std::vector kare = {{0, 0, 0}, {40, 0, 0}, {40, 40, 0}, {0, 40, 0}}; const BrepGovde duz = yuzeyFill(kare); FIKO_KONTROL(duz.gecerliMi()); const auto kenarMaksZ = [](const BrepGovde& g) { f64 mz = 0.0; const auto oz = topolojiOzeti(g); for (u32 k = 1; k <= (u32)oz.kenarSayi; ++k) for (const Vec3d& p : g.kenarNoktalari(k)) mz = std::max(mz, std::abs(p.z)); return mz; }; const std::vector> hedef = {{{2.0, 20.0, 0.0}, 6.0}}; // sol kenara yakın const BrepGovde serbest = yuzeySisirCok(duz, hedef, 15.0, false); FIKO_KONTROL(serbest.gecerliMi()); FIKO_KONTROL(kenarMaksZ(serbest) > 0.5); // kilitsiz: sınır da kalktı (kopma riski) const BrepGovde kilitli = yuzeySisirCok(duz, hedef, 15.0, true, 1); FIKO_KONTROL(kilitli.gecerliMi()); FIKO_KONTROL(kenarMaksZ(kilitli) < 1e-6); // kilitli: sınır sabit — bağlılık korunur FIKO_KONTROL(kilitli.alan() > 400.5); // iç bölge yine şişti (uzama içeride) const BrepGovde derin = yuzeySisirCok(duz, hedef, 15.0, true, 2); FIKO_KONTROL(derin.gecerliMi() && kenarMaksZ(derin) < 1e-6); // Varsayılan (parametresiz) çağrı eski davranış BİREBİR (kilitsiz). FIKO_YAKIN(yuzeySisirCok(duz, hedef, 15.0).alan(), serbest.alan(), 1e-9); } FIKO_TEST(gsd_sisir_kilit_gecis_olcum) { // Ş2 ÖLÇÜM (tahmin yasak): kilitli şişirmede kenar→tepe geçişi ne kadar dik? // B-spline derece≥3 + kilitli dış halka matematiksel pürüzsüz; burada profil örneklenip // maks eğim + eğim-sıçraması SAYIYLA raporlanır (görsel karar Fikri'de). Assert yalnız // makullük: eğim patlaması yok, tepe kenardan yüksek. const std::vector kare = {{0, 0, 0}, {40, 0, 0}, {40, 40, 0}, {0, 40, 0}}; const BrepGovde duz = yuzeyFill(kare); const BrepGovde kilitli = yuzeySisirCok(duz, {{{2.0, 20.0, 0.0}, 6.0}}, 15.0, true, 1); FIKO_KONTROL(kilitli.gecerliMi()); std::vector gr; FIKO_KONTROL(yuzeyOrneklemGrid(kilitli, 41, 41, gr)); // Hedef hattı (y≈20) profili: x'e göre sırala, eğim + eğim-değişimi ölç. std::vector> prof; // (x, z) for (const Vec3d& p : gr) if (std::abs(p.y - 20.0) < 0.6) prof.push_back({p.x, p.z}); std::sort(prof.begin(), prof.end()); FIKO_KONTROL(prof.size() >= 10); f64 maksEgim = 0.0, maksSicrama = 0.0, oncekiEgim = 0.0, tepeZ = 0.0; for (size_t i = 1; i < prof.size(); ++i) { const f64 dx = prof[i].first - prof[i - 1].first; if (dx < 1e-9) continue; const f64 egim = (prof[i].second - prof[i - 1].second) / dx; maksEgim = std::max(maksEgim, std::abs(egim)); if (i > 1) maksSicrama = std::max(maksSicrama, std::abs(egim - oncekiEgim)); oncekiEgim = egim; tepeZ = std::max(tepeZ, prof[i].second); } std::printf(" [olcum] sisir-kilit gecis: tepeZ=%.3f maksEgim=%.3f maksEgimSicrama=%.3f\n", tepeZ, maksEgim, maksSicrama); FIKO_KONTROL(tepeZ > 1.0); // iç bölge gerçekten şişti FIKO_KONTROL(maksEgim < 10.0); // patlama yok (makullük) } FIKO_TEST(gsd_kenar_kaydir_reshape) { // 10x10 düz yüzey (z=0, alan 100). x=0 kenarını Z'de 5 kaldır → eğimli/eğri yüzey, alan artar. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde duz = yuzeyFill(kare); FIKO_KONTROL(duz.gecerliMi()); const BrepGovde y = kenarKaydir(duz, {0, 5, 0}, {0, 0, 5}); // x=0 kenarına yakın nokta FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(topolojiOzeti(y).yuzSayi == 1); // tek yüz (yeniden şekillendi, bölünmedi) FIKO_KONTROL(y.alan() > 105.0); // kenar kalktı → alan artar FIKO_KONTROL(y.alan() < 140.0); // sağlık sınırı (patlamadı) FIKO_KONTROL(!kenarKaydir(duz, {0, 5, 0}, {0, 0, 0}).gecerliMi()); // vec ~0 → geçersiz } FIKO_TEST(gsd_yama_kati_kenarlarindan) { // Katı kenarlarından yama: kutu üst yüzünün 4 kenarı kenarCikar ile tel'e → yamaYuzey // (gsd_sistemi "yamaYuzey kenarSayi>0" yolunun motor kompozisyonu). Alan ≈ üst yüz (100). const BrepGovde k = kutu(10, 10, 10); const int ke = topolojiOzeti(k).kenarSayi; f64 zmax = -1e30; for (int e = 1; e <= ke; ++e) { KenarBilgi kb; if (k.kenarBilgi((u32)e, kb)) zmax = std::max(zmax, std::max(kb.bas.z, kb.son.z)); } std::vector teller; std::vector ortalar; // aynı kenarın (paylaşımlı) çift kaydını orta-noktayla ele for (int e = 1; e <= ke; ++e) { KenarBilgi kb; if (!k.kenarBilgi((u32)e, kb)) continue; if (std::abs(kb.bas.z - zmax) > 1e-6 || std::abs(kb.son.z - zmax) > 1e-6) continue; bool tekrar = false; for (const Vec3d& o : ortalar) if ((o - kb.orta).uzunluk() < 1e-6) { tekrar = true; break; } if (tekrar) continue; BrepGovde t = kenarCikar(k, (u32)e); if (t.gecerliMi()) { teller.push_back(std::move(t)); ortalar.push_back(kb.orta); } } // NOT: kutu() ordinal uzayında üst yüzün 4 kenarından yalnız 3'ü benzersiz çıkıyor // (K10/K12 çift kayıt) — kompozisyon 3 kenarla da ~100'lük yüzeyi kurar (Filling U-sınır). FIKO_KONTROL((int)teller.size() >= 3); std::vector ptr; for (const auto& t : teller) ptr.push_back(&t); const BrepGovde y = yamaYuzey(ptr); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(topolojiOzeti(y).yuzSayi == 1); const f64 alanM = std::abs(y.alan()); // Filling yüzü ters oryantasyonlu dönebilir (işaretli alan) FIKO_KONTROL(alanM > 85.0 && alanM < 115.0); // ~üst yüz (100) — kompozisyon kilidi } FIKO_TEST(kati_kenar_tasi_kutu) { // Plasticity move-edge MVP: 10³ kutunun üst-ön kenarını (+y) içeri it → ön yüz eğilir, // üst yüz otomatik kırpılır → kama kesilmiş geçerli katı, hacim ~900. const BrepGovde k = kutu(10, 10, 10); // Üst-ön kenar: en yüksek z'de, x'e paralel, en küçük y'li kenar (orijinden bağımsız). u32 ord = 0; { const int ke = topolojiOzeti(k).kenarSayi; f64 zmax = -1e30; for (int e = 1; e <= ke; ++e) { KenarBilgi kb; if (k.kenarBilgi((u32)e, kb)) zmax = std::max(zmax, std::max(kb.bas.z, kb.son.z)); } f64 ymin = 1e30; for (int e = 1; e <= ke; ++e) { KenarBilgi kb; if (!k.kenarBilgi((u32)e, kb)) continue; if (std::abs(kb.bas.z - zmax) > 1e-6 || std::abs(kb.son.z - zmax) > 1e-6) continue; const Vec3d d = kb.son - kb.bas; if (std::abs(d.y) > 1e-6 || std::abs(d.z) > 1e-6) continue; // x'e paralel değil if (kb.orta.y < ymin) { ymin = kb.orta.y; ord = (u32)e; } } } FIKO_KONTROL(ord != 0); const BrepGovde y = katiKenarTasi(k, ord, {0, 2, 0}); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(topolojiOzeti(y).katiSayi == 1); FIKO_KONTROL(y.hacim() < 999.0); // kama kesildi FIKO_KONTROL(y.hacim() > 800.0); // ~900 (sağlık sınırı) FIKO_KONTROL(!katiKenarTasi(k, 999, {0, 2, 0}).gecerliMi()); // olmayan kenar FIKO_KONTROL(!katiKenarTasi(k, ord, {0, 0, 0}).gecerliMi()); // vec ~0 } FIKO_TEST(yuz_bilgi_ucuz_merkez_fallback) { // alanHesapla=false: merkez pahalı SurfaceProperties yerine UCUZ UV-orta ile DOLMALI — // gizmo her kare bunu çağırır; B-spline yüzde alan hesabı kare başına yüzlerce ms = donmaydı. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde duz = yuzeyFill(kare); geometri::YuzBilgi yb; FIKO_KONTROL(duz.yuzBilgi(1, yb, false)); FIKO_YAKIN(yb.merkez.x, 5.0, 1.5); // düzlemde UV-orta ≈ yüz ortası FIKO_YAKIN(yb.merkez.y, 5.0, 1.5); FIKO_YAKIN(yb.merkez.z, 0.0, 1e-6); const BrepGovde kubbe = yuzeySisir(duz, {5, 5, 0}, 8.0, 3.0); // B-spline yüz geometri::YuzBilgi yb2; FIKO_KONTROL(kubbe.yuzBilgi(1, yb2, false)); const f64 nl2 = yb2.normal.x * yb2.normal.x + yb2.normal.y * yb2.normal.y + yb2.normal.z * yb2.normal.z; FIKO_KONTROL(nl2 > 1e-9); // normal geçerli (gizmo oku çizilir) const f64 ml2 = yb2.merkez.x * yb2.merkez.x + yb2.merkez.y * yb2.merkez.y + yb2.merkez.z * yb2.merkez.z; FIKO_KONTROL(ml2 > 1e-9); // merkez dolu (çıpa var) } FIKO_TEST(gsd_sismis_yuzeyde_tekrar_op) { // ŞİŞMİŞ (NURBS) yüzeyde tekrar op çalışıyor mu? (Kullanıcı: "şişeni şişiremiyoruz") const std::vector kare = {{0, 0, 0}, {20, 0, 0}, {20, 20, 0}, {0, 20, 0}}; const BrepGovde duz = yuzeyFill(kare); const BrepGovde kubbe = yuzeySisir(duz, {10, 10, 0}, 15.0, 5.0); FIKO_KONTROL(kubbe.gecerliMi()); geometri::YuzBilgi yb; FIKO_KONTROL(kubbe.yuzBilgi(1, yb)); // gizmo bunu ister — DEGENERE OLMAMALI const f64 nlen = yb.normal.x * yb.normal.x + yb.normal.y * yb.normal.y + yb.normal.z * yb.normal.z; FIKO_KONTROL(nlen > 1e-9); // normal geçerli (gizmo oku çizilebilsin) FIKO_KONTROL(topolojiOzeti(kubbe).yuzSayi == 1); const BrepGovde kubbe2 = yuzeySisir(kubbe, {10, 10, 0}, 8.0, 3.0); FIKO_KONTROL(kubbe2.gecerliMi()); // şişmişi TEKRAR şişir const BrepGovde ofs = yuzeyOfset(kubbe, 2.0); FIKO_KONTROL(ofs.gecerliMi()); // şişmişte offset const BrepGovde kk = kenarKaydir(kubbe, {0, 10, 0}, {0, 0, 3}); FIKO_KONTROL(kk.gecerliMi()); // şişmişte kenar kaydır } FIKO_TEST(gsd_koprule_iki_kenar) { // İki paralel çizgi (z=0 ve z=10, x:0→20) → köprü = 20x10 düz şerit, alan 200. const BrepGovde a = cizgiIkiNokta({0, 0, 0}, {20, 0, 0}); const BrepGovde b = cizgiIkiNokta({0, 0, 10}, {20, 0, 10}); FIKO_KONTROL(a.gecerliMi() && b.gecerliMi()); const BrepGovde kopru = koprule(a, b); FIKO_KONTROL(kopru.gecerliMi()); FIKO_YAKIN(kopru.alan(), 200.0, 1e-1); FIKO_KONTROL(topolojiOzeti(kopru).katiSayi == 0); // açık yüzey FIKO_KONTROL(!koprule(a, BrepGovde{}).gecerliMi()); } FIKO_TEST(gsd_loft_uc_kesit_yuzey) { // 3 paralel çember kesit (z=0/10/20, R:5→8→5) → çok-kesitli açık shell (fıçı). const BrepGovde k0 = cemberMerkezR({0, 0, 0}, {0, 0, 1}, 5.0, 360.0); const BrepGovde k1 = cemberMerkezR({0, 0, 10}, {0, 0, 1}, 8.0, 360.0); const BrepGovde k2 = cemberMerkezR({0, 0, 20}, {0, 0, 1}, 5.0, 360.0); FIKO_KONTROL(k0.gecerliMi() && k1.gecerliMi() && k2.gecerliMi()); const BrepGovde y = loftYuzey({&k0, &k1, &k2}); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(topolojiOzeti(y).yuzSayi >= 1); FIKO_KONTROL(topolojiOzeti(y).katiSayi == 0); // açık yüzey, katı değil FIKO_KONTROL(!loftYuzey({&k0}).gecerliMi()); // tek kesit → geçersiz } FIKO_TEST(gsd_loft_kilavuzlu_yuzey) { // 2 çember kesit (R5, z=0/20) + düz kılavuz (z ekseni) → silindirimsi yüzey, alan ≈ 2π·5·20. const BrepGovde k0 = cemberMerkezR({0, 0, 0}, {0, 0, 1}, 5.0, 360.0); const BrepGovde k1 = cemberMerkezR({0, 0, 20}, {0, 0, 1}, 5.0, 360.0); const BrepGovde kl = cizgiIkiNokta({0, 0, 0}, {0, 0, 20}); FIKO_KONTROL(k0.gecerliMi() && k1.gecerliMi() && kl.gecerliMi()); const BrepGovde y = loftYuzeyKilavuz({&k0, &k1}, kl); FIKO_KONTROL(y.gecerliMi()); FIKO_YAKIN(y.alan(), 628.3, 35.0); FIKO_KONTROL(topolojiOzeti(y).katiSayi == 0); // açık yüzey FIKO_KONTROL(!loftYuzeyKilavuz({&k0}, kl).gecerliMi()); // tek kesit → geçersiz FIKO_KONTROL(!loftYuzeyKilavuz({&k0, &k1}, BrepGovde{}).gecerliMi()); // kılavuz yok } FIKO_TEST(gsd_yuzey_kirp_ikiye_boler) { // 10x10 düz kare yüzey, y=5'te dik şeritle kesilir → 2 alt-yüz (y<5, y>5). const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde yuzey = yuzeyFill(kare); const std::vector kesiciKontur = {{-1, 5, -1}, {11, 5, -1}, {11, 5, 1}, {-1, 5, 1}}; const BrepGovde kesici = yuzeyFill(kesiciKontur); FIKO_KONTROL(yuzey.gecerliMi() && kesici.gecerliMi()); const BrepGovde bol = yuzeyKirp(yuzey, kesici); FIKO_KONTROL(bol.gecerliMi()); FIKO_KONTROL(topolojiOzeti(bol).yuzSayi >= 2); // en az ikiye bölündü FIKO_KONTROL(!yuzeyKirp(yuzey, BrepGovde{}).gecerliMi()); } FIKO_TEST(gsd_yama_dort_kenar_egri_sinir) { // Eğri (saddle) 4-kenarlı sınır → pürüzsüz yama yüzey (BRepFill_Filling). const BrepGovde e0 = cizgiIkiNokta({0, 0, 0}, {10, 0, 2}); const BrepGovde e1 = cizgiIkiNokta({10, 0, 2}, {10, 10, 0}); const BrepGovde e2 = cizgiIkiNokta({10, 10, 0}, {0, 10, 2}); const BrepGovde e3 = cizgiIkiNokta({0, 10, 2}, {0, 0, 0}); FIKO_KONTROL(e0.gecerliMi() && e1.gecerliMi() && e2.gecerliMi() && e3.gecerliMi()); const BrepGovde y = yamaYuzey({&e0, &e1, &e2, &e3}); FIKO_KONTROL(y.gecerliMi()); FIKO_KONTROL(topolojiOzeti(y).yuzSayi == 1); // tek yama yüz FIKO_KONTROL(topolojiOzeti(y).katiSayi == 0); FIKO_KONTROL(!yamaYuzey({&e0, &e1}).gecerliMi()); // <3 kenar → geçersiz } FIKO_TEST(gsd_yuzey_orneklem_grid) { // 10x10 düz kare (z=0) → 5x5 grid, 25 nokta, hepsi z≈0 ve kare içinde. const std::vector kare = {{0, 0, 0}, {10, 0, 0}, {10, 10, 0}, {0, 10, 0}}; const BrepGovde y = yuzeyFill(kare); FIKO_KONTROL(y.gecerliMi()); std::vector g; FIKO_KONTROL(yuzeyOrneklemGrid(y, 5, 5, g)); FIKO_KONTROL((int)g.size() == 25); for (const Vec3d& p : g) { FIKO_KONTROL(p.z > -1e-6 && p.z < 1e-6); // düzlem üstünde FIKO_KONTROL(p.x > -1e-6 && p.x < 10.0 + 1e-6); // kare sınırında FIKO_KONTROL(p.y > -1e-6 && p.y < 10.0 + 1e-6); } FIKO_KONTROL(!yuzeyOrneklemGrid(y, 1, 5, g)); // nu<2 → false FIKO_KONTROL(g.empty()); } FIKO_TEST(gsd_yuzey_duzelt_kubbeyi_yumusatir) { // Şişirilmiş kubbeyi düzelt → alan azalır (düze doğru relax), geçerli kalır. const std::vector kare = {{0, 0, 0}, {20, 0, 0}, {20, 20, 0}, {0, 20, 0}}; const BrepGovde duz = yuzeyFill(kare); const BrepGovde kubbe = yuzeySisir(duz, {10, 10, 0}, 15.0, 6.0); FIKO_KONTROL(kubbe.gecerliMi()); const f64 kubbeAlan = kubbe.alan(); const BrepGovde yumusak = yuzeyDuzelt(kubbe, 0.5, 5); FIKO_KONTROL(yumusak.gecerliMi()); FIKO_KONTROL(yumusak.alan() < kubbeAlan); // relax → düzleşir → alan azalır FIKO_KONTROL(yumusak.alan() > 399.0); // ama hâlâ ~yüzey (aşırı çökmez) FIKO_KONTROL(!yuzeyDuzelt(kubbe, 0.5, 0).gecerliMi()); // iterasyon 0 } FIKO_TEST(gsd_koprule_ters_kenar_bowtie_denetim) { // a: (0,0,0)->(20,0,0), b TERS: (20,0,10)->(0,0,10). Hizasız köprü BOWTIE (kelebek) yapar // → alan ~2x şişer/kesişir. Sağlıklı köprü ~200 olmalı. Bu test sorunu ortaya çıkarır. const BrepGovde a = cizgiIkiNokta({0, 0, 0}, {20, 0, 0}); const BrepGovde b = cizgiIkiNokta({20, 0, 10}, {0, 0, 10}); const BrepGovde kopru = koprule(a, b); FIKO_KONTROL(kopru.gecerliMi()); std::printf(" [KOPRU-TERS] alan=%.2f (saglikli~200, bowtie~223+)\n", kopru.alan()); FIKO_KONTROL(kopru.alan() < 210.0); // bowtie'de alan çok büyür → sorun varsa KALIR } FIKO_TEST(gsd_yuzey_sisir_kucuk_yuzey) { // 5x5 küçük yüzey, küçük yarıçapla şişir → gerçek kubbe (ofset değil). const std::vector kare = {{0, 0, 0}, {5, 0, 0}, {5, 5, 0}, {0, 5, 0}}; const BrepGovde y = yuzeyFill(kare); const BrepGovde k = yuzeySisir(y, {2.5, 2.5, 0}, 4.0, 1.5); FIKO_KONTROL(k.gecerliMi()); FIKO_KONTROL(k.alan() > 25.0); } FIKO_TEST(kenar_dihedral_kutu) { // Kübün TÜM kenarları dışbükey 90° (ordinal uzayı TopExp — paylaşılan kenar çift sayılır). const BrepGovde g = kutu(10, 10, 10); u32 sayi = 0; for (u32 o = 1;; ++o) { KenarBilgi kb; if (!g.kenarBilgi(o, kb)) break; const KenarDihedralBilgi d = g.kenarDihedral(o); FIKO_KONTROL(d.gecerli); FIKO_YAKIN(d.aciDeg, 90.0, 1.0); FIKO_KONTROL(d.disbukey); ++sayi; } FIKO_KONTROL(sayi >= 12); // 12 fiziksel kenar (ordinal çift-sayımıyla daha fazla olabilir) FIKO_KONTROL(!g.kenarDihedral(0).gecerli); // geçersiz ordinal FIKO_KONTROL(!BrepGovde{}.kenarDihedral(1).gecerli); // geçersiz gövde } FIKO_TEST(kenar_dihedral_cep_icbukey) { // Üst yüze 5 derin cep: taban-duvar (+ duvar-duvar dikey) kenarları İÇBÜKEY 90°. const BrepGovde blok = kutu(20, 20, 20); // z ∈ [-10, 10] Donusumd yukari; yukari.konum = {0, 0, 10}; const BrepGovde cep = cikarma(blok, donusumUygula(kutu(10, 10, 10), yukari)); // araç z∈[5,15] FIKO_KONTROL(cep.gecerliMi()); u32 icbukey = 0; for (u32 o = 1;; ++o) { KenarBilgi kb; if (!cep.kenarBilgi(o, kb)) break; const KenarDihedralBilgi d = cep.kenarDihedral(o); if (d.gecerli && !d.disbukey && std::abs(d.aciDeg - 90.0) < 1.0) ++icbukey; } FIKO_KONTROL(icbukey >= 4); // en az cep tabanı çevresi (4 kenar) } FIKO_TEST(kenar_dihedral_silindir) { // Kapak kenarları (çember) dışbükey 90°; dikiş (seam, doğru — iki yanı AYNI yüz) ≈ 0°. const BrepGovde g = silindir(5.0, 10.0); u32 kapak = 0, dikis = 0; for (u32 o = 1;; ++o) { KenarBilgi kb; if (!g.kenarBilgi(o, kb)) break; const KenarDihedralBilgi d = g.kenarDihedral(o); if (!d.gecerli) continue; if (kb.cemberMi) { FIKO_YAKIN(d.aciDeg, 90.0, 1.0); FIKO_KONTROL(d.disbukey); ++kapak; } else if (kb.dogruMu) { FIKO_YAKIN(d.aciDeg, 0.0, 1.0); // teğete-yakın → disbukey işareti önemsiz ++dikis; } } FIKO_KONTROL(kapak >= 2); FIKO_KONTROL(dikis >= 1); } // ---- Spline profil Pad (sketch spline → gercek B-spline kenarli kati) -------- // Kapali profil: ustte 4-noktali spline (0,0)→(10,0), altta donus cizgisi. Prizma // gecerli kati vermeli; hacim düz-üçgen tabanından FARKLI (gerçek eğri kanıtı). FIKO_TEST(spline_profil_pad) { ProfilEgri s; s.tip = ProfilEgri::Tip::Spline; s.p0 = {0, 0, 0}; s.p1 = {10, 0, 0}; s.noktalar = {{0, 0, 0}, {3, 3, 0}, {7, 3, 0}, {10, 0, 0}}; // yukari kabarik ProfilEgri l; l.tip = ProfilEgri::Tip::Cizgi; l.p0 = {10, 0, 0}; l.p1 = {0, 0, 0}; const ProfilKontur kontur{s, l}; const BrepGovde g = prizmaMultiEgri({kontur}, {0, 0, 1}, 5.0, 0.0); FIKO_KONTROL(g.gecerliMi()); const f64 v = g.hacim(); FIKO_KONTROL(v > 1.0); // bos degil // Kabarik spline alani kaba sinirlar: ust ucgen (0,0)-(5,~3.75)-(10,0) alani ~18.75, // dikdortgen 10x3=30. Spline alani ikisinin arasinda → hacim (alan*5) 60..150 bandi. FIKO_KONTROL(v > 60.0 && v < 150.0); } // ---- Kesit: PERF olcumu (tarak govde — kesit gizmo surukleme yolu) ---------- // Surukleme her ~120ms'de brepKesit (profil) + brepKesitKapak (OCCT Common + // remesh) SENKRON kosuyor; sure stdout'a (assert edilmez, makine bagimli). FIKO_TEST(kesit_perf_tarak) { BrepGovde g = kutu(100, 20, 6); for (int i = 0; i < 10; ++i) { Donusumd t; t.konum = {-45.0 + i * 10.0, 0.0, 6.0}; g = birlesim(g, donusumUygula(kutu(4, 20, 6), t)); } FIKO_KONTROL(g.gecerliMi()); const Vec3d pt{0, 0, 3}, n{1, 0, 0}; // dislere dik dusey kesit const auto t0 = std::chrono::steady_clock::now(); const auto egriler = brepKesit(g, pt, n, 0.05); const auto t1 = std::chrono::steady_clock::now(); const auto ucgenler = brepKesitKapak(g, pt, n); const auto t2 = std::chrono::steady_clock::now(); std::printf("[perf] brepKesit: %zu halka, %.1f ms | brepKesitKapak: %zu nokta, %.1f ms\n", egriler.size(), std::chrono::duration(t1 - t0).count(), ucgenler.size(), std::chrono::duration(t2 - t1).count()); FIKO_KONTROL(!egriler.empty()); FIKO_KONTROL(ucgenler.size() >= 3 && ucgenler.size() % 3 == 0); } // ---- Undercut: PERF olcumu (tarak — exact per-yuz isin yolu) ----------------- // Varsayilan parametreler (ornekAdim 0=oto, izgara tavani 24 → ≤576 isin/yuz). FIKO_TEST(undercut_perf_tarak) { BrepGovde g = kutu(100, 20, 6); for (int i = 0; i < 10; ++i) { Donusumd t; t.konum = {-45.0 + i * 10.0, 0.0, 6.0}; g = birlesim(g, donusumUygula(kutu(4, 20, 6), t)); } FIKO_KONTROL(g.gecerliMi()); const auto t0 = std::chrono::steady_clock::now(); const auto rapor = undercutRapor(g, Donusumd{}, {0, 0, 1}, 0.0, 24); const f64 ms = std::chrono::duration( std::chrono::steady_clock::now() - t0).count(); u32 kapali = 0, kismi = 0; for (const auto& u : rapor) { if (u.durum == UndercutDurum::Kapali) ++kapali; else if (u.durum == UndercutDurum::Kismi) ++kismi; } std::printf("[perf] undercutRapor: %zu yuz (%u kapali, %u kismi), %.1f ms\n", rapor.size(), kapali, kismi, ms); FIKO_KONTROL(!rapor.empty()); // Dislerin arasindaki taban seritleri +Z cekiminde ACIK olmali; dis yan // duvarlar dik → durum ne olursa olsun rapor tum yuzleri icermeli. FIKO_KONTROL(rapor.size() >= 60); } // ---- (BUYUK) Gercek .wrl → BREP smoke — yalniz FIKO_BUYUK_TEST env varsa ---- // vrmlOku gercek CATIA VRML'yi TopoDS'e (per-ucgen yuz + yuz→Shape secim grubu + // per-yuz renk + feature kenar) cevirir → STEP gibi per-yuz/kenar secim. 12 MB // Ust_Kalip.wrl repoda DEGIL; gelistirici makinesinde elle kosar. FIKO_TEST(vrml_buyuk_brep_smoke) { if (!std::getenv("FIKO_BUYUK_TEST")) return; KenarVeri kenarlar; std::vector renkler; std::vector yuzShape; // her yuz → ait oldugu Shape (CATIA yuzu / secim grubu) const auto tp0 = std::chrono::steady_clock::now(); BrepGovde g = vrmlOku("D:/__sistem__/Downloads/Test/Ust_Kalip.wrl", &kenarlar, &renkler, &yuzShape); const auto tp1 = std::chrono::steady_clock::now(); FIKO_KONTROL(g.gecerliMi()); // gecerli TopoDS const MeshVeri m = g.ucgenle(Vec3f{0.6f, 0.6f, 0.6f}); const auto tp2 = std::chrono::steady_clock::now(); std::printf("[VRML ZAMAN] vrmlOku=%.0fms ucgenle=%.0fms\n", std::chrono::duration(tp1 - tp0).count(), std::chrono::duration(tp2 - tp1).count()); FIKO_KONTROL(!m.vertexler.empty()); // meshlenebilir // mm OLCEK: CATIA "scale 0.001" notralize (×1000) → model mm (kalip yuzlerce mm; // eskiden metre gelirdi, kosegen ~2-4 idi → STEP/FikoOp mm dunyasiyla uyumsuz). const Vec3f mb = m.sinir.boyut(); FIKO_KONTROL(std::sqrt(mb.x * mb.x + mb.y * mb.y + mb.z * mb.z) > 500.0f); FIKO_KONTROL(!renkler.empty()); // per-yuz renk (diffuseColor) FIKO_KONTROL(kenarlar.kenarSayi > 0); // feature kenarlari (IndexedLineSet) FIKO_KONTROL(!yuzShape.empty()); // secim gruplari mevcut u32 maksShape = 0; for (u32 s : yuzShape) maksShape = std::max(maksShape, s); FIKO_KONTROL(maksShape >= 1); // en az 1 Shape grubu // PERF: yüz sayısı artık Shape sayısı (per-üçgen DEĞİL) → ~4152, on binlerce değil. FIKO_KONTROL(yuzShape.size() < 20000); // eski per-üçgen 156306 idi FIKO_KONTROL(maksShape == yuzShape.size()); // 1 yüz = 1 Shape (1:1) // Mesh-temelli (yüzeysiz) gövde HIZLI YOL regresyonu — asıl kasma/donma buradaydı: // (1) ucgenleKaba yüzeysiz yüzde Copy+BRepMesh yapmamalı (17s→ms; kaba=ince). std::shared_ptr yeniOnb; const MeshVeri kaba = g.ucgenleKaba(Vec3f{0.6f, 0.6f, 0.6f}, nullptr, yeniOnb); FIKO_KONTROL(!kaba.vertexler.empty()); // (2) yuzBilgi: triangulation'dan ANALİTİK TANIMA — hover/ölçüm/benzerYuzler/çipler. // Tüm yüzlerde başarılı olmalı (eskiden segfault → sonra false → şimdi mesh-fit). int ok = 0, duzlem = 0, silindir = 0, kure = 0; const auto tFit0 = std::chrono::steady_clock::now(); for (u32 o = 1; o <= (u32)yuzShape.size(); ++o) { YuzBilgi yb; if (!g.yuzBilgi(o, yb, false)) continue; ++ok; if (yb.duzlemMi) ++duzlem; if (yb.silindirMi) ++silindir; if (yb.kureMi) ++kure; FIKO_KONTROL(yb.alan > 0); // alan her yüzde dolu } const auto tFit1 = std::chrono::steady_clock::now(); FIKO_KONTROL(ok == (int)yuzShape.size()); // hiç yüz bilgisiz kalmadı FIKO_KONTROL(duzlem > 0); // kalıpta düz yüzey kesin var std::printf("[VRML FIT] yuz=%d duzlem=%d silindir=%d kure=%d sure(%zu yuz)=%.0fms\n", ok, duzlem, silindir, kure, yuzShape.size(), std::chrono::duration(tFit1 - tFit0).count()); // (3) benzerYuzler artık çalışır (yuzBilgi üstünden) — en az kendisi döner. FIKO_KONTROL(!g.benzerYuzler(1).empty()); // AKILLI SEÇİM MALİYETİ (her seçimde çip 2-3 aday koşturuyor → main-thread tıkanması). // Silindir bir yüz bul (benzerYuzler orada anlamlı = tüm delikleri tarar). u32 silOrd = 0; for (u32 o = 1; o <= (u32)yuzShape.size() && !silOrd; ++o) { YuzBilgi yb; if (g.yuzBilgi(o, yb, false) && yb.silindirMi) silOrd = o; } if (silOrd) { // 1. çağrı: cache SOĞUK (yuzBilgiOnbellekKur warm eder). 2. çağrı: cache SICAK → çok hızlı. const auto a0 = std::chrono::steady_clock::now(); const auto bz = g.benzerYuzler(silOrd); // soğuk (warm dahil) const auto a1 = std::chrono::steady_clock::now(); const auto bz2 = g.benzerYuzler(silOrd); // sıcak const auto a2 = std::chrono::steady_clock::now(); const double sogukMs = std::chrono::duration(a1 - a0).count(); const double sicakMs = std::chrono::duration(a2 - a1).count(); std::printf("[AKILLI SECIM] benzerYuzler SOGUK=%.1fms SICAK=%.2fms (%zu yüz)\n", sogukMs, sicakMs, bz.size()); FIKO_KONTROL(bz.size() == bz2.size()); // cache tutarlı FIKO_KONTROL(sicakMs < 2.0); // cache SICAK → 10ms değil <1ms } // EDGE akıllı seçim maliyeti (benzerKenarlar = O(kenar) kenarBilgi döngüsü, 10354 kenar). { const auto e0 = std::chrono::steady_clock::now(); const auto bk = g.benzerKenarlar(1); const auto e1 = std::chrono::steady_clock::now(); const auto bk2 = g.benzerKenarlar(1); const auto e2 = std::chrono::steady_clock::now(); std::printf("[EDGE SECIM] benzerKenarlar SOGUK=%.1fms SICAK=%.2fms (%zu kenar → %zu)\n", std::chrono::duration(e1 - e0).count(), std::chrono::duration(e2 - e1).count(), (size_t)kenarlar.kenarSayi, bk.size()); FIKO_KONTROL(bk.size() == bk2.size()); } // (4) BREP kenarları: VRML line-set'leri gerçek TopoDS_Edge (ölçüm/hover) — ordinal // hizası: kenar sayısı görsel grup sayısıyla birebir (sonrası yok). KenarBilgi kb; FIKO_KONTROL(g.kenarBilgi(1, kb)); FIKO_KONTROL(kb.uzunluk > 0); FIKO_KONTROL(g.kenarBilgi(kenarlar.kenarSayi, kb)); FIKO_KONTROL(!g.kenarBilgi(kenarlar.kenarSayi + 1, kb)); } // STEP açma zaman profili — parse(OCCT) vs mesh(BRepMesh) — hızlandırma hedefi. FIKO_TEST(step_buyuk_zaman) { if (!std::getenv("FIKO_BUYUK_TEST")) return; const std::string yol = "D:/__sistem__/Downloads/Test/MLFX.0095-1001(NEW DOKUM).stp"; const auto s0 = std::chrono::steady_clock::now(); std::vector gov = stepYukle(yol); const auto s1 = std::chrono::steady_clock::now(); FIKO_KONTROL(!gov.empty()); std::size_t yuzT = 0, vtx = 0; double meshSeri = 0, meshPar = 0; for (auto& ig : gov) { if (!ig.govde.gecerliMi()) continue; const auto m0 = std::chrono::steady_clock::now(); const MeshVeri m = ig.govde.ucgenle(ig.renk, -1.0, false); // SERİ const auto m1 = std::chrono::steady_clock::now(); const MeshVeri mp = ig.govde.ucgenle(ig.renk, -1.0, true); // PARALEL (import-güvenli) const auto m2 = std::chrono::steady_clock::now(); meshSeri += std::chrono::duration(m1 - m0).count(); meshPar += std::chrono::duration(m2 - m1).count(); vtx += m.vertexler.size(); yuzT += m.yuzSayi; FIKO_KONTROL(mp.vertexler.size() == m.vertexler.size()); // paralel = seri sonuç } std::printf("[STEP ZAMAN] parse+brep=%.0fms mesh-SERI=%.0fms mesh-PARALEL=%.0fms govde=%zu yuz=%zu vtx=%zu\n", std::chrono::duration(s1 - s0).count(), meshSeri, meshPar, gov.size(), yuzT, vtx); FIKO_KONTROL(vtx > 0); } // GECICI TESHIS — kullanicinin "17778_a09013_m01_01.stp acilmiyor" raporu icin. FIKO_BUYUK_TEST // ile kosulur. stepYukle (duz) + stepYukleHiyerarsi (gercek uygulama yolu) ikisini de dener, // Standard_Failure/std::exception yakalar, ne zaman/nerede basarisiz oldugunu yazdirir. // Is bitince SILINECEK. FIKO_TEST(teshis_17778_step_ac) { if (!std::getenv("FIKO_BUYUK_TEST")) return; occtSinyalKur(); const std::string yol = "D:/__sistem__/Masaustu/17778_a09013_m01_01.stp"; std::printf("[TESHIS] dosya: %s\n", yol.c_str()); // 1) Duz stepYukle (XCAF'siz, tek-govde) — hiyerarsi katmanindan bagimsiz taban test. try { const auto t0 = std::chrono::steady_clock::now(); std::vector gov = stepYukle(yol, [](f32 o, std::string_view m) { std::printf("[TESHIS] stepYukle ilerleme: %.0f%% %.*s\n", o * 100.0f, (int)m.size(), m.data()); }); const auto t1 = std::chrono::steady_clock::now(); std::printf("[TESHIS] stepYukle SONUC: govde=%zu sure=%.0fms\n", gov.size(), std::chrono::duration(t1 - t0).count()); for (size_t i = 0; i < gov.size(); ++i) std::printf("[TESHIS] govde[%zu] gecerli=%d\n", i, (int)gov[i].govde.gecerliMi()); } catch (const std::exception& e) { std::printf("[TESHIS] stepYukle ISTISNA: %s\n", e.what()); } catch (...) { std::printf("[TESHIS] stepYukle BILINMEYEN ISTISNA\n"); } // 2) stepYukleHiyerarsi — gercek uygulamanin (dosya_islemleri.cpp) kullandigi yol. try { const auto t0 = std::chrono::steady_clock::now(); auto kokler = stepYukleHiyerarsi(yol, [](f32 o, std::string_view m) { std::printf("[TESHIS] hiyerarsi ilerleme: %.0f%% %.*s\n", o * 100.0f, (int)m.size(), m.data()); }); const auto t1 = std::chrono::steady_clock::now(); std::printf("[TESHIS] stepYukleHiyerarsi SONUC: kok=%zu sure=%.0fms\n", kokler.size(), std::chrono::duration(t1 - t0).count()); FIKO_KONTROL(!kokler.empty()); } catch (const std::exception& e) { std::printf("[TESHIS] stepYukleHiyerarsi ISTISNA: %s\n", e.what()); FIKO_KONTROL(false); } catch (...) { std::printf("[TESHIS] stepYukleHiyerarsi BILINMEYEN ISTISNA\n"); FIKO_KONTROL(false); } } // Mesh-temelli (VRML) gövde BinTools round-trip: yüklenen brep meshlenebilmeli — .fikocad // kaydı/geri yüklemede VRML gövde geometrisinin KAYBOLMAMA regresyonu. NOT: BinTools yüzeysiz // yüzlerin üçgenlemesini triangles=false'ta bile korur (o yüzlerin tek geometrisi odur). FIKO_TEST(vrml_bintools_ucgenli_roundtrip) { if (!std::getenv("FIKO_BUYUK_TEST")) return; BrepGovde g = vrmlOku("D:/__sistem__/Downloads/Test/Ust_Kalip.wrl"); FIKO_KONTROL(g.gecerliMi()); const BrepGovde g2 = govdeBaytOku(govdeBaytYaz(g, /*ucgenli*/ true)); FIKO_KONTROL(g2.gecerliMi()); FIKO_KONTROL(!g2.ucgenle(Vec3f{0.6f, 0.6f, 0.6f}).vertexler.empty()); // üçgenleme korundu } // ---- Blend-koruyan Yüz İt/Çek (Grow: Moving) ------------------------------- namespace { // Üst (+Z) düz yüzün 1-tabanlı ordinali (en yüksek merkezli, normali +Z olan düzlem). u32 ustDuzYuz(const BrepGovde& g) { const int n = topolojiOzeti(g).yuzSayi; u32 enIyi = 0; f64 enYuksek = -1e18; YuzBilgi yb; for (u32 i = 1; i <= (u32)n; ++i) { if (!g.yuzBilgi(i, yb) || !yb.duzlemMi) continue; if (yb.normal.z < 0.9) continue; if (yb.merkez.z > enYuksek) { enYuksek = yb.merkez.z; enIyi = i; } } return enIyi; } // Verilen yarıçapta silindirik/torik (yuvarlak blend) yüz var mı? bool yuvarlakBlendVar(const BrepGovde& g, f64 r, f64 tol) { const int n = topolojiOzeti(g).yuzSayi; YuzBilgi yb; for (u32 i = 1; i <= (u32)n; ++i) { if (!g.yuzBilgi(i, yb)) continue; const f64 rr = yb.torusMu ? yb.kucukYaricap : (yb.silindirMi ? yb.yaricap : 0.0); if (rr > 0 && std::abs(rr - r) <= tol) return true; } return false; } } // namespace FIKO_TEST(blend_korur_itcek_blend_yoksa_duz_yola_duser) { // Sözleşme: teğet yuvarlak blend YOKSA sonuç yuzItCekCoklu ile BİREBİR aynı olmalı // (davranış korunur — yeni yol sessizce farklı geometri üretmemeli). const BrepGovde g = kutu(4, 4, 2); const u32 ust = ustDuzYuz(g); FIKO_KONTROL(ust != 0); const BrepGovde duz = yuzItCekCoklu(g, {ust}, 1.0); const BrepGovde blend = yuzItCekBlendKorur(g, {ust}, 1.0); FIKO_KONTROL(duz.gecerliMi() && blend.gecerliMi()); FIKO_YAKIN(blend.hacim(), duz.hacim(), 1e-9); FIKO_YAKIN(blend.hacim(), 48.0, 1e-6); // 4×4×3 } FIKO_TEST(blend_korur_itcek_fillet_yaricapi_korunur) { // Kutunun BİR üst kenarına r=0.5 fillet → üst yüzü +1 çek. // Blend sökülüp aynı yarıçapla yeniden kurulduğu için: // (a) sonuç geçerli, (b) r=0.5 yuvarlak blend HÂLÂ var, // (c) hacim artışı tam olarak üst yüz alanı × 1 = 16 (fillet kesiği aynı kaldı). const BrepGovde g = kutu(4, 4, 2); // kutu() MERKEZ hizalı: z ∈ [-1, +1] → üst kot +1 const int kn = topolojiOzeti(g).kenarSayi; u32 ustKenar = 0; KenarBilgi kb; for (u32 i = 1; i <= (u32)kn; ++i) { if (!g.kenarBilgi(i, kb) || !kb.dogruMu) continue; if (std::abs(kb.bas.z - 1.0) < 1e-6 && std::abs(kb.son.z - 1.0) < 1e-6) { ustKenar = i; break; } } FIKO_KONTROL(ustKenar != 0); const BrepGovde f = yuvarlat(g, {ustKenar}, 0.5); FIKO_KONTROL(f.gecerliMi()); FIKO_KONTROL(yuvarlakBlendVar(f, 0.5, 1e-6)); const u32 ust = ustDuzYuz(f); FIKO_KONTROL(ust != 0); const BrepGovde son = yuzItCekBlendKorur(f, {ust}, 1.0); FIKO_KONTROL(son.gecerliMi()); FIKO_KONTROL(yuvarlakBlendVar(son, 0.5, 1e-4)); // Hacim artışı TAM 16 (4×4×1): fillet kesiği birebir aynı kaldı — sökülüp aynı R ile kuruldu. FIKO_YAKIN(son.hacim() - f.hacim(), 16.0, 1e-6); // Yüz sayısı DEĞİŞMEZ: fazla kenar yuvarlanırsa burası büyür (regresyon kilidi — blend'in // KESKİN uç komşuları duvar sanılınca 7 yerine 9 çıkıyordu). FIKO_KONTROL(topolojiOzeti(son).yuzSayi == topolojiOzeti(f).yuzSayi); }