// PmiSistemi köprüsü — sahte çözücüyle (Vulkan'sız): çapa çözümü, olay güdümlü // tazeleme, silinince geçersizleme, diril'de kendiliğinden onarım. #include "fiko/sahne/pmi_nesne.hpp" #include "fiko/sahne/sahne_islem.hpp" #include "fiko/sahne/pmi_sistemi.hpp" #include "fiko_test.hpp" using namespace fiko; namespace { PmiSistemi::Cozucu sahteCozucu(bool* var, Vec3f merkez) { return [var, merkez](const OlcumBaglanti& l, OlcumRef& r) { if (!*var || !l.var) return false; r.var = true; r.merkez = merkez; r.normal = {0, 0, 1}; r.duzlem = true; return true; }; } } // namespace FIKO_TEST(pmi_sistemi_capa_cozumu) { PmiSistemi ps; bool canli = true; ps.cozucuAta(sahteCozucu(&canli, {5, 6, 7})); pmi::PmiOge o; o.hedefler.push_back({42, 3, 1, 111}); const u32 k = ps.defter().ekle(o); FIKO_KONTROL(ps.capaCoz(*ps.defter().bul(k))); const pmi::PmiOge* p = ps.defter().bul(k); FIKO_KONTROL(p->gecerli); FIKO_KONTROL(p->capa.x == 5 && p->capa.z == 7); FIKO_KONTROL(p->duzlemNormal.z == 1); // düzlem normali yerleşime taşındı // duzlemSag normale DİK ve birim. FIKO_KONTROL(std::abs(p->duzlemSag.z) < 1e-6); // Hedefsiz öğe → geçersiz (çökme yok). pmi::PmiOge bos; FIKO_KONTROL(!ps.capaCoz(bos) && !bos.gecerli); } FIKO_TEST(pmi_sistemi_olay_guncelleme) { OlayGunlugu g; PmiSistemi ps; bool canli = true; ps.cozucuAta(sahteCozucu(&canli, {1, 2, 3})); ps.bagla(g); pmi::PmiOge o; o.hedefler.push_back({42, 1, 1, 0}); o.gecerli = false; // başta çözülmemiş const u32 k = ps.defter().ekle(o); g.yayinla(BrepDegisti{42}, "test"); // model değişti → çapa çözülür FIKO_KONTROL(ps.defter().bul(k)->gecerli); FIKO_KONTROL(ps.defter().bul(k)->capa.y == 2); g.yayinla(VarlikSilindi{42}, "test"); // gövde silindi → kopuk (veri korunur) FIKO_KONTROL(!ps.defter().bul(k)->gecerli); FIKO_KONTROL(ps.defter().sayi() == 1); // öğe SİLİNMEZ (undo dostu) g.yayinla(VarlikEklendi{42}, "test"); // diril → kendiliğinden onarım FIKO_KONTROL(ps.defter().bul(k)->gecerli); // Çözücü başarısız olursa (gövde gerçekten yok) geçersiz kalır. canli = false; g.yayinla(BrepDegisti{42}, "test"); FIKO_KONTROL(!ps.defter().bul(k)->gecerli); // Başka gövdenin olayı bu öğeye DOKUNMAZ. canli = true; g.yayinla(BrepDegisti{99}, "test"); FIKO_KONTROL(!ps.defter().bul(k)->gecerli); } FIKO_TEST(pmi_sistemi_hedef_cevirimi) { const pmi::PmiHedef h{42, 7, 2, 555}; const OlcumBaglanti l = PmiSistemi::hedefCevir(h); FIKO_KONTROL(l.var && l.govde == 42 && l.alt == 7); FIKO_KONTROL(l.kip == SecimKip::Kenar && l.kid == 555); FIKO_KONTROL(!PmiSistemi::hedefCevir({0, 0, 1, 0}).var); // gövdesiz → var=false } FIKO_TEST(pmi_dugum_agac_ve_ozellikler) { Dunya d; PmiSistemi ps; pmi::PmiOge o; o.tip = pmi::PmiTip::Gdt; o.gdt[0].karakter = pmi::GdtKarakteristik::Diklik; o.gdt[0].tolerans = 0.05; o.gdt[0].datum[0] = 'A'; o.hedefler.push_back({42, 3, 1, 0}); // kid=0 → "kimliksiz" rozeti o.gecerli = true; const u32 pk = ps.defter().ekle(o); // Düğüm kur (Sahne::pmiEkle bileşen kümesinin Dunya karşılığı). const Varlik v = d.olustur(); Dugum dg; dg.kimlik = (u32)v; dg.tip = DugumTip::Pmi; dg.ad = "⊥ Diklik"; d.ekle(v, std::move(dg)); d.ekle(v, std::make_unique(v, &d, &ps, pk)); d.ekle(v, std::make_unique(v, &d, &ps, pk)); auto* pn = dynamic_cast(d.bul(v)->get()); FIKO_KONTROL(pn && std::string(pn->turAdi()) == "GD&T"); FIKO_KONTROL(pn->bagimliliklar().size() == 1 && pn->bagimliliklar()[0] == (Varlik)42); OzellikSeti oz = pn->ozellikler(d); bool tolVar = false; for (Ozellik& z : oz) if (z.ad == "Tolerans" && z.sayiYaz) { z.sayiYaz(0.1); tolVar = true; } FIKO_KONTROL(tolVar); FIKO_KONTROL(ps.defter().bul(pk)->gdt[0].tolerans == 0.1); // veri TEK yerde (defter) PmiGorunum g(v, &d, &ps, pk); FIKO_KONTROL(std::string(g.agacSimgesi()) == "⊥"); FIKO_KONTROL(g.agacMiniBilgi(d).find("| A") != std::string::npos); std::vector roz; g.agacRozetleri(d, roz); FIKO_KONTROL(roz.size() == 1 && roz[0].metin == "kimliksiz"); // kid=0 uyarısı ps.defter().bul(pk)->gecerli = false; roz.clear(); g.agacRozetleri(d, roz); FIKO_KONTROL(roz.size() == 1 && roz[0].metin == "kopuk"); // Görünürlük defter öğesinden yürür. g.gorunurAyarla(false); FIKO_KONTROL(!g.gorunur() && !ps.defter().bul(pk)->goster); } FIKO_TEST(pmi_duzen_islem_undo_redo) { Dunya d; OlayGunlugu g; PmiSistemi ps; pmi::PmiOge o; o.tip = pmi::PmiTip::Gdt; o.gdt[0].tolerans = 0.05; const u32 pk = ps.defter().ekle(o); pmi::PmiOge once = *ps.defter().bul(pk); ps.defter().bul(pk)->gdt[0].tolerans = 0.2; // UI değişikliği pmi::PmiOge sonra = *ps.defter().bul(pk); PmiDuzenIslem islem(&ps, pk, std::move(once), std::move(sonra), "Test"); islem.uygula(d, g); FIKO_KONTROL(ps.defter().bul(pk)->gdt[0].tolerans == 0.2); const u32 s1 = ps.defter().bul(pk)->surum; islem.geriAl(d, g); FIKO_KONTROL(ps.defter().bul(pk)->gdt[0].tolerans == 0.05); FIKO_KONTROL(ps.defter().bul(pk)->surum == s1 + 1); // sürüm İLERİ gider (önbellek tazelenir) islem.uygula(d, g); FIKO_KONTROL(ps.defter().bul(pk)->gdt[0].tolerans == 0.2); // Öğe silinmişse no-op (çökme yok). ps.defter().sil(pk); islem.geriAl(d, g); FIKO_KONTROL(ps.defter().bul(pk) == nullptr); } FIKO_TEST(pmi_islem_olaylari_yayinlanir) { // Makro/plugin/olay erişilebilirlik ilkesi: düzen/sil/geri-al PMI olayı yayınlar. Dunya d; OlayGunlugu g; int degisti = 0, silindi = 0, eklendi = 0; g.abone({OlayTuru::PmiDegisti}, [&](const OlayKaydi&) { ++degisti; }); g.abone({OlayTuru::PmiSilindi}, [&](const OlayKaydi&) { ++silindi; }); g.abone({OlayTuru::PmiEklendi}, [&](const OlayKaydi&) { ++eklendi; }); PmiSistemi ps; pmi::PmiOge o; const u32 pk = ps.defter().ekle(o); pmi::PmiOge once = *ps.defter().bul(pk); ps.defter().bul(pk)->gdt[0].tolerans = 0.3; PmiDuzenIslem islem(&ps, pk, std::move(once), *ps.defter().bul(pk), "T"); islem.uygula(d, g); islem.geriAl(d, g); FIKO_KONTROL(degisti == 2); FIKO_KONTROL(silindi == 0 && eklendi == 0); } FIKO_TEST(pmi_sil_islem_undo_redo_dongusu) { // PmiSilIslem Sahne ister (anlik/diril) → burada DEFTER sözleşmesi doğrulanır: // sil→geri al→sil zincirinde öğe aynı KİMLİKLE döner, içerik korunur. PmiSistemi ps; pmi::PmiOge o; o.tip = pmi::PmiTip::Gdt; o.gdt[0].tolerans = 0.15; o.ozelAlanlar.push_back({"Operasyon", "OP30"}); const u32 pk = ps.defter().ekle(o); const pmi::PmiOge kopya = *ps.defter().bul(pk); FIKO_KONTROL(ps.defter().sil(pk)); FIKO_KONTROL(ps.defter().bul(pk) == nullptr); FIKO_KONTROL(ps.defter().ekle(kopya) == pk); // aynı kimlikle geri const pmi::PmiOge* geri = ps.defter().bul(pk); FIKO_KONTROL(geri && geri->gdt[0].tolerans == 0.15); FIKO_KONTROL(geri->ozelAlanlar.size() == 1 && geri->ozelAlanlar[0].second == "OP30"); // İkinci tur (redo→undo) da aynı davranmalı. ps.defter().sil(pk); FIKO_KONTROL(ps.defter().ekle(kopya) == pk); FIKO_KONTROL(ps.defter().sayi() == 1); } FIKO_TEST(pmi_capa_cozucusuz_guvenli) { // Çözücü BAĞLANMADAN (belge kurulmadan) çağrılırsa: çökme yok, öğe geçersizlenir. PmiSistemi ps; pmi::PmiOge o; o.hedefler.push_back({7, 1, 1, 42}); const u32 pk = ps.defter().ekle(o); ps.guncelle(7); // no-op (çözücü yok) FIKO_KONTROL(!ps.defter().bul(pk)->gecerli); ps.gecersizle(7); FIKO_KONTROL(ps.defter().sayi() == 1); // veri korunur // Var olmayan gövde için guncelle/gecersizle sessiz. ps.guncelle(999); ps.gecersizle(999); FIKO_KONTROL(ps.defter().sayi() == 1); }