#include #include #include #include #include "fiko/sketch/eskiz_veri.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::eskiz; // Midpoint (CATIA): nokta, cizginin ORTA noktasinda tutulur. NOT: EskizVeri::coz // Sabit kisitini sabitParam'a CEVIRMEZ (app katmani isi) → mutlak konum degil // ILISKI dogrulanir: coz sonrasi pt == (a+b)/2, tasima sonrasi da korunur. FIKO_TEST(midpoint_kisiti) { EskizVeri e; const u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 4.0); const u32 n = e.noktaEkle(2.0, 9.0); // kasitli uzak baslangic e.kisitEkle(KisitTip::Midpoint, {n, c}, {0, 0}, 0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); const auto orta = [&](u32 cz, int eks) { return 0.5 * (eks == 0 ? e.noktaX(cz, 0) + e.noktaX(cz, 1) : e.noktaY(cz, 0) + e.noktaY(cz, 1)); }; FIKO_YAKIN(e.noktaX(n, 0), orta(c, 0), 1e-6); FIKO_YAKIN(e.noktaY(n, 0), orta(c, 1), 1e-6); // Cizgiyi tasi + yeniden coz → iliski KORUNUR (kisit kalici). e.otele({c}, 4.0, -2.0, 0); Solver::Sonuc s2 = e.coz(); FIKO_KONTROL(s2.kalanNorm < 1e-6); FIKO_YAKIN(e.noktaX(n, 0), orta(c, 0), 1e-6); FIKO_YAKIN(e.noktaY(n, 0), orta(c, 1), 1e-6); } // Pivotsuz sutun raporu (serbestParamlar) + geoTamKisitliMi yaklasimi: // pivotsuz sayisi HER ZAMAN dof'a esittir; kisitsiz eskizde tum paramlar serbesttir. FIKO_TEST(serbest_param_raporu) { EskizVeri e; const u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.3); Solver::Sonuc s0 = e.coz(); // kisit yok → tum 4 param serbest FIKO_KONTROL(s0.dof == 4 && (int)s0.serbestParamlar.size() == 4); FIKO_KONTROL(!e.geoTamKisitliMi(c)); e.kisitEkle(KisitTip::Yatay, {c}); e.kisitEkle(KisitTip::Mesafe, {c}, 10.0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.dof == 2); FIKO_KONTROL((int)s.serbestParamlar.size() == s.dof); // degismez: pivotsuz = dof for (int ix : s.serbestParamlar) FIKO_KONTROL(ix >= 0 && ix < 4); FIKO_KONTROL(!e.geoTamKisitliMi(c)); // oteleme serbestligi kaldi FIKO_KONTROL(!e.geoTamKisitliMi(999)); // olmayan geo guvenli (false) } // Yay/spline UCU Cakisik kisiti: uclar a/b'de gercek solver noktalari → Cakisik // noktaSec ile cozulur. App oto-cakisik'in yay/spline uclarini dahil etmesinin // (sketcher.oto_cakisik_yay_uc) motor guvencesi. FIKO_TEST(cakisik_yay_ucu) { EskizVeri e; const u32 y = e.yayEkle(0.0, 0.0, 10.0, 0.0, 1.5707963268); // (10,0) → (0,10) const u32 c = e.cizgiEkle(0.4, 10.5, 20.0, 20.0); // ucu yay bitisine yakin e.kisitEkle(KisitTip::Cakisik, {y, c}, {1, 0}, 0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); FIKO_YAKIN(e.noktaX(y, 1), e.noktaX(c, 0), 1e-6); FIKO_YAKIN(e.noktaY(y, 1), e.noktaY(c, 0), 1e-6); // Spline ucu da ayni semayla baglanir (uclar a/b'de aynali). const u32 sp = e.splineEkle({{20.2, 19.6}, {30.0, 25.0}, {40.0, 22.0}}); e.kisitEkle(KisitTip::Cakisik, {c, sp}, {1, 0}, 0); Solver::Sonuc s2 = e.coz(); FIKO_KONTROL(s2.kalanNorm < 1e-6); FIKO_YAKIN(e.noktaX(c, 1), e.noktaX(sp, 0), 1e-6); FIKO_YAKIN(e.noktaY(c, 1), e.noktaY(sp, 0), 1e-6); } // PERF olcumu: buyuk eskizde coz() + surukle() suresi (analitik Jacobian karari // icin veri — sonlu-fark m*nf cift artiklar cagrisi yapar). Sure assert edilmez. FIKO_TEST(solver_perf_buyuk_eskiz) { EskizVeri e; // 60 huceli kapali zincir olusturan dikdortgen izgara benzeri yapi: // yatay cizgiler + coincidence + mesafe kisitlari (gercekci karisim). std::vector cizgiler; const int N = 60; for (int i = 0; i < N; ++i) { const f64 x = (f64)(i % 10) * 10.0, y = (f64)(i / 10) * 10.0; cizgiler.push_back(e.cizgiEkle(x, y, x + 9.0, y + 0.3)); } for (int i = 0; i + 1 < N; ++i) e.kisitEkle(KisitTip::Cakisik, {cizgiler[(size_t)i], cizgiler[(size_t)i + 1]}, {1, 0}, 0); for (int i = 0; i < N; i += 2) e.kisitEkle(KisitTip::Mesafe, {cizgiler[(size_t)i]}, 9.0); for (int i = 1; i < N; i += 2) e.kisitEkle(KisitTip::Yatay, {cizgiler[(size_t)i]}); const auto t0 = std::chrono::steady_clock::now(); Solver::Sonuc s = e.coz(); const f64 cozMs = std::chrono::duration( std::chrono::steady_clock::now() - t0).count(); const auto t1 = std::chrono::steady_clock::now(); e.surukle(cizgiler[0], 3.0, 2.0); // interaktif kritik yol (her fare karesi) const f64 surukleMs = std::chrono::duration( std::chrono::steady_clock::now() - t1).count(); std::printf("[perf] solver: %d cizgi/%zu kisit — coz %.1f ms · surukle %.1f ms " "(iter %d, norm %.2e)\n", N, e.kisitSayisi(), cozMs, surukleMs, s.iterasyon, s.kalanNorm); FIKO_KONTROL(s.kalanNorm < 1e-4); } // TAM Simetri: orta nokta eksende + segment eksene DIK (eski kod yalniz ortayi // uyguluyordu — noktalar eksen boyunca kayabiliyordu, "yarim" notu 07-09). // Iliski-tabanli dogrulama (Tur 21 dersi: coz her seyi oynatabilir). FIKO_TEST(simetrik_tam) { EskizVeri e; const u32 eksen = e.cizgiEkle(0.0, -5.0, 0.0, 5.0); const u32 n1 = e.noktaEkle(-3.0, 1.0); const u32 n2 = e.noktaEkle(4.0, 2.5); // kasitli: dik DEGIL + orta eksende degil e.kisitEkle(KisitTip::Simetrik, {n1, n2, eksen}, {0, 0, 0}, 0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); const f64 ax = e.noktaX(eksen, 0), ay = e.noktaY(eksen, 0); const f64 dx = e.noktaX(eksen, 1) - ax, dy = e.noktaY(eksen, 1) - ay; const f64 len = std::hypot(dx, dy); FIKO_KONTROL(len > 1e-6); const f64 ox = 0.5 * (e.noktaX(n1, 0) + e.noktaX(n2, 0)); const f64 oy = 0.5 * (e.noktaY(n1, 0) + e.noktaY(n2, 0)); // (1) Orta nokta eksen dogrusunda (dik mesafe ~0). FIKO_YAKIN((dx * (oy - ay) - dy * (ox - ax)) / len, 0.0, 1e-6); // (2) Segment eksene DIK (dot ~0) — eski kodda SAGLANMIYORDU. const f64 sx = e.noktaX(n2, 0) - e.noktaX(n1, 0); const f64 sy = e.noktaY(n2, 0) - e.noktaY(n1, 0); FIKO_YAKIN((dx * sx + dy * sy) / len, 0.0, 1e-6); } // (a) Kare: 4 cizgi + cakisik koseler + yatay/dikey + 2 mesafe. Sekil tam // belirli (kalan yalnizca kati-cisim oteleme); solver kareyi kurar. FIKO_TEST(kare_sekil_kisitli) { EskizVeri e; u32 alt = e.cizgiEkle(0.0, 0.0, 10.0, 0.3); u32 sag = e.cizgiEkle(10.0, 0.3, 9.8, 10.0); u32 ust = e.cizgiEkle(9.8, 10.0, 0.2, 9.9); u32 sol = e.cizgiEkle(0.2, 9.9, 0.0, 0.0); e.kisitEkle(KisitTip::Cakisik, {alt, sag}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {sag, ust}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {ust, sol}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {sol, alt}, {1, 0}, 0); e.kisitEkle(KisitTip::Yatay, {alt}); e.kisitEkle(KisitTip::Yatay, {ust}); e.kisitEkle(KisitTip::Dikey, {sol}); e.kisitEkle(KisitTip::Dikey, {sag}); e.kisitEkle(KisitTip::Mesafe, {alt}, 10.0); e.kisitEkle(KisitTip::Mesafe, {sol}, 10.0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); FIKO_KONTROL(s.durum == Solver::Durum::IyiKisitli || s.durum == Solver::Durum::AzKisitli); Skalar ax = e.noktaX(alt, 0), ay = e.noktaY(alt, 0); Skalar bx = e.noktaX(alt, 1), by = e.noktaY(alt, 1); FIKO_YAKIN(std::abs(bx - ax), 10.0, 1e-4); FIKO_YAKIN(by, ay, 1e-4); } // (a2) TAM kilitli kare: Yatay(alt)+Dikey(sol)+Dik(alt,sag)+Dik(sag,ust) sekli // tam katilastirir (2 mesafe boyutlandirir); capa noktasi bir koseye cakisik. // Sekil rijit oldugu icin geriye yalnizca 2 oteleme serbestligi kalir (dof=2). // NOT: cakisik capa noktasi (o) hem 2 param hem 2 kisit ekler → net dof // degismez; oteleme dof'unu tuketmez. Rijitligi Dik(sag,ust) saglar. FIKO_TEST(kare_tam_kilit) { EskizVeri e; u32 alt = e.cizgiEkle(0.1, -0.1, 9.9, 0.2); u32 sag = e.cizgiEkle(9.9, 0.2, 10.1, 9.8); u32 ust = e.cizgiEkle(10.1, 9.8, 0.0, 10.2); u32 sol = e.cizgiEkle(0.0, 10.2, 0.1, -0.1); e.kisitEkle(KisitTip::Cakisik, {alt, sag}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {sag, ust}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {ust, sol}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {sol, alt}, {1, 0}, 0); e.kisitEkle(KisitTip::Yatay, {alt}); e.kisitEkle(KisitTip::Dikey, {sol}); e.kisitEkle(KisitTip::Dik, {alt, sag}); e.kisitEkle(KisitTip::Dik, {sag, ust}); e.kisitEkle(KisitTip::Mesafe, {alt}, 10.0); e.kisitEkle(KisitTip::Mesafe, {sol}, 10.0); u32 o = e.noktaEkle(0.0, 0.0); e.kisitEkle(KisitTip::Cakisik, {o, alt}, {0, 0}, 0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); // Rijit sekil → yalnizca oteleme kalir (dof <= 2). FIKO_KONTROL(s.dof <= 2); Skalar ux = e.noktaX(sol, 1) - e.noktaX(sol, 0); FIKO_YAKIN(std::abs(ux), 0.0, 1e-3); } // (b) Ucgen + fazla/celiskili kisit → AsiriKisitli veya Celiskili. FIKO_TEST(ucgen_asiri_kisitli) { EskizVeri e; u32 c0 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 c1 = e.cizgiEkle(10.0, 0.0, 5.0, 8.0); u32 c2 = e.cizgiEkle(5.0, 8.0, 0.0, 0.0); e.kisitEkle(KisitTip::Cakisik, {c0, c1}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {c1, c2}, {1, 0}, 0); e.kisitEkle(KisitTip::Cakisik, {c2, c0}, {1, 0}, 0); // Uc kenar uzunlugu + uc ic aci: fazla belirtim (ucgen 3+ serbestlik ama // 6 kisit) → celiskili/asiri. e.kisitEkle(KisitTip::Mesafe, {c0}, 10.0); e.kisitEkle(KisitTip::Mesafe, {c1}, 9.43); e.kisitEkle(KisitTip::Mesafe, {c2}, 9.43); // Celiskili ek: c0 uzunlugu ayni anda 5 olsun (tutarsiz). e.kisitEkle(KisitTip::Mesafe, {c0}, 5.0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.durum == Solver::Durum::Celiskili || s.durum == Solver::Durum::AsiriKisitli || s.durum == Solver::Durum::Yakinsamadi); } // (c) Tek cizgi + yatay → dof azalir (2 nokta = 4 serbest; yatay 1 kisit → dof 3). FIKO_TEST(tek_cizgi_yatay_dof_azalir) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 5.0, 2.0); Solver::Sonuc once = e.coz(); // kisit yok → dof=4 FIKO_KONTROL(once.dof == 4); e.kisitEkle(KisitTip::Yatay, {c}); Solver::Sonuc sonra = e.coz(); FIKO_KONTROL(sonra.dof == 3); FIKO_KONTROL(sonra.kalanNorm < 1e-6); // Yatay uygulandi: iki ucun y'si esit. FIKO_YAKIN(e.noktaY(c, 0), e.noktaY(c, 1), 1e-6); } // (d) Surukleme: 'a' ucunu tasiyinca yatay + uzunluk kisitlari korunur. FIKO_TEST(surukleme_kisit_korur) { EskizVeri e; u32 c = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); e.kisitEkle(KisitTip::Yatay, {c}); e.kisitEkle(KisitTip::Mesafe, {c}, 10.0); e.coz(); // 'a' ucunu (3,4)'e cek; 'b' serbest → yatay + uzunluk tam saglanabilir. Solver::Sonuc s = e.surukle(c, 3.0, 4.0); FIKO_KONTROL(s.kalanNorm < 1e-5); // 'a' hedefe gitti. FIKO_YAKIN(e.noktaX(c, 0), 3.0, 1e-3); FIKO_YAKIN(e.noktaY(c, 0), 4.0, 1e-3); // Yatay korundu: iki uc y esit. FIKO_YAKIN(e.noktaY(c, 0), e.noktaY(c, 1), 1e-4); // Uzunluk korundu: |b-a| ~ 10. Skalar dx = e.noktaX(c, 1) - e.noktaX(c, 0); Skalar dy = e.noktaY(c, 1) - e.noktaY(c, 0); FIKO_YAKIN(std::sqrt(dx * dx + dy * dy), 10.0, 1e-3); } // (e) Daire yaricap kisiti → yaricap hedefe gider. FIKO_TEST(daire_yaricap) { EskizVeri e; u32 d = e.daireEkle(0.0, 0.0, 3.0); e.kisitEkle(KisitTip::Yaricap, {d}, 5.0); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-8); const Geometri* g = e.geoBul(d); FIKO_YAKIN(e.px(g->ir), 5.0, 1e-6); } // (f) Iki cizgi dik kisiti → aci 90 derece. FIKO_TEST(iki_cizgi_dik) { EskizVeri e; u32 c0 = e.cizgiEkle(0.0, 0.0, 10.0, 0.0); u32 c1 = e.cizgiEkle(0.0, 0.0, 8.0, 1.0); // hafif egik e.kisitEkle(KisitTip::Cakisik, {c0, c1}, {0, 0}, 0); e.kisitEkle(KisitTip::Yatay, {c0}); e.kisitEkle(KisitTip::Dik, {c0, c1}); Solver::Sonuc s = e.coz(); FIKO_KONTROL(s.kalanNorm < 1e-6); // c1 dikey olmali (c0 yatay + dik). Skalar dx = e.noktaX(c1, 1) - e.noktaX(c1, 0); FIKO_YAKIN(dx, 0.0, 1e-4); }