#include #include "fiko/sketch/eskiz_veri.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::eskiz; // (a) Trim: yatay cizgi (0,0)->(10,0) ile dikey cizgi (5,-5)->(5,5). // Yatay cizginin sag ucundan (tik ~9) trim → sag uc (5,0) kesisime cekilir. FIKO_TEST(trim_iki_kesisen_cizgi) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); // dikey kesici bool ok = e.trim(yatay, 9.0, 0.0); // sag ucta tikla FIKO_KONTROL(ok); // Sag uc (b) artik (5,0). FIKO_YAKIN(e.noktaX(yatay, 1), 5.0, 1e-6); FIKO_YAKIN(e.noktaY(yatay, 1), 0.0, 1e-6); // Sol uc degismedi. FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); } // (a2) Trim CATIA davranisi: iki kesici arasindaki tiklanan parca SILINIR (uzak // uc noktasi TASINMAZ). Yatay (0,0)->(10,0), kesiciler x=3 ve x=7. Orta (5,0) // tikla → (0,0)-(3,0) korunur + yeni parca (7,0)-(10,0). Uclar (0 ve 10) sabit. FIKO_TEST(trim_orta_parca_silme_katia) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(3.0, -5.0, 3.0, 5.0); e.cizgiEkle(7.0, -5.0, 7.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.trim(yatay, 5.0, 0.0); // orta parcaya tikla FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once + 1); // ikiye bolundu (uc tasinmadi) // Sol uc (0,0) DEGISMEDI — eski hatali davranista buraya cekilirdi. FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 1), 3.0, 1e-6); // sag uc ilk kesisime kisaldi } // (b) Uzat: kisa cizgi (0,0)->(3,0), hedef dikey cizgi x=8. Sag uctan uzat → // sag uc (8,0)'a gider. FIKO_TEST(uzat_hedefe) { EskizVeri e; u32 kisa = e.cizgiEkle(0.0, 0.0, 3.0, 0.0); e.cizgiEkle(8.0, -5.0, 8.0, 5.0); bool ok = e.uzat(kisa, 3.0, 0.0); // sag uc FIKO_KONTROL(ok); FIKO_YAKIN(e.noktaX(kisa, 1), 8.0, 1e-6); FIKO_YAKIN(e.noktaY(kisa, 1), 0.0, 1e-6); } // (c) Bol: cizgi (0,0)->(10,0) noktada (4,0) ikiye. Orijinal -> (0,0)-(4,0), // yeni -> (4,0)-(10,0). FIKO_TEST(bol_cizgi) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 yeni = e.bol(c, 4.0, 0.0); FIKO_KONTROL(yeni != 0); FIKO_YAKIN(e.noktaX(c, 1), 4.0, 1e-6); // orijinal kisaldi FIKO_YAKIN(e.noktaX(yeni, 0), 4.0, 1e-6); // yeni baslangic FIKO_YAKIN(e.noktaX(yeni, 1), 10.0, 1e-6); // yeni bitis } // (d) Kose yuvarlatma: iki dik cizgi. Yatay (0,0)->(10,0), Dikey (0,0)->(0,10). // r=2 fillet → teget yay + cizgiler (2,0) ve (0,2)'ye kisalir. FIKO_TEST(kose_yuvarlat_dik) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 dikey = e.cizgiEkle(0.0, 0.0, 0.0, 10.0); u32 yay = e.koseYuvarlat(yatay, dikey, 2.0); FIKO_KONTROL(yay != 0); const Geometri* gy = e.geoBul(yay); FIKO_KONTROL(gy && gy->tip == GeoTip::Yay); // Yay merkezi (2,2), yaricap 2. FIKO_YAKIN(e.px(gy->merkez.ix), 2.0, 1e-6); FIKO_YAKIN(e.px(gy->merkez.iy), 2.0, 1e-6); FIKO_YAKIN(e.px(gy->ir), 2.0, 1e-6); // Yatay cizginin kose ucu (2,0)'a kisaldi. FIKO_YAKIN(e.noktaX(yatay, 0), 2.0, 1e-6); FIKO_YAKIN(e.noktaY(yatay, 0), 0.0, 1e-6); // Dikey cizginin kose ucu (0,2)'ye kisaldi. FIKO_YAKIN(e.noktaX(dikey, 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaY(dikey, 0), 2.0, 1e-6); } // (d1b) KISITLI köşe fillet + coz(): dikdörtgen/üçgen köşesi Cakisik + H/V kısıtlı. // Bug: fillet uçları teğet noktasına taşıyınca coz() çakışıklığı geri dayatıp geometriyi // köşeye çeker → kaydırma + trim yok. koseCakisikKaldir çakışıklığı silmeli → trim kalıcı. FIKO_TEST(kose_yuvarlat_kisitli_trim) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 dikey = e.cizgiEkle(10.0, 0.0, 10.0, 10.0); e.kisitEkle(KisitTip::Cakisik, {yatay, dikey}, {1, 0}, 0); // köşe (10,0) e.kisitEkle(KisitTip::Yatay, {yatay}, {}, 0); e.kisitEkle(KisitTip::Dikey, {dikey}, {}, 0); e.coz(); u32 yay = e.koseYuvarlat(yatay, dikey, 2.0); e.coz(); FIKO_KONTROL(yay != 0); // Yatay çizginin köşe ucu (nokta 1) (8,0)'a kısaldı — coz() geri çekMEMELİ. FIKO_YAKIN(e.noktaX(yatay, 1), 8.0, 1e-4); FIKO_YAKIN(e.noktaY(yatay, 1), 0.0, 1e-4); // Dikey çizginin köşe ucu (nokta 0) (10,2)'ye kısaldı. FIKO_YAKIN(e.noktaX(dikey, 0), 10.0, 1e-4); FIKO_YAKIN(e.noktaY(dikey, 0), 2.0, 1e-4); } // (d1c) ÜÇGEN (3 çizgi, ters çizim sırası) fillet: çakışıklık geo sırası {L2,L1} olabilir. // koseCakisikKaldir iki yönlü eşleşmeli. pah için de aynı guard. FIKO_TEST(pah_ucgen_kisitli_trim) { EskizVeri e; // Üçgen: taban + sağ kenar + hipotenüs, köşede coincidence (çizim sırası L2 sonra L1). u32 taban = e.cizgiEkle(0.0, 0.0, 12.0, 0.0); u32 sag = e.cizgiEkle(12.0, 0.0, 6.0, 9.0); u32 hip = e.cizgiEkle(6.0, 9.0, 0.0, 0.0); // Çakışıklık geo sırası TERS: {sag, taban} — koseCakisikKaldir'in iki-yönlü eşleşmesini test eder. e.kisitEkle(KisitTip::Cakisik, {sag, taban}, {0, 1}, 0); // köşe (12,0) e.kisitEkle(KisitTip::Cakisik, {hip, sag}, {0, 1}, 0); e.kisitEkle(KisitTip::Cakisik, {hip, taban}, {1, 0}, 0); e.kisitEkle(KisitTip::Yatay, {taban}, {}, 0); e.coz(); u32 pc = e.pah(taban, sag, 2.0); e.coz(); FIKO_KONTROL(pc != 0); // Taban köşe ucu (nokta 1) köşeden (12,0) uzaklaşmalı (x < 11). FIKO_KONTROL(e.noktaX(taban, 1) < 11.0); // Sağ kenar köşe ucu (nokta 0) köşeden uzaklaşmalı (12,0)'dan. FIKO_KONTROL(std::hypot(e.noktaX(sag, 0) - 12.0, e.noktaY(sag, 0) - 0.0) > 0.5); } // (d1d) UZUNLUK kısıtlı köşe fillet: çizgide Mesafe(uzunluk) kısıtı varken fillet // kısaltırsa coz() uzunluğu geri getirip çizgiyi KAYDIRIR. Fillet bu ölçüyü kaldırmalı. FIKO_TEST(kose_yuvarlat_uzunluk_kisitli) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 dikey = e.cizgiEkle(10.0, 0.0, 10.0, 10.0); e.kisitEkle(KisitTip::Cakisik, {yatay, dikey}, {1, 0}, 0); e.kisitEkle(KisitTip::Yatay, {yatay}, {}, 0); e.kisitEkle(KisitTip::Dikey, {dikey}, {}, 0); e.kisitEkle(KisitTip::Mesafe, {yatay}, 10.0); // yatay uzunluk = 10 (fillet ile çelişir) e.coz(); u32 yay = e.koseYuvarlat(yatay, dikey, 2.0); e.coz(); FIKO_KONTROL(yay != 0); // Yatay çizgi (8,0)'a kısalmalı — Mesafe kısıtı çekMEMELİ (fillet ölçüyü kaldırır). FIKO_YAKIN(e.noktaX(yatay, 1), 8.0, 1e-3); FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-3); // diğer uç kaymamalı } // (d2) Genis (obtuse) kose fillet: ham atan2 farki reflex/negatif olabilir. Fix minor yay // (span in (0,pi), CCW) garanti eder → render (lineer a1->a2) ile BRep (CCW zorlar) tutarli. // Regresyon: fix'siz span negatif (a2-a1=-pi/4) → BRep 315 derece reflex yay → yanlis kati. FIKO_TEST(kose_yuvarlat_genis_aci_minor_yay) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 egik = e.cizgiEkle(0.0, 0.0, -10.0, 10.0); // 135 derece → obtuse kose u32 yay = e.koseYuvarlat(yatay, egik, 1.0); FIKO_KONTROL(yay != 0); const Geometri* gy = e.geoBul(yay); FIKO_KONTROL(gy && gy->tip == GeoTip::Yay); const double a1 = e.px(gy->ib1), a2 = e.px(gy->ib2); const double span = a2 - a1; FIKO_KONTROL(span > 0.0 && span < 3.141592653589793); // minor + CCW (reflex/negatif DEGIL) } // (e) Pah: iki dik cizgi + mesafe 2 → pah cizgisi (2,0)-(0,2). FIKO_TEST(pah_dik) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 dikey = e.cizgiEkle(0.0, 0.0, 0.0, 10.0); u32 pc = e.pah(yatay, dikey, 2.0); FIKO_KONTROL(pc != 0); // Pah cizgisi uclarindan biri (2,0), digeri (0,2). Skalar ax = e.noktaX(pc, 0), ay = e.noktaY(pc, 0); Skalar bx = e.noktaX(pc, 1), by = e.noktaY(pc, 1); bool dogru = (std::abs(ax - 2) < 1e-6 && std::abs(ay) < 1e-6 && std::abs(bx) < 1e-6 && std::abs(by - 2) < 1e-6); FIKO_KONTROL(dogru); } // (f) Aynala: cizgi (1,1)->(3,1), eksen dikey cizgi x=0 (0,-5)->(0,5). // Yansima → (-1,1)->(-3,1). FIKO_TEST(aynala_dikey_eksen) { EskizVeri e; u32 c = e.cizgiEkle(1.0, 1.0, 3.0, 1.0); u32 eksen = e.cizgiEkle(0.0, -5.0, 0.0, 5.0); auto yeni = e.aynala({c}, eksen); FIKO_KONTROL(yeni.size() == 1); FIKO_YAKIN(e.noktaX(yeni[0], 0), -1.0, 1e-6); FIKO_YAKIN(e.noktaY(yeni[0], 0), 1.0, 1e-6); FIKO_YAKIN(e.noktaX(yeni[0], 1), -3.0, 1e-6); FIKO_YAKIN(e.noktaY(yeni[0], 1), 1.0, 1e-6); } // (g) Ötele (tasi): cizgi (0,0)->(2,0), dx=5 dy=3 taşı (kopya=0). FIKO_TEST(otele_tasi) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 2.0, 0.0); auto yeni = e.otele({c}, 5.0, 3.0, 0); FIKO_KONTROL(yeni.empty()); // tasima → yeni kimlik yok FIKO_YAKIN(e.noktaX(c, 0), 5.0, 1e-6); FIKO_YAKIN(e.noktaY(c, 0), 3.0, 1e-6); FIKO_YAKIN(e.noktaX(c, 1), 7.0, 1e-6); } // (h) Ötele (kopya): 2 kopya → 2 yeni geometri, konumlar dogru. FIKO_TEST(otele_kopya) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 1.0, 0.0); auto yeni = e.otele({c}, 3.0, 0.0, 2); FIKO_KONTROL(yeni.size() == 2); FIKO_YAKIN(e.noktaX(yeni[0], 0), 3.0, 1e-6); FIKO_YAKIN(e.noktaX(yeni[1], 0), 6.0, 1e-6); // Orijinal degismedi. FIKO_YAKIN(e.noktaX(c, 0), 0.0, 1e-6); } // (i) Döndür (tasi): nokta cizgisi (1,0)->(2,0) merkez (0,0) 90 derece. // (1,0)->(0,1), (2,0)->(0,2). FIKO_TEST(dondur_90) { EskizVeri e; u32 c = e.cizgiEkle(1.0, 0.0, 2.0, 0.0); e.dondur({c}, 0.0, 0.0, 3.14159265358979323846 / 2.0, 0); FIKO_YAKIN(e.noktaX(c, 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaY(c, 0), 1.0, 1e-6); FIKO_YAKIN(e.noktaX(c, 1), 0.0, 1e-6); FIKO_YAKIN(e.noktaY(c, 1), 2.0, 1e-6); } // (j) Ölçekle (tasi): cizgi (2,0)->(4,0), ref (0,0), oran 2 → (4,0)->(8,0). FIKO_TEST(olcekle_tasi) { EskizVeri e; u32 c = e.cizgiEkle(2.0, 0.0, 4.0, 0.0); e.olcekle({c}, 0.0, 0.0, 2.0, 0); FIKO_YAKIN(e.noktaX(c, 0), 4.0, 1e-6); FIKO_YAKIN(e.noktaX(c, 1), 8.0, 1e-6); } // (k) Ofset: yatay cizgi (0,0)->(10,0), mesafe 2 → sol normal (+y) paralel. // Yeni cizgi y=2. FIKO_TEST(ofset_cizgi) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); auto yeni = e.ofsetle({c}, 2.0, false); FIKO_KONTROL(yeni.size() == 1); FIKO_YAKIN(e.noktaY(yeni[0], 0), 2.0, 1e-6); FIKO_YAKIN(e.noktaY(yeni[0], 1), 2.0, 1e-6); FIKO_YAKIN(e.noktaX(yeni[0], 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaX(yeni[0], 1), 10.0, 1e-6); } // (l) Ofset daire: yaricap +mesafe. FIKO_TEST(ofset_daire) { EskizVeri e; u32 d = e.daireEkle(0.0, 0.0, 5.0); auto yeni = e.ofsetle({d}, 2.0, false); FIKO_KONTROL(yeni.size() == 1); const Geometri* g = e.geoBul(yeni[0]); FIKO_KONTROL(g && g->tip == GeoTip::Daire); FIKO_YAKIN(e.px(g->ir), 7.0, 1e-6); } // (l2) Ofset cift taraf (Both Side): yatay cizgi, mesafe 2 → y=+2 VE y=-2 // iki kopya (once +, sonra -). FIKO_TEST(ofset_cift_taraf) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); auto yeni = e.ofsetle({c}, 2.0, true); FIKO_KONTROL(yeni.size() == 2); FIKO_YAKIN(e.noktaY(yeni[0], 0), 2.0, 1e-6); FIKO_YAKIN(e.noktaY(yeni[1], 0), -2.0, 1e-6); } // (l3) Zincir komsulugu — nokta yayilimi: U-sekli 3 cizgi (dik koseler, // uc-uca). Nokta yayilimi (tegetSart=false) ilk cizgiden GECISLI 2 komsu // bulur; teget sartla (dik kose → teget kirik) hicbirini bulmaz. FIKO_TEST(zincir_komsu_nokta_ve_teget) { EskizVeri e; u32 c1 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(10.0, 0.0, 10.0, 10.0); e.cizgiEkle(10.0, 10.0, 0.0, 10.0); FIKO_KONTROL(e.zincirKomsulari(c1, false).size() == 2); FIKO_KONTROL(e.zincirKomsulari(c1, true).empty()); } // (l4) Zincir komsulugu — teget yayilim: cizgi (0,0)->(10,0) + ucunda TEGET // yay (merkez (10,5), r=5, aci -pi/2..0 → (10,0)'da baslar, tegeti (1,0)). // Teget sartla da bulunur. FIKO_TEST(zincir_komsu_teget_yay) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 y = e.yayEkle(10.0, 5.0, 5.0, -3.14159265358979323846 / 2.0, 0.0); auto z = e.zincirKomsulari(c, true); FIKO_KONTROL(z.size() == 1 && z[0] == y); } // (m) Kapat: trimlenmis yay → tam cember (bitis = baslangic + 2pi). FIKO_TEST(kapat_yay) { EskizVeri e; u32 y = e.yayEkle(0.0, 0.0, 3.0, 0.0, 3.14159265358979323846 / 2.0); bool ok = e.kapat(y); FIKO_KONTROL(ok); const Geometri* g = e.geoBul(y); Skalar span = e.px(g->ib2) - e.px(g->ib1); FIKO_YAKIN(span, 2.0 * 3.14159265358979323846, 1e-6); } // (o) Hizli Kirp - orta parca: yatay cizgi (0,0)->(10,0), iki dikey kesici // x=3 ve x=7. Ortadaki parcaya (5,0) tikla → orta silinir, 2 parcaya boler. // Orijinal (0,0)-(3,0), yeni (7,0)-(10,0). FIKO_TEST(hizli_kirp_orta_parca) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(3.0, -5.0, 3.0, 5.0); // sol kesici e.cizgiEkle(7.0, -5.0, 7.0, 5.0); // sag kesici std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 5.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once + 1); // yeni parca eklendi // Orijinal artik (0,0)-(3,0). FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 1), 3.0, 1e-6); } // (p) Hizli Kirp - tek kesisim (kisalma): yatay (0,0)->(10,0), tek kesici x=5. // Sag parcaya (8,0) tikla → sag uc (5,0)'a kisalir. FIKO_TEST(hizli_kirp_tek_kesisim) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 8.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // yeni parca yok, sadece kisaldi FIKO_YAKIN(e.noktaX(yatay, 1), 5.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); } // (q) Hizli Kirp - kesisimsiz (tam silme): tek cizgi, kesici yok → silinir. FIKO_TEST(hizli_kirp_tam_silme) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(c, 5.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once - 1); // geometri silindi FIKO_KONTROL(e.geoBul(c) == nullptr); } // (r) Hizli Kirp - yay orta parca: yarim cember yay merkez (0,0) r=5, // 0..pi. Iki dikey kesici x=-3 ve x=3 yayla kesisir. Tepe (0,5) tikla → // orta silinir, yeni yay parcasi eklenir. FIKO_TEST(hizli_kirp_yay_orta) { EskizVeri e; const Skalar pi = 3.14159265358979323846; u32 y = e.yayEkle(0.0, 0.0, 5.0, 0.0, pi); e.cizgiEkle(3.0, 0.0, 3.0, 6.0); // sag kesici (x=3, y=4'te keser) e.cizgiEkle(-3.0, 0.0, -3.0, 6.0); // sol kesici (x=-3, y=4'te keser) std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(y, 0.0, 5.0); // tepe noktasi FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once + 1); // yeni yay parcasi } // ================= KUSUR 1: trim/böl sonrası kısıt yaşam döngüsü ================= // (s) Böl → uzak uçtaki (b) kısıt YENİ parçaya remap edilir. L1 (0,0)->(10,0), // L2 (10,0)->(10,5). L1.b(1) ile L2.a(0) Cakisik. L1'i (5,0)'da böl → L1 kısalır // (b artık 5,0), yeni parça (5,0)->(10,0) B'yi devralır. Cakisik kısıt L1 yerine // yeni parçayı hedeflemeli; çöz → yeni parçanın b'si (10,0)'da KALIR (geri // çekilmez), L1'in yeni b'si (5,0) serbesttir (bağ yok). FIKO_TEST(bol_uzak_uc_kisit_remap) { EskizVeri e; u32 l1 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 l2 = e.cizgiEkle(10.0, 0.0, 10.0, 5.0); e.kisitEkle(KisitTip::Cakisik, {l1, l2}, {1, 0}, 0); // L1.b ↔ L2.a e.coz(); u32 yeni = e.bol(l1, 5.0, 0.0); FIKO_KONTROL(yeni != 0); e.coz(); // L1 kısaldı: b ucu (5,0)'da (kesim). Uzak uç kısıtı L1'de DEĞİL → geri // çekilmez. FIKO_YAKIN(e.noktaX(l1, 1), 5.0, 1e-6); FIKO_YAKIN(e.noktaY(l1, 1), 0.0, 1e-6); // Yeni parça B'yi devraldı ve Cakisik onu L2.a'ya bağlıyor → (10,0)'da kalır. FIKO_YAKIN(e.noktaX(yeni, 1), 10.0, 1e-6); FIKO_YAKIN(e.noktaY(yeni, 1), 0.0, 1e-6); // Kısıt hâlâ 1 tane ama artık 'yeni'yi hedefliyor (l1 değil). FIKO_KONTROL(e.kisitSayisi() == 1); bool remap = false; for (const Kisit& k : e.kisitlar()) if (k.tip == KisitTip::Cakisik) { FIKO_KONTROL(k.geo.size() == 2); remap = (k.geo[0] == yeni || k.geo[1] == yeni); } FIKO_KONTROL(remap); } // (t) Trim ile serbest uç kesişime çekilince, o uçtaki Cakisik SİLİNİR (kesilen // bağlantı geri yapışmasın). L1 (0,0)->(10,0), kesici L2 (5,-5)->(5,5). L1.b(1) // başka bir noktaya (P) Cakisik. Sağ parçaya (8,0) tıkla → b (5,0)'a çekilir, // b'deki Cakisik temizlenir → çözünce b (5,0)'da KALIR (P'ye geri gitmez). FIKO_TEST(trim_serbest_uc_kisit_temizlenir) { EskizVeri e; u32 l1 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); // kesici u32 nk = e.noktaEkle(10.0, 3.0); // L1.b'nin eski bağı e.kisitEkle(KisitTip::Cakisik, {l1, nk}, {1, 0}, 0); std::size_t kOnce = e.kisitSayisi(); bool ok = e.hizliKirp(l1, 8.0, 0.0); // sağ parça → b (5,0)'a kısal FIKO_KONTROL(ok); FIKO_KONTROL(e.kisitSayisi() == kOnce - 1); // b'deki Cakisik silindi e.coz(); FIKO_YAKIN(e.noktaX(l1, 1), 5.0, 1e-6); // b (5,0)'da kaldı, geri yapışmadı FIKO_YAKIN(e.noktaY(l1, 1), 0.0, 1e-6); } // (u) Trim ile KORUNAN uçtaki tam-geo boyut kısıtı (Yatay) silinmez: L1 // (0,0)->(10,0) Yatay kısıtlı, kesici x=5. Sağ parçayı kırp → Yatay kalır. FIKO_TEST(trim_tumgeo_kisit_korunur) { EskizVeri e; u32 l1 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); e.kisitEkle(KisitTip::Yatay, {l1}); // nokta[] yok → tüm-geo std::size_t kOnce = e.kisitSayisi(); bool ok = e.hizliKirp(l1, 8.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.kisitSayisi() == kOnce); // Yatay korundu bool yatayVar = false; for (const Kisit& k : e.kisitlar()) if (k.tip == KisitTip::Yatay && !k.geo.empty() && k.geo[0] == l1) yatayVar = true; FIKO_KONTROL(yatayVar); } // ================= KESISIM REGRESYON: cakisma/ortusme noktalari ================= // (v) TAM KESISIME tikla: yatay (0,0)->(10,0), kesici x=5. Kesisim noktasinin // TAM uzerine (5,0) tikla → eskiden sifir-uzunluk parca (bozuk bolme) olusurdu. // Simdi komsu dolu araliga (sag: 5..10) kayar → sag uc kirpilir, geo SAYISI ayni. FIKO_TEST(hizli_kirp_tam_kesisime_tik) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 5.0, 0.0); // kesisim noktasinin tam uzeri FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // bozuk bolme YOK (sifir-boya cokme yok) // Sag araliga kayti → A ucu 5'e cekildi, B (10) sabit VEYA tersi; ikisinden biri // 5'te olmali ve cizgi hala saglam (uc-uca ayni degil). Skalar x0 = e.noktaX(yatay, 0), x1 = e.noktaX(yatay, 1); bool saglam = (std::abs(x0 - 5.0) < 1e-6 && std::abs(x1 - 10.0) < 1e-6) || (std::abs(x0 - 0.0) < 1e-6 && std::abs(x1 - 5.0) < 1e-6); FIKO_KONTROL(saglam); } // (w) COKLU kesisim dogru araligi: yatay (0,0)->(10,0), kesiciler x=2,5,8. // (6.5,0) tikla (5 ile 8 arasi) → orta parca (5..8) silinir, ikiye boler. // Orijinal (0,0)-(5,0), yeni (8,0)-(10,0). FIKO_TEST(hizli_kirp_coklu_kesisim_dogru_aralik) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(2.0, -5.0, 2.0, 5.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); e.cizgiEkle(8.0, -5.0, 8.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 6.5, 0.0); // 5 ile 8 arasi parca FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once + 1); // ikiye bolundu FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 1), 5.0, 1e-6); // sag uc 5'e (orta parca alt siniri) } // (x) COKLU kesici AYNI noktada (cakisik/ust uste): yatay (0,0)->(10,0), iki // kesici de x=5'ten gecer (birebir ust uste). (8,0) tikla → tek kesisim gibi // davranmali (sag uc 5'e kisalir), ikiye bolme YOK. FIKO_TEST(hizli_kirp_cakisik_kesici) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(5.0, -5.0, 5.0, 5.0); // kesici 1 e.cizgiEkle(5.0, -3.0, 5.0, 8.0); // kesici 2 AYNI x=5 (cakisik kesisim) std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 8.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // cakisik kesisim tekillendi → bolme yok FIKO_YAKIN(e.noktaX(yatay, 1), 5.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); } // (y) TEGET cember gercek kesisim degil: yatay (0,0)->(10,0), cember merkez // (5,2) r=2 → cizgiye (5,0)'da TEGET (tek dokunma). Teget bolme/kirpma // yapMAMALI → tik (8,0) tum cizgiyi siler (kesisim yok gibi). FIKO_TEST(hizli_kirp_teget_cember_kesmez) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.daireEkle(5.0, 2.0, 2.0); // (5,0)'da teget std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 8.0, 0.0); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once - 1); // teget kesisim saymaz → tum cizgi silindi FIKO_KONTROL(e.geoBul(yatay) == nullptr); } // (z) YAY tam kesisime tik: yarim yay merkez (0,0) r=5, 0..pi. Kesici x=3 // (y=4'te keser). Kesisim aci ~atan2(4,3). O acinin tam uzerine tikla → // sifir-boya cokme YOK, komsu araliga kayar (geo sayisi degismez, kirpma olur). FIKO_TEST(hizli_kirp_yay_kesisime_tik) { EskizVeri e; const Skalar pi = 3.14159265358979323846; u32 y = e.yayEkle(0.0, 0.0, 5.0, 0.0, pi); e.cizgiEkle(3.0, 0.0, 3.0, 6.0); // (3,4)'te keser std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(y, 3.0, 4.0); // kesisim noktasinin tam uzeri FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // bozuk bolme yok } // (daire trim) Cember r=5 @origin, iki dikey kesici x=±3 (y=±4'te keser). Tepeye // (0,5) tikla → ust dilim [53°,127°] cikar, daire YERINDE yaya doner (sayi ayni, // kalan yay ~ 2pi - 1.287 = 4.996 rad). FIKO_TEST(hizli_kirp_daire_yaya_doner) { EskizVeri e; const Skalar pi = 3.14159265358979323846; u32 d = e.daireEkle(0.0, 0.0, 5.0); e.cizgiEkle(3.0, -6.0, 3.0, 6.0); e.cizgiEkle(-3.0, -6.0, -3.0, 6.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(d, 0.0, 5.0); // ust dilime tikla FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // yerinde donusum → yeni geo yok const Geometri* g = e.geoBul(d); FIKO_KONTROL(g && g->tip == GeoTip::Yay); Skalar span = e.px(g->ib2) - e.px(g->ib1); FIKO_KONTROL(std::abs(span - (2 * pi - 1.287)) < 0.01); } // (yay∩daire) Üst yarım yay (r5) bir daireyle (r3 @0,5) 55°/125°'de kesişir. Tepeye // (0,5 → 90°) tıkla → orta dilim çıkar, yay ikiye bölünür (silinmez, sayi+1). FIKO_TEST(hizli_kirp_yay_daire_kesisim) { EskizVeri e; const Skalar pi = 3.14159265358979323846; u32 y = e.yayEkle(0.0, 0.0, 5.0, 0.0, pi); e.daireEkle(0.0, 5.0, 3.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(y, 0.0, 5.0); // 90° tepe (orta dilim) FIKO_KONTROL(ok); FIKO_KONTROL(e.geoBul(y) != nullptr); // yay silinmedi FIKO_KONTROL(e.geoSayisi() == once + 1); // ikiye bölündü } // ================= QUICK TRIM MODLARI (Rubber Out / Keep) + TUMLEYEN ================= // (aa) DisSil (Break and Rubber Out): yatay (0,0)->(10,0), kesiciler x=3 ve x=7. // Ortaya (5,0) DisSil tikla → tiklanan parca KALIR, dis parcalar silinir: // cizgi (3,0)-(7,0) olur, geo sayisi degismez. FIKO_TEST(hizli_kirp_dis_sil) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(3.0, -5.0, 3.0, 5.0); e.cizgiEkle(7.0, -5.0, 7.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 5.0, 0.0, KirpMod::DisSil); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once); // bolme/silme yok, iki uc kisaldi FIKO_YAKIN(e.noktaX(yatay, 0), 3.0, 1e-6); FIKO_YAKIN(e.noktaX(yatay, 1), 7.0, 1e-6); } // (ab) DisSil kesisimsiz: degisiklik yok → false (tum parca zaten tiklanan). FIKO_TEST(hizli_kirp_dis_sil_kesisimsiz) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); FIKO_KONTROL(!e.hizliKirp(c, 5.0, 0.0, KirpMod::DisSil)); FIKO_KONTROL(e.geoBul(c) != nullptr); // silinmedi } // (ac) Tut (Break and Keep): yatay (0,0)->(10,0), kesiciler x=3 ve x=7 → // 3 parcaya bolunur (0-3, 3-7, 7-10), hicbiri silinmez (geo +2). FIKO_TEST(hizli_kirp_tut_bol) { EskizVeri e; u32 yatay = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.cizgiEkle(3.0, -5.0, 3.0, 5.0); e.cizgiEkle(7.0, -5.0, 7.0, 5.0); std::size_t once = e.geoSayisi(); bool ok = e.hizliKirp(yatay, 5.0, 0.0, KirpMod::Tut); FIKO_KONTROL(ok); FIKO_KONTROL(e.geoSayisi() == once + 2); // 2 yeni parca FIKO_YAKIN(e.noktaX(yatay, 0), 0.0, 1e-6); // orijinal ilk dilim FIKO_YAKIN(e.noktaX(yatay, 1), 3.0, 1e-6); } // (ad) Tumleyen: yay 0..pi/2 r=3 → tumleyen pi/2..2pi (span 3pi/2). Uc noktalar // AYNI iki konumda kalir (takas): a=(0,3), b=(3,0). FIKO_TEST(tumleyen_yay) { EskizVeri e; const Skalar pi = 3.14159265358979323846; u32 y = e.yayEkle(0.0, 0.0, 3.0, 0.0, pi / 2.0); FIKO_KONTROL(e.tumleyen(y) == y); const Geometri* g = e.geoBul(y); FIKO_YAKIN(e.px(g->ib2) - e.px(g->ib1), 1.5 * pi, 1e-6); // tumleyen span FIKO_YAKIN(e.noktaX(y, 0), 0.0, 1e-6); // a: aci pi/2 → (0,3) FIKO_YAKIN(e.noktaY(y, 0), 3.0, 1e-6); FIKO_YAKIN(e.noktaX(y, 1), 3.0, 1e-6); // b: aci 2pi → (3,0) FIKO_YAKIN(e.noktaY(y, 1), 0.0, 1e-6); } // (ae) Tumleyen yalniz Yay: daire ve cizgi → 0 (basarisiz). FIKO_TEST(tumleyen_yalniz_yay) { EskizVeri e; u32 d = e.daireEkle(0.0, 0.0, 5.0); u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); FIKO_KONTROL(e.tumleyen(d) == 0); FIKO_KONTROL(e.tumleyen(c) == 0); } // (n) kisitSuruAyarla: driving/reference toggle. FIKO_TEST(kisit_suru_ayarla) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 k = e.kisitEkle(KisitTip::Mesafe, {c}, 10.0); e.kisitSuruAyarla(k, false); bool bulundu = false; for (const auto& kk : e.kisitlar()) if (kk.kimlik == k) { FIKO_KONTROL(!kk.suru); bulundu = true; } FIKO_KONTROL(bulundu); }