#include "fiko/io/fiko_format.hpp" #include #include #include #include #include #include #include #include "miniz.h" #include "fiko/core/gunluk.hpp" #include "fiko/geometri/brep.hpp" #include "fiko/parca/part_design_sistemi.hpp" // PartDesignSistemi (FEAT chunk çıkar/uygula) #include "fiko/render/mesh_veri.hpp" #include "fiko/render/orbit_kamera.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "fiko/sahne/olcum_sistemi.hpp" // OlcumSistemi (OLCM chunk çıkar/uygula) #include "fiko/sahne/parametre_nesne.hpp" // ParametreNesnesi (PARM chunk çıkar/uygula) #include "fiko/sahne/sahne.hpp" #include "fiko/sahne/grup_nesne.hpp" // GrupRenkBilesen (v1.12 renk-kodlu klasör kalıcılık) #include "fiko/sahne/pafta_nesne.hpp" // PaftaNesnesi (PFTA chunk çıkar/uygula) #include "fiko/sahne/pmi_nesne.hpp" // PmiNesnesi/PmiSistemi (PMIA chunk çıkar/uygula) #include "fiko/sahne/sketch_nesne.hpp" // SketchNesnesi (SKCH chunk çıkar/uygula) // ============================================================================ // .fikocad ikili format cekirdegi + Sahne/OrbitKamera kurulumu. // Spec: docs/dosya_format_spec.md. // ============================================================================ namespace fiko::io { namespace { constexpr u8 MAGIC[4] = {'F', 'K', 'C', 'D'}; constexpr u16 SURUM_BUYUK = 1; constexpr u16 SURUM_KUCUK = 20; // v1.20 pafta görünüm pmiGoster constexpr u16 SURUM_KUCUK_ESKI_ = 19; // ...v1.13 KYA kalıcı kimlik; v1.14 ölçüm link KYA kid; v1.19 CAEK (FEM kurulumu) // 4-karakter tag → u32 (little-endian tutarli, karsilastirma icin). constexpr u32 tag(char a, char b, char c, char d) { return (u32)(u8)a | ((u32)(u8)b << 8) | ((u32)(u8)c << 16) | ((u32)(u8)d << 24); } constexpr u32 TAG_META = tag('M', 'E', 'T', 'A'); constexpr u32 TAG_CMRA = tag('C', 'M', 'R', 'A'); constexpr u32 TAG_TREE = tag('T', 'R', 'E', 'E'); constexpr u32 TAG_NODE = tag('N', 'O', 'D', 'E'); constexpr u32 TAG_PARM = tag('P', 'A', 'R', 'M'); // v1.2: global parametre/formül listesi constexpr u32 TAG_SKCH = tag('S', 'K', 'C', 'H'); // v1.3: parametrik sketch'ler (düzlem + eskiz) constexpr u32 TAG_FEAT = tag('F', 'E', 'A', 'T'); // v1.3: Part Design feature ağacı constexpr u32 TAG_REFD = tag('R', 'E', 'F', 'D'); // v1.4: referans datum (Nokta/Cizgi/Duzlem) constexpr u32 TAG_ASMG = tag('A', 'S', 'M', 'G'); // v1.5: oge-bazli agac simge override (id -> emoji/yol) constexpr u32 TAG_OGOZ = tag('O', 'G', 'O', 'Z'); // v1.6: per-oge (yuz/kenar/nokta) tam gorsel override constexpr u32 TAG_OLCM = tag('O', 'L', 'C', 'M'); constexpr u32 TAG_PFTA = tag('P', 'F', 'T', 'A'); // v1.15: teknik resim (pafta) sayfaları constexpr u32 TAG_MLZM = tag('M', 'L', 'Z', 'M'); // v1.16: malzeme kutuphanesi + atamalar constexpr u32 TAG_PMIA = tag('P', 'M', 'I', 'A'); // v1.15: 3B PMI/GD&T ogeleri // v1.7: parametrik olcumler + olcum zincirleri constexpr u32 TAG_KNMT = tag('K', 'N', 'M', 'T'); // v1.17: kinematik mekanizma (uzuv+mafsal+yasa) constexpr u32 TAG_CAEK = tag('C', 'A', 'E', 'K'); // v1.19: CAE (FEM) kurulumları constexpr u32 TAG_BODY = tag('B', 'O', 'D', 'Y'); // v1.11: CATIA çoklu-PartBody grup Varlik'leri + aktifBody // ---- Tampon yazici / okuyucu (little-endian POD, kesintiye dayanikli) ------ struct Yazar { std::string b; void ham(const void* p, size_t n) { b.append(static_cast(p), n); } template void pod(const T& v) { ham(&v, sizeof(T)); } void str(const std::string& s) { pod((u32)s.size()); ham(s.data(), s.size()); } }; struct Okur { const char* p; const char* son; bool hata = false; Okur(const char* d, size_t n) : p(d), son(d + n) {} void ham(void* o, size_t n) { if ((size_t)(son - p) < n) { hata = true; return; } std::memcpy(o, p, n); p += n; } template T pod() { T v{}; ham(&v, sizeof(T)); return v; } std::string str() { const u32 n = pod(); if (hata || (size_t)(son - p) < n) { hata = true; return {}; } std::string s(p, n); p += n; return s; } size_t kalan() const { return (size_t)(son - p); } }; // ---- miniz deflate/inflate (tek cagrili) ----------------------------------- bool sikistir(const std::string& girdi, std::string& cikti) { mz_ulong sinir = mz_compressBound((mz_ulong)girdi.size()); cikti.resize(sinir); mz_ulong hedef = sinir; const int rc = mz_compress2(reinterpret_cast(cikti.data()), &hedef, reinterpret_cast(girdi.data()), (mz_ulong)girdi.size(), 9); // MZ_BEST_COMPRESSION (max oran) if (rc != MZ_OK) return false; cikti.resize(hedef); return true; } bool coz(const std::string& girdi, size_t hamBoyut, std::string& cikti) { cikti.resize(hamBoyut); mz_ulong hedef = (mz_ulong)hamBoyut; const int rc = mz_uncompress(reinterpret_cast(cikti.data()), &hedef, reinterpret_cast(girdi.data()), (mz_ulong)girdi.size()); if (rc != MZ_OK || hedef != hamBoyut) return false; return true; } // Bir chunk yaz: sikistir=true ise deflate dener; sonuc daha buyukse ham birakir. void chunkYaz(std::string& out, u32 etiket, const std::string& govde, bool sikistirIste) { std::string sk; // sıkıştırılmış tampon (yalnız kullanılırsa dolar) const std::string* disk = &govde; // varsayılan: HAM gövdeye referans → büyük blob kopyası YOK u8 bayrak = 0; if (sikistirIste && !govde.empty()) { if (sikistir(govde, sk) && sk.size() < govde.size()) { disk = &sk; bayrak = 1; } } Yazar h; h.pod(etiket); h.pod(bayrak); const u8 ayrik[3] = {0, 0, 0}; h.ham(ayrik, 3); h.pod((u64)govde.size()); // hamBoyut h.pod((u64)disk->size()); // diskBoyut out.reserve(out.size() + h.b.size() + disk->size()); // tek realloc (append büyük blob'da yeniden ayırmasın) out.append(h.b); out.append(*disk); } // Bir düğümün per-yüz renklerini çıkar. ÖNCE brep->yuzRenkleri (kesin kaynak); // boşsa CANLI mesh'ten (cpuRenk + cpuAlt) türet — render tam olarak cpuRenk'i // kullandığından bu "ekrandaki gerçek renk"tir. Renkler tekdüze (hepsi = d.renk) // ise boş döner (gereksiz şişme yok; yüklemede tekdüze renk zaten uygulanır). std::vector perYuzRenkTuret(const Dugum& n) { if (n.brep && !n.brep->yuzRenkleri().empty()) return n.brep->yuzRenkleri(); if (n.cpuRenk.empty() || n.cpuRenk.size() != n.cpuAlt.size()) return {}; u32 maxOrd = 0; for (u32 a : n.cpuAlt) maxOrd = std::max(maxOrd, a); if (maxOrd == 0) return {}; const auto fark = [](Vec3f a, Vec3f b) { return std::abs(a.x - b.x) > 1e-4f || std::abs(a.y - b.y) > 1e-4f || std::abs(a.z - b.z) > 1e-4f; }; bool renkFarkli = false; for (const Vec3f& c : n.cpuRenk) if (fark(c, n.renk)) { renkFarkli = true; break; } if (!renkFarkli) return {}; // tekdüze → per-yüz saklamaya gerek yok std::vector yr(maxOrd, n.renk); for (size_t i = 0; i < n.cpuAlt.size(); ++i) { const u32 a = n.cpuAlt[i]; if (a >= 1 && a <= maxOrd) yr[a - 1] = n.cpuRenk[i]; } return yr; } } // namespace // ---- Saf format cekirdegi --------------------------------------------------- bool fikoYaz(const FikoBelge& belge, std::string& cikti, std::string& hata, const Ilerleme& ilerle) { if (ilerle) ilerle(0.1f, "Paketleniyor"); // Dosya basligi (12 bayt) Yazar bas; bas.ham(MAGIC, 4); bas.pod(SURUM_BUYUK); bas.pod(SURUM_KUCUK); bas.pod((u32)1); // bayrak: little-endian cikti.append(bas.b); // META { Yazar m; m.pod((u32)belge.gruplar.size()); m.pod((u32)belge.dugumler.size()); m.pod(belge.birim); chunkYaz(cikti, TAG_META, m.b, false); } // CMRA { Yazar c; c.ham(belge.kamera.yonelim, sizeof(f32) * 4); c.ham(belge.kamera.odak, sizeof(f32) * 3); c.pod(belge.kamera.mesafe); c.pod(belge.kamera.fovDeg); c.pod(belge.kamera.ortografik); c.pod(belge.kamera.orbitHassas); c.pod(belge.kamera.panHassas); c.pod(belge.kamera.zoomOran); c.pod(belge.kamera.yumusatma); chunkYaz(cikti, TAG_CMRA, c.b, false); } // TREE (gruplar) { Yazar t; t.pod((u32)belge.gruplar.size()); for (const FikoGrup& g : belge.gruplar) { t.pod(g.kimlik); t.pod(g.ust); t.pod(g.gorunur); t.str(g.ad); t.pod(g.renkVar); // v1.12 renk-kodlu klasör t.ham(&g.renk.x, sizeof(f32) * 3); } chunkYaz(cikti, TAG_TREE, t.b, true); } if (ilerle) ilerle(0.5f, "Sıkıştırılıyor"); // NODE (govdeler + B-rep) { Yazar n; n.pod((u32)belge.dugumler.size()); // v1.8 brep DEDUP: özdeş gövde bir kez saklanır. Hash-havuz (çakışma → bayt karşılaştır) // → büyük anahtar kopyası yok. Dizi/pattern gövdeleri + deflate 32KB penceresi dışı // tekrarlar tek kopyaya iner (boyut küçülür; tekil modelde yalnız +4 bayt/düğüm, sıkışır). std::unordered_map> brepHavuz; u32 idx = 0; for (const FikoDugum& d : belge.dugumler) { n.pod(d.kimlik); n.pod(d.ust); n.pod(d.tip); n.pod(d.gorunur); n.ham(&d.renk.x, sizeof(f32) * 3); n.pod(d.saydamlik); n.pod(d.gorselOran); n.pod(d.p1); n.pod(d.p2); n.pod(d.p3); n.pod(d.aciZDerece); n.ham(d.konum, sizeof(f64) * 3); n.ham(d.yonelim, sizeof(f64) * 4); n.ham(d.olcek, sizeof(f64) * 3); n.str(d.ad); // paylasim: kendi indeksi → inline (ilk görülüş/boş); < indeks → önceki özdeş gövdeyi paylaş. u32 paylasim = idx; if (!d.brep.empty()) { u64 h = 1469598103934665603ull; for (unsigned char c : d.brep) h = (h ^ c) * 1099511628211ull; auto& adaylar = brepHavuz[h]; for (u32 a : adaylar) if (belge.dugumler[a].brep == d.brep) { paylasim = a; break; } if (paylasim == idx) adaylar.push_back(idx); } n.pod(paylasim); if (paylasim == idx) n.str(d.brep); // yalnız ilk kopya inline yazılır ++idx; n.pod((u32)d.yuzRenkleri.size()); // STEP per-yuz renkleri (BinTools tasimaz) if (!d.yuzRenkleri.empty()) n.ham(d.yuzRenkleri.data(), d.yuzRenkleri.size() * sizeof(Vec3f)); // KYA kalıcı kimlik (v1.13): yüz/kenar/nokta u64 etiket dizileri + sayaç. const auto kidYaz = [&n](const std::vector& v) { n.pod((u32)v.size()); if (!v.empty()) n.ham(v.data(), v.size() * sizeof(u64)); }; kidYaz(d.yuzKid); kidYaz(d.kenarKid); kidYaz(d.noktaKid); } chunkYaz(cikti, TAG_NODE, n.b, true); } // PARM (global parametre/formül) — v1.2. Boşsa yazma (eski davranış korunur). if (!belge.parametreler.empty()) { Yazar pm; pm.pod((u32)belge.parametreler.size()); for (const FikoParametre& pr : belge.parametreler) { pm.str(pr.ad); pm.str(pr.ifade); pm.str(pr.birim); pm.pod(pr.deger); } chunkYaz(cikti, TAG_PARM, pm.b, true); } // KNMT (kinematik mekanizma) — v1.17. Boşsa YAZILMAZ → eski okuyucu bozulmaz. if (!belge.uzuvlar.empty() || !belge.mafsallar.empty() || !belge.yasalar.empty()) { Yazar kn; kn.pod((u32)belge.uzuvlar.size()); for (const FikoUzuv& u : belge.uzuvlar) { kn.str(u.ad); kn.pod(u.sahne); kn.ham(u.tabanKonum, sizeof(f64) * 3); kn.ham(u.tabanYon, sizeof(f64) * 4); kn.ham(u.tabanOlcek, sizeof(f64) * 3); } kn.pod((u32)belge.mafsallar.size()); for (const FikoMafsal& m : belge.mafsallar) { kn.str(m.ad); kn.pod(m.tip); kn.pod(m.ana); kn.pod(m.cocuk); kn.ham(m.capaKonum, sizeof(f64) * 3); kn.ham(m.capaYon, sizeof(f64) * 4); kn.ham(m.capaCocukKonum, sizeof(f64) * 3); // v1.18 çift taraflı çapa kn.ham(m.capaCocukYon, sizeof(f64) * 4); kn.pod(m.q); kn.pod(m.q2); kn.pod(m.q3); kn.pod(m.vidaAdim); kn.pod(m.altSinir); kn.pod(m.ustSinir); } kn.pod((u32)belge.yasalar.size()); for (const FikoYasa& y : belge.yasalar) { kn.pod(y.mafsal); kn.pod(y.tip); kn.pod(y.degisken); kn.pod(y.deger); kn.pod(y.hiz); kn.pod(y.genlik); kn.pod(y.periyot); kn.pod(y.faz); kn.pod((u32)y.anahtarlar.size()); for (const auto& [t, q] : y.anahtarlar) { kn.pod(t); kn.pod(q); } } chunkYaz(cikti, TAG_KNMT, kn.b, true); } // CAEK (yapısal analiz kurulumları) — v1.19. Boşsa YAZILMAZ → eski okuyucu bozulmaz. if (!belge.caeKurulumlar.empty()) { Yazar ck; ck.pod((u32)belge.caeKurulumlar.size()); for (const FikoCaeKurulum& c : belge.caeKurulumlar) { ck.pod(c.dugum); ck.pod(c.cozunurluk); ck.pod(c.elastisite); ck.pod(c.poisson); ck.pod(c.sabitYuz); ck.pod(c.yukYuz); ck.pod(c.simetriKisit); ck.pod(c.konservatif); ck.ham(c.kuvvet, sizeof(f64) * 3); } chunkYaz(cikti, TAG_CAEK, ck.b, true); } // SKCH (parametrik sketch'ler) — v1.3. Boşsa yazma (geriye-uyum korunur). if (!belge.sketchler.empty()) { Yazar sk; sk.pod((u32)belge.sketchler.size()); for (const FikoSketch& s : belge.sketchler) { sk.pod(s.kimlik); sk.pod(s.ust); sk.str(s.ad); sk.ham(s.duzlemKonum, sizeof(f64) * 3); sk.ham(s.duzlemYon, sizeof(f64) * 4); sk.ham(s.duzlemOlcek, sizeof(f64) * 3); sk.str(s.eskiz); // EskizVeri seri blob (uzunluk önekli) } chunkYaz(cikti, TAG_SKCH, sk.b, true); } // FEAT (Part Design feature ağacı) — v1.3. Boşsa yazma (geriye-uyum korunur). if (!belge.featureler.empty()) { Yazar ft; ft.pod((u32)belge.featureler.size()); for (const FikoFeature& f : belge.featureler) { ft.pod(f.kimlik); ft.str(f.tip); ft.str(f.ad); ft.pod(f.sketch); ft.pod(f.hedefDugum); ft.pod(f.sonucDugum); ft.pod(f.bastirildi); ft.pod(f.kilitli); ft.pod((u32)f.parametreler.size()); for (const auto& [a, d] : f.parametreler) { ft.str(a); ft.pod(d); } ft.pod((u32)f.formuller.size()); for (const auto& [a, i] : f.formuller) { ft.str(a); ft.str(i); } // v1.10: yüz provenance (okuyucu sKucuk>=10 ile gate'ler — eski dosya sorunsuz). ft.pod((u32)f.uretilenYuzler.size()); for (u32 o : f.uretilenYuzler) ft.pod(o); ft.pod((u32)f.yuzGeriHarita.size()); for (i32 o : f.yuzGeriHarita) ft.pod(o); } chunkYaz(cikti, TAG_FEAT, ft.b, true); } // REFD (referans datum: Nokta/Çizgi/Düzlem) — v1.4. Boşsa yazma (geriye-uyum korunur). if (!belge.datumlar.empty()) { Yazar rd; rd.pod((u32)belge.datumlar.size()); for (const FikoDatum& dt : belge.datumlar) { rd.pod(dt.kimlik); rd.pod(dt.ust); rd.pod(dt.tip); rd.pod(dt.gorunur); rd.pod(dt.tanimTip); rd.ham(&dt.renk.x, sizeof(f32) * 3); rd.pod(dt.gorselOran); rd.ham(dt.konum, sizeof(f64) * 3); rd.ham(dt.yon, sizeof(f64) * 3); rd.pod(dt.kaynak); rd.pod(dt.mesafe); rd.str(dt.ad); } chunkYaz(cikti, TAG_REFD, rd.b, true); } // ASMG (öğe-bazlı ağaç simge override'ları: Varlik → emoji/yol) — v1.5. Boşsa yazma. if (!belge.agacSimgeleri.empty()) { Yazar sm; sm.pod((u32)belge.agacSimgeleri.size()); for (const auto& [id, deger] : belge.agacSimgeleri) { sm.pod(id); sm.str(deger); } chunkYaz(cikti, TAG_ASMG, sm.b, true); } // BODY (CATIA çoklu-PartBody: body grup Varlik'leri + aktifBody) — v1.11. Boşsa yazma. if (!belge.bodyler.empty()) { Yazar bd; bd.pod((u32)belge.bodyler.size()); for (u32 v : belge.bodyler) bd.pod(v); bd.pod(belge.aktifBody); chunkYaz(cikti, TAG_BODY, bd.b, true); } // OGOZ (per-öğe görsel override: yüz/kenar/nokta alfa+görünür+stil) — v1.6. Boşsa yazma. if (!belge.ogeOzellikleri.empty()) { Yazar oz; const auto yazOge = [](Yazar& w, const std::vector& v) { w.pod((u32)v.size()); for (const FikoOgeOz& o : v) { w.pod(o.ord); w.ham(&o.renk.x, sizeof(f32) * 3); w.pod(o.alfa); w.pod(o.gorunur); w.pod(o.stil); w.pod(o.kalinlik); w.pod(o.noktaBoyut); w.pod(o.sekil); w.pod(o.metalik); w.pod(o.puruz); } }; const auto yazTekOge = [](Yazar& w, const FikoOgeOz& o) { w.pod(o.ord); w.ham(&o.renk.x, sizeof(f32) * 3); w.pod(o.alfa); w.pod(o.gorunur); w.pod(o.stil); w.pod(o.kalinlik); w.pod(o.noktaBoyut); w.pod(o.sekil); w.pod(o.metalik); w.pod(o.puruz); }; oz.pod((u32)belge.ogeOzellikleri.size()); for (const FikoDugumOz& d : belge.ogeOzellikleri) { oz.pod(d.dugum); yazOge(oz, d.yuz); yazOge(oz, d.kenar); yazOge(oz, d.nokta); oz.pod(d.varsVar); // v1.9: gövde-seviye öğe varsayılanları if (d.varsVar) { yazTekOge(oz, d.yuzVars); yazTekOge(oz, d.kenarVars); yazTekOge(oz, d.noktaVars); } } chunkYaz(cikti, TAG_OGOZ, oz.b, true); } // OLCM (parametrik ölçümler + zincirler) — v1.7. Boşsa yazma (geriye-uyum korunur). if (!belge.olcumler.empty() || !belge.olcumZincirleri.empty()) { Yazar om; const auto yazLink = [](Yazar& w, const FikoOlcumLink& l) { w.pod(l.var); w.pod(l.govde); w.pod(l.alt); w.pod(l.kip); w.pod(l.serbest); w.ham(&l.yerel.x, sizeof(f32) * 3); w.pod(l.kid); // v1.14: KYA kalıcı kimlik (ordinal kayınca link buradan çözülür) }; om.pod((u32)belge.olcumler.size()); for (const FikoOlcum& o : belge.olcumler) { om.pod(o.kimlik); om.pod(o.tur); om.pod(o.mod1); om.pod(o.mod2); yazLink(om, o.k1); yazLink(om, o.k2); om.pod(o.ofset); om.pod(o.aci); om.pod(o.uzatma1); om.pod(o.uzatma2); om.pod(o.taban1); om.pod(o.taban2); } om.pod((u32)belge.olcumZincirleri.size()); for (const FikoOlcumZincir& z : belge.olcumZincirleri) { om.pod(z.kimlik); om.pod(z.kapali); om.pod((u32)z.noktalar.size()); for (const FikoOlcumLink& l : z.noktalar) yazLink(om, l); } chunkYaz(cikti, TAG_OLCM, om.b, true); } // PFTA (teknik resim sayfaları) — v1.15. Boşsa yazma (geriye-uyum korunur). if (!belge.paftalar.empty()) { Yazar pf; pf.pod((u32)belge.paftalar.size()); for (const FikoPafta& p : belge.paftalar) { pf.pod(p.kimlik); pf.pod(p.ust); pf.str(p.ad); pf.pod(p.sayfa); pf.pod(p.ozelEn); pf.pod(p.ozelBoy); pf.pod(p.olcekPay); pf.pod(p.olcekPayda); pf.pod(p.antetGoster); pf.pod(p.antetEn); pf.pod(p.antetBoy); pf.str(p.proje); pf.str(p.parca); pf.str(p.cizen); pf.str(p.tarih); pf.str(p.malzeme); pf.str(p.revizyon); pf.str(p.aciklama); pf.pod((u32)p.gorunumler.size()); for (const FikoPaftaGorunum& g : p.gorunumler) { pf.pod(g.kimlik); pf.pod(g.kaynak); pf.pod(g.ust); pf.pod(g.yon); pf.pod(g.hiza); pf.pod(g.olcekMiras); pf.pod(g.gizliCizgi); pf.pod(g.goster); pf.pod(g.olcekPay); pf.pod(g.olcekPayda); pf.ham(g.konum, sizeof(f64) * 2); pf.ham(g.boyut, sizeof(f64) * 2); pf.str(g.ad); pf.pod(g.kesitMi); pf.pod(g.taramaGoster); pf.pod(g.kesitAnaGorunum); pf.ham(g.kesitA, sizeof(f64) * 2); pf.ham(g.kesitB, sizeof(f64) * 2); pf.pod(g.kesitHarf); pf.pod(g.detayMi); pf.pod(g.detayAnaGorunum); pf.ham(g.detayMerkez, sizeof(f64) * 2); pf.pod(g.detayYaricap); pf.pod(g.detayHarf); pf.pod(g.pmiGoster); // v1.20 } pf.pod((u32)p.olculer.size()); for (const FikoPaftaOlcu& o : p.olculer) { pf.pod(o.kimlik); pf.pod(o.gorunum); pf.pod(o.tip); pf.pod(o.otoDeger); pf.pod(o.goster); pf.ham(o.p1, sizeof(f64) * 2); pf.ham(o.p2, sizeof(f64) * 2); pf.ham(o.tepe, sizeof(f64) * 2); pf.pod(o.ofset); pf.pod(o.elleDeger); pf.str(o.onEk); pf.str(o.sonEk); } } chunkYaz(cikti, TAG_PFTA, pf.b, true); } // PMIA (3B PMI/GD&T) — v1.15. Boşsa yazma. if (!belge.pmiler.empty()) { Yazar pm; const auto yazLink2 = [](Yazar& w, const FikoOlcumLink& l) { w.pod(l.var); w.pod(l.govde); w.pod(l.alt); w.pod(l.kip); w.pod(l.serbest); w.ham(&l.yerel.x, sizeof(f32) * 3); w.pod(l.kid); }; pm.pod((u32)belge.pmiler.size()); for (const FikoPmi& q : belge.pmiler) { pm.pod(q.kimlik); pm.pod(q.dugumKimlik); pm.pod(q.ust); pm.str(q.ad); pm.pod(q.tip); pm.pod(q.yerlesim); pm.pod((u32)q.hedefler.size()); for (const FikoOlcumLink& l : q.hedefler) yazLink2(pm, l); pm.ham(&q.ofsetYerel.x, sizeof(f32) * 3); pm.ham(&q.duzlemNormal.x, sizeof(f32) * 3); pm.ham(&q.duzlemSag.x, sizeof(f32) * 3); pm.pod(q.liderVar); pm.pod(q.goster); pm.pod(q.gorselOran); pm.pod(q.gdtSatirSayi); for (int i = 0; i < 2; ++i) { const FikoPmiGdtSatir& g = q.gdt[i]; pm.pod(g.karakter); pm.pod(g.tolerans); pm.pod(g.capsal); pm.pod(g.kosul); pm.pod(g.projeksiyonlu); pm.pod(g.projeksiyonUzunluk); pm.ham(g.datum, 3); pm.ham(g.datumKosul, 3); } pm.pod(q.datumHarf); pm.str(q.metin); pm.pod((u32)q.ozelAlanlar.size()); for (const auto& [a2, d2] : q.ozelAlanlar) { pm.str(a2); pm.str(d2); } pm.ham(&q.renk.x, sizeof(f32) * 3); pm.pod(q.yaziBoyu); pm.pod(q.cizgiKalinlik); pm.pod(q.sembolOlcek); pm.pod(q.alfa); } chunkYaz(cikti, TAG_PMIA, pm.b, true); } // MLZM (malzeme kutuphanesi + atamalar) — v1.16. Bossa yazma. HAZIR malzemeler // yazilmaz (kutuphane onlari zaten kurar); yalniz kullanicinin urettikleri + // atamalar tasinir → dosya kucuk kalir, hazir tablo guncellenince eski dosyalar // yeni tanimlari alir. if (!belge.malzemeler.empty() || !belge.malzemeAtamalari.empty()) { Yazar mz; mz.pod((u32)belge.malzemeler.size()); for (const FikoMalzeme& m : belge.malzemeler) { mz.pod(m.kimlik); mz.str(m.ad); mz.str(m.aciklama); mz.str(m.dokumAlasimAdi); mz.pod(m.sinif); mz.pod(m.hazir); mz.ham(&m.tabanRenk.x, sizeof(f32) * 3); mz.pod(m.opaklik); mz.pod(m.metaliklik); mz.pod(m.puruzluluk); mz.pod(m.yansima); mz.pod(m.ortmeSiddet); mz.pod(m.anizotropi); mz.pod(m.anizotropiAci); mz.pod(m.kaplamaBerrak); mz.pod(m.kaplamaPuruz); mz.ham(&m.kaplamaRenk.x, sizeof(f32) * 3); mz.pod(m.gecirgenlik); mz.pod(m.kalinlik); mz.pod(m.kirilmaIndisi); mz.ham(&m.emilimRenk.x, sizeof(f32) * 3); mz.ham(&m.parlakTuyRenk.x, sizeof(f32) * 3); mz.ham(&m.sacilmaRenk.x, sizeof(f32) * 3); mz.ham(&m.emisyonRenk.x, sizeof(f32) * 3); mz.pod(m.parlakTuyPuruz); mz.pod(m.sacilmaSiddet); mz.pod(m.emisyonSiddet); for (int i = 0; i < 8; ++i) { mz.str(m.dokular[i].yol); mz.pod(m.dokular[i].siddet); mz.pod(m.dokular[i].ters); } mz.pod(m.kaplama); mz.pod(m.sarma); mz.pod(m.dunyaUzayinda); mz.ham(&m.dokuOlcek.x, sizeof(f32) * 3); mz.ham(&m.dokuOfset.x, sizeof(f32) * 3); mz.pod(m.dokuDonus); mz.pod(m.triplanarKeskinlik); mz.pod(m.kabartmaDerinlik); mz.pod(m.yogunluk); } mz.pod((u32)belge.malzemeAtamalari.size()); for (const FikoMalzemeAtama& a : belge.malzemeAtamalari) { mz.pod(a.govde); mz.pod(a.yuz); mz.pod(a.malzeme); } chunkYaz(cikti, TAG_MLZM, mz.b, true); } if (ilerle) ilerle(0.9f, "Paketlendi"); (void)hata; return true; } bool fikoOku(const std::string& veri, FikoBelge& belge, std::string& hata, const Ilerleme& ilerle) { if (ilerle) ilerle(0.1f, "Çözülüyor"); if (veri.size() < 12) { hata = "Bozuk .fikocad (çok kısa)"; return false; } const char* p = veri.data(); if (std::memcmp(p, MAGIC, 4) != 0) { hata = "Geçersiz .fikocad dosyası (imza yok)"; return false; } u16 sBuyuk, sKucuk; std::memcpy(&sBuyuk, p + 4, 2); std::memcpy(&sKucuk, p + 6, 2); if (sBuyuk > SURUM_BUYUK) { hata = "Sürüm uyumsuz: dosya v" + std::to_string(sBuyuk) + ", uygulama v" + std::to_string(SURUM_BUYUK) + " — güncelleme gerekli"; return false; } size_t o = 12; bool metaVar = false; while (o + 24 <= veri.size()) { u32 etiket; u8 bayrak; u64 hamBoyut, diskBoyut; std::memcpy(&etiket, p + o, 4); std::memcpy(&bayrak, p + o + 4, 1); std::memcpy(&hamBoyut, p + o + 8, 8); std::memcpy(&diskBoyut, p + o + 16, 8); o += 24; if (o + diskBoyut > veri.size() || diskBoyut > (u64)veri.size()) { hata = "Bozuk .fikocad (eksik chunk gövdesi)"; return false; } std::string govde; if (bayrak == 1) { const std::string sk(p + o, (size_t)diskBoyut); if (hamBoyut > (u64)(veri.size()) * 64u + 65536u) { // makul üst sınır (zip-bomb guard) hata = "Bozuk .fikocad (aşırı açılım boyutu)"; return false; } if (!coz(sk, (size_t)hamBoyut, govde)) { hata = "Bozuk .fikocad (sıkıştırma çözülemedi)"; return false; } } else { govde.assign(p + o, (size_t)diskBoyut); } o += (size_t)diskBoyut; Okur r(govde.data(), govde.size()); if (etiket == TAG_META) { r.pod(); // grupSayi (bilgi amaçlı; gerçek sayı chunk'lardan) r.pod(); // dugumSayi belge.birim = r.pod(); metaVar = true; } else if (etiket == TAG_CMRA) { r.ham(belge.kamera.yonelim, sizeof(f32) * 4); r.ham(belge.kamera.odak, sizeof(f32) * 3); belge.kamera.mesafe = r.pod(); belge.kamera.fovDeg = r.pod(); belge.kamera.ortografik = r.pod(); belge.kamera.orbitHassas = r.pod(); belge.kamera.panHassas = r.pod(); belge.kamera.zoomOran = r.pod(); belge.kamera.yumusatma = r.pod(); } else if (etiket == TAG_TREE) { const u32 sayi = r.pod(); belge.gruplar.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoGrup g; g.kimlik = r.pod(); g.ust = r.pod(); g.gorunur = r.pod(); g.ad = r.str(); if (sKucuk >= 12) { // v1.12 renk-kodlu klasör (eski dosyada yok → renkVar=0) g.renkVar = r.pod(); r.ham(&g.renk.x, sizeof(f32) * 3); } belge.gruplar.push_back(std::move(g)); } } else if (etiket == TAG_NODE) { const u32 sayi = r.pod(); belge.dugumler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoDugum d; d.kimlik = r.pod(); d.ust = r.pod(); d.tip = r.pod(); d.gorunur = r.pod(); r.ham(&d.renk.x, sizeof(f32) * 3); d.saydamlik = r.pod(); d.gorselOran = r.pod(); d.p1 = r.pod(); d.p2 = r.pod(); d.p3 = r.pod(); d.aciZDerece = r.pod(); r.ham(d.konum, sizeof(f64) * 3); r.ham(d.yonelim, sizeof(f64) * 4); r.ham(d.olcek, sizeof(f64) * 3); d.ad = r.str(); if (sKucuk >= 8) { // v1.8 brep DEDUP const u32 paylasim = r.pod(); if (paylasim == i) d.brep = r.str(); // inline (ilk kopya) else if (paylasim < i) d.brep = belge.dugumler[paylasim].brep; // önceki özdeşi paylaş // paylasim geçersiz (>i) → d.brep boş → govdeBaytOku geçersiz → düğüm atlanır (çökme yok) } else { d.brep = r.str(); // v<1.8: her düğüm inline } const u32 yrSayi = r.pod(); if (!r.hata && yrSayi > 0 && r.kalan() >= (size_t)yrSayi * sizeof(Vec3f)) { d.yuzRenkleri.resize(yrSayi); r.ham(d.yuzRenkleri.data(), (size_t)yrSayi * sizeof(Vec3f)); } else if (yrSayi > 0) { r.hata = true; // bozuk/kesik renk verisi } if (sKucuk >= 13) { // v1.13 KYA kalıcı kimlik (yüz/kenar/nokta u64 etiket + sayaç) const auto kidOku = [&r](std::vector& v) { const u32 n = r.pod(); if (!r.hata && n > 0 && r.kalan() >= (size_t)n * sizeof(u64)) { v.resize(n); r.ham(v.data(), (size_t)n * sizeof(u64)); } else if (n > 0) { r.hata = true; // bozuk/kesik kimlik verisi } }; kidOku(d.yuzKid); kidOku(d.kenarKid); kidOku(d.noktaKid); } belge.dugumler.push_back(std::move(d)); } } else if (etiket == TAG_PARM) { const u32 sayi = r.pod(); belge.parametreler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoParametre pr; pr.ad = r.str(); pr.ifade = r.str(); pr.birim = r.str(); pr.deger = r.pod(); belge.parametreler.push_back(std::move(pr)); } } else if (etiket == TAG_CAEK) { // v1.19 CAE (FEM) kurulumları const u32 n = r.pod(); belge.caeKurulumlar.reserve(n); for (u32 i = 0; i < n && !r.hata; ++i) { FikoCaeKurulum c; c.dugum = r.pod(); c.cozunurluk = r.pod(); c.elastisite = r.pod(); c.poisson = r.pod(); c.sabitYuz = r.pod(); c.yukYuz = r.pod(); c.simetriKisit = r.pod(); c.konservatif = r.pod(); r.ham(c.kuvvet, sizeof(f64) * 3); belge.caeKurulumlar.push_back(c); } } else if (etiket == TAG_KNMT) { const u32 uSayi = r.pod(); belge.uzuvlar.reserve(uSayi); for (u32 i = 0; i < uSayi && !r.hata; ++i) { FikoUzuv u; u.ad = r.str(); u.sahne = r.pod(); r.ham(u.tabanKonum, sizeof(f64) * 3); r.ham(u.tabanYon, sizeof(f64) * 4); r.ham(u.tabanOlcek, sizeof(f64) * 3); belge.uzuvlar.push_back(std::move(u)); } const u32 mSayi = r.pod(); belge.mafsallar.reserve(mSayi); for (u32 i = 0; i < mSayi && !r.hata; ++i) { FikoMafsal m; m.ad = r.str(); m.tip = r.pod(); m.ana = r.pod(); m.cocuk = r.pod(); r.ham(m.capaKonum, sizeof(f64) * 3); r.ham(m.capaYon, sizeof(f64) * 4); if (sKucuk >= 18) { // v1.18 çift taraflı çapa (eski dosyada YOK → birim kalır) r.ham(m.capaCocukKonum, sizeof(f64) * 3); r.ham(m.capaCocukYon, sizeof(f64) * 4); } m.q = r.pod(); m.q2 = r.pod(); m.q3 = r.pod(); m.vidaAdim = r.pod(); m.altSinir = r.pod(); m.ustSinir = r.pod(); belge.mafsallar.push_back(std::move(m)); } const u32 ySayi = r.pod(); belge.yasalar.reserve(ySayi); for (u32 i = 0; i < ySayi && !r.hata; ++i) { FikoYasa y; y.mafsal = r.pod(); y.tip = r.pod(); y.degisken = r.pod(); y.deger = r.pod(); y.hiz = r.pod(); y.genlik = r.pod(); y.periyot = r.pod(); y.faz = r.pod(); const u32 aSayi = r.pod(); y.anahtarlar.reserve(aSayi); for (u32 j = 0; j < aSayi && !r.hata; ++j) { const f64 t = r.pod(); const f64 q = r.pod(); y.anahtarlar.emplace_back(t, q); } belge.yasalar.push_back(std::move(y)); } } else if (etiket == TAG_SKCH) { const u32 sayi = r.pod(); belge.sketchler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoSketch s; s.kimlik = r.pod(); s.ust = r.pod(); s.ad = r.str(); r.ham(s.duzlemKonum, sizeof(f64) * 3); r.ham(s.duzlemYon, sizeof(f64) * 4); r.ham(s.duzlemOlcek, sizeof(f64) * 3); s.eskiz = r.str(); belge.sketchler.push_back(std::move(s)); } } else if (etiket == TAG_FEAT) { const u32 sayi = r.pod(); belge.featureler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoFeature f; f.kimlik = r.pod(); f.tip = r.str(); f.ad = r.str(); f.sketch = r.pod(); f.hedefDugum = r.pod(); f.sonucDugum = r.pod(); f.bastirildi = r.pod(); f.kilitli = r.pod(); const u32 pSayi = r.pod(); for (u32 j = 0; j < pSayi && !r.hata; ++j) { std::string a = r.str(); f64 d = r.pod(); f.parametreler.emplace_back(std::move(a), d); } const u32 fSayi = r.pod(); for (u32 j = 0; j < fSayi && !r.hata; ++j) { std::string a = r.str(); std::string ifade = r.str(); f.formuller.emplace_back(std::move(a), std::move(ifade)); } if (sKucuk >= 10) { // v1.10: yüz provenance const u32 uSayi = r.pod(); f.uretilenYuzler.reserve(uSayi); for (u32 j = 0; j < uSayi && !r.hata; ++j) f.uretilenYuzler.push_back(r.pod()); const u32 gSayi = r.pod(); f.yuzGeriHarita.reserve(gSayi); for (u32 j = 0; j < gSayi && !r.hata; ++j) f.yuzGeriHarita.push_back(r.pod()); } belge.featureler.push_back(std::move(f)); } } else if (etiket == TAG_REFD) { const u32 sayi = r.pod(); belge.datumlar.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoDatum dt; dt.kimlik = r.pod(); dt.ust = r.pod(); dt.tip = r.pod(); dt.gorunur = r.pod(); dt.tanimTip = r.pod(); r.ham(&dt.renk.x, sizeof(f32) * 3); dt.gorselOran = r.pod(); r.ham(dt.konum, sizeof(f64) * 3); r.ham(dt.yon, sizeof(f64) * 3); dt.kaynak = r.pod(); dt.mesafe = r.pod(); dt.ad = r.str(); belge.datumlar.push_back(std::move(dt)); } } else if (etiket == TAG_ASMG) { const u32 sayi = r.pod(); belge.agacSimgeleri.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { const u64 id = r.pod(); std::string deger = r.str(); belge.agacSimgeleri.emplace_back(id, std::move(deger)); } } else if (etiket == TAG_BODY) { const u32 sayi = r.pod(); belge.bodyler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) belge.bodyler.push_back(r.pod()); belge.aktifBody = r.pod(); } else if (etiket == TAG_OGOZ) { const auto okuOge = [](Okur& rr, std::vector& out) { const u32 m = rr.pod(); out.reserve(m); for (u32 j = 0; j < m && !rr.hata; ++j) { FikoOgeOz o; o.ord = rr.pod(); rr.ham(&o.renk.x, sizeof(f32) * 3); o.alfa = rr.pod(); o.gorunur = rr.pod(); o.stil = rr.pod(); o.kalinlik = rr.pod(); o.noktaBoyut = rr.pod(); o.sekil = rr.pod(); o.metalik = rr.pod(); o.puruz = rr.pod(); out.push_back(o); } }; const u32 sayi = r.pod(); belge.ogeOzellikleri.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoDugumOz d; d.dugum = r.pod(); okuOge(r, d.yuz); okuOge(r, d.kenar); okuOge(r, d.nokta); if (sKucuk >= 9) { // v1.9: gövde-seviye öğe varsayılanları const auto okuTekOge = [](Okur& rr) { FikoOgeOz o; o.ord = rr.pod(); rr.ham(&o.renk.x, sizeof(f32) * 3); o.alfa = rr.pod(); o.gorunur = rr.pod(); o.stil = rr.pod(); o.kalinlik = rr.pod(); o.noktaBoyut = rr.pod(); o.sekil = rr.pod(); o.metalik = rr.pod(); o.puruz = rr.pod(); return o; }; d.varsVar = r.pod(); if (d.varsVar) { d.yuzVars = okuTekOge(r); d.kenarVars = okuTekOge(r); d.noktaVars = okuTekOge(r); } } belge.ogeOzellikleri.push_back(std::move(d)); } } else if (etiket == TAG_OLCM) { const auto okuLink = [sKucuk](Okur& rr) { FikoOlcumLink l; l.var = rr.pod(); l.govde = rr.pod(); l.alt = rr.pod(); l.kip = rr.pod(); l.serbest = rr.pod(); rr.ham(&l.yerel.x, sizeof(f32) * 3); if (sKucuk >= 14) l.kid = rr.pod(); // v1.14 KYA kalıcı kimlik return l; }; const u32 oSayi = r.pod(); belge.olcumler.reserve(oSayi); for (u32 i = 0; i < oSayi && !r.hata; ++i) { FikoOlcum o; o.kimlik = r.pod(); o.tur = r.pod(); o.mod1 = r.pod(); o.mod2 = r.pod(); o.k1 = okuLink(r); o.k2 = okuLink(r); o.ofset = r.pod(); o.aci = r.pod(); o.uzatma1 = r.pod(); o.uzatma2 = r.pod(); o.taban1 = r.pod(); o.taban2 = r.pod(); belge.olcumler.push_back(std::move(o)); } const u32 zSayi = r.pod(); belge.olcumZincirleri.reserve(zSayi); for (u32 i = 0; i < zSayi && !r.hata; ++i) { FikoOlcumZincir z; z.kimlik = r.pod(); z.kapali = r.pod(); const u32 nSayi = r.pod(); z.noktalar.reserve(nSayi); for (u32 j = 0; j < nSayi && !r.hata; ++j) z.noktalar.push_back(okuLink(r)); belge.olcumZincirleri.push_back(std::move(z)); } } else if (etiket == TAG_PFTA) { // v1.15 teknik resim sayfaları const u32 pSayi = r.pod(); belge.paftalar.reserve(pSayi); for (u32 i = 0; i < pSayi && !r.hata; ++i) { FikoPafta p; p.kimlik = r.pod(); p.ust = r.pod(); p.ad = r.str(); p.sayfa = r.pod(); p.ozelEn = r.pod(); p.ozelBoy = r.pod(); p.olcekPay = r.pod(); p.olcekPayda = r.pod(); p.antetGoster = r.pod(); p.antetEn = r.pod(); p.antetBoy = r.pod(); p.proje = r.str(); p.parca = r.str(); p.cizen = r.str(); p.tarih = r.str(); p.malzeme = r.str(); p.revizyon = r.str(); p.aciklama = r.str(); const u32 gSayi = r.pod(); p.gorunumler.reserve(gSayi); for (u32 j = 0; j < gSayi && !r.hata; ++j) { FikoPaftaGorunum g; g.kimlik = r.pod(); g.kaynak = r.pod(); g.ust = r.pod(); g.yon = r.pod(); g.hiza = r.pod(); g.olcekMiras = r.pod(); g.gizliCizgi = r.pod(); g.goster = r.pod(); g.olcekPay = r.pod(); g.olcekPayda = r.pod(); r.ham(g.konum, sizeof(f64) * 2); r.ham(g.boyut, sizeof(f64) * 2); g.ad = r.str(); g.kesitMi = r.pod(); g.taramaGoster = r.pod(); g.kesitAnaGorunum = r.pod(); r.ham(g.kesitA, sizeof(f64) * 2); r.ham(g.kesitB, sizeof(f64) * 2); g.kesitHarf = (char)r.pod(); g.detayMi = r.pod(); g.detayAnaGorunum = r.pod(); r.ham(g.detayMerkez, sizeof(f64) * 2); g.detayYaricap = r.pod(); g.detayHarf = r.pod(); if (sKucuk >= 20) g.pmiGoster = r.pod(); // v1.20 (eski dosyada yok → 1 kalır) p.gorunumler.push_back(std::move(g)); } const u32 oSayi2 = r.pod(); p.olculer.reserve(oSayi2); for (u32 j = 0; j < oSayi2 && !r.hata; ++j) { FikoPaftaOlcu o; o.kimlik = r.pod(); o.gorunum = r.pod(); o.tip = r.pod(); o.otoDeger = r.pod(); o.goster = r.pod(); r.ham(o.p1, sizeof(f64) * 2); r.ham(o.p2, sizeof(f64) * 2); r.ham(o.tepe, sizeof(f64) * 2); o.ofset = r.pod(); o.elleDeger = r.pod(); o.onEk = r.str(); o.sonEk = r.str(); p.olculer.push_back(std::move(o)); } belge.paftalar.push_back(std::move(p)); } } else if (etiket == TAG_MLZM) { // v1.16 malzeme kutuphanesi + atamalar const u32 mSayi = r.pod(); belge.malzemeler.reserve(mSayi); for (u32 i = 0; i < mSayi && !r.hata; ++i) { FikoMalzeme m; m.kimlik = r.pod(); m.ad = r.str(); m.aciklama = r.str(); m.dokumAlasimAdi = r.str(); m.sinif = r.pod(); m.hazir = r.pod(); r.ham(&m.tabanRenk.x, sizeof(f32) * 3); m.opaklik = r.pod(); m.metaliklik = r.pod(); m.puruzluluk = r.pod(); m.yansima = r.pod(); m.ortmeSiddet = r.pod(); m.anizotropi = r.pod(); m.anizotropiAci = r.pod(); m.kaplamaBerrak = r.pod(); m.kaplamaPuruz = r.pod(); r.ham(&m.kaplamaRenk.x, sizeof(f32) * 3); m.gecirgenlik = r.pod(); m.kalinlik = r.pod(); m.kirilmaIndisi = r.pod(); r.ham(&m.emilimRenk.x, sizeof(f32) * 3); r.ham(&m.parlakTuyRenk.x, sizeof(f32) * 3); r.ham(&m.sacilmaRenk.x, sizeof(f32) * 3); r.ham(&m.emisyonRenk.x, sizeof(f32) * 3); m.parlakTuyPuruz = r.pod(); m.sacilmaSiddet = r.pod(); m.emisyonSiddet = r.pod(); for (int k = 0; k < 8; ++k) { m.dokular[k].yol = r.str(); m.dokular[k].siddet = r.pod(); m.dokular[k].ters = r.pod(); } m.kaplama = r.pod(); m.sarma = r.pod(); m.dunyaUzayinda = r.pod(); r.ham(&m.dokuOlcek.x, sizeof(f32) * 3); r.ham(&m.dokuOfset.x, sizeof(f32) * 3); m.dokuDonus = r.pod(); m.triplanarKeskinlik = r.pod(); m.kabartmaDerinlik = r.pod(); m.yogunluk = r.pod(); belge.malzemeler.push_back(std::move(m)); } const u32 aSayi = r.pod(); belge.malzemeAtamalari.reserve(aSayi); for (u32 i = 0; i < aSayi && !r.hata; ++i) { FikoMalzemeAtama a; a.govde = r.pod(); a.yuz = r.pod(); a.malzeme = r.pod(); belge.malzemeAtamalari.push_back(a); } } else if (etiket == TAG_PMIA) { // v1.15 3B PMI/GD&T const auto okuLink2 = [](Okur& rr) { FikoOlcumLink l; l.var = rr.pod(); l.govde = rr.pod(); l.alt = rr.pod(); l.kip = rr.pod(); l.serbest = rr.pod(); rr.ham(&l.yerel.x, sizeof(f32) * 3); l.kid = rr.pod(); return l; }; const u32 sayi = r.pod(); belge.pmiler.reserve(sayi); for (u32 i = 0; i < sayi && !r.hata; ++i) { FikoPmi q; q.kimlik = r.pod(); q.dugumKimlik = r.pod(); q.ust = r.pod(); q.ad = r.str(); q.tip = r.pod(); q.yerlesim = r.pod(); const u32 hN = r.pod(); q.hedefler.reserve(hN); for (u32 j = 0; j < hN && !r.hata; ++j) q.hedefler.push_back(okuLink2(r)); r.ham(&q.ofsetYerel.x, sizeof(f32) * 3); r.ham(&q.duzlemNormal.x, sizeof(f32) * 3); r.ham(&q.duzlemSag.x, sizeof(f32) * 3); q.liderVar = r.pod(); q.goster = r.pod(); q.gorselOran = r.pod(); q.gdtSatirSayi = r.pod(); for (int j = 0; j < 2; ++j) { FikoPmiGdtSatir& g = q.gdt[j]; g.karakter = r.pod(); g.tolerans = r.pod(); g.capsal = r.pod(); g.kosul = r.pod(); g.projeksiyonlu = r.pod(); g.projeksiyonUzunluk = r.pod(); r.ham(g.datum, 3); r.ham(g.datumKosul, 3); } q.datumHarf = (char)r.pod(); q.metin = r.str(); const u32 oN = r.pod(); for (u32 j = 0; j < oN && !r.hata; ++j) { std::string a2 = r.str(); std::string d2 = r.str(); q.ozelAlanlar.emplace_back(std::move(a2), std::move(d2)); } r.ham(&q.renk.x, sizeof(f32) * 3); q.yaziBoyu = r.pod(); q.cizgiKalinlik = r.pod(); q.sembolOlcek = r.pod(); q.alfa = r.pod(); belge.pmiler.push_back(std::move(q)); } } // Tanınmayan etiket → atla (o zaten diskBoyut ilerletildi = ileri-uyumluluk). if (r.hata) { hata = "Bozuk .fikocad (chunk verisi kesildi)"; return false; } } if (!metaVar) { hata = "Bozuk .fikocad (META chunk yok)"; return false; } if (ilerle) ilerle(0.9f, "Ayrıştırıldı"); return true; } // ---- Sahne düzeyi ----------------------------------------------------------- // ANA-THREAD snapshot: Sahne + kamera → FikoBelge. govdeBaytYaz (OCCT BinTools // serialize) burada calisir → tutarli/atomik goruntu; sonra worker sadece POD // paket + deflate + disk yazar (saf std::string isi). // OlcumBaglanti (sahne) → FikoOlcumLink (io) — govde Varlik aynen (yüklemede remap edilir). static FikoOlcumLink linkCikar(const OlcumBaglanti& l) { FikoOlcumLink f; f.var = l.var ? 1 : 0; f.govde = l.govde; f.alt = l.alt; f.kip = (u8)l.kip; f.serbest = l.serbest ? 1 : 0; f.yerel = l.yerel; f.kid = l.kid; // KYA kalıcı kimlik → save/load sonrası da edit-dayanıklı link return f; } FikoBelge belgeCikar(const Sahne& sahne, const OrbitKamera& kamera, const parca::PartDesignSistemi* partD, bool brepErtele, const OlcumSistemi* olcum, const PmiSistemi* pmiSis) { FikoBelge belge; // Kamera const Quatf q = kamera.yonelim(); belge.kamera.yonelim[0] = q.x; belge.kamera.yonelim[1] = q.y; belge.kamera.yonelim[2] = q.z; belge.kamera.yonelim[3] = q.w; const Vec3f od = kamera.odak(); belge.kamera.odak[0] = od.x; belge.kamera.odak[1] = od.y; belge.kamera.odak[2] = od.z; belge.kamera.mesafe = kamera.mesafe(); belge.kamera.fovDeg = kamera.gorusAcisiDeg(); belge.kamera.ortografik = kamera.ortografik() ? 1 : 0; belge.kamera.orbitHassas = kamera.orbitHassasiyet(); belge.kamera.panHassas = kamera.panHassasiyet(); belge.kamera.zoomOran = kamera.zoomOran(); belge.kamera.yumusatma = kamera.yumusatma(); // CATIA çoklu-PartBody: body grup Varlik'leri + In Work Object (yüklemede harita ile remap). belge.bodyler = sahne.bodyler(); belge.aktifBody = sahne.aktifBody(); const Dunya& d = sahne.dunya(); // Gruplar: AdBilesen var + Dugum yok → GrupNesnesi (folder). "Origin" atlanır // (yeni belgede otomatik kurulur). for (auto [v, ad] : d.depo()) { if (d.var(v)) continue; if (ad.ad == "Origin") continue; FikoGrup g; g.kimlik = v; if (const HiyerarsiBilesen* h = d.bul(v)) g.ust = h->ust; if (const GorunurBilesen* gv = d.bul(v)) g.gorunur = gv->gorunur ? 1 : 0; if (const GrupRenkBilesen* rr = d.bul(v)) { g.renkVar = 1; g.renk = rr->renk; } g.ad = ad.ad; belge.gruplar.push_back(std::move(g)); } // Düğümler: yalnız katı gövdeler (tip 0..Ithal) + geçerli B-rep. for (const Dugum& n : d.depo().yogun()) { // Katı gövdeler (0..Ithal) + GSD Tel/Yüzey (gerçek OCCT wire/shell brep) serileşir; // datum/Sketch/EksenSistemi/CAM atlanır (kendi yolunda kurulur/yeniden hesaplanır). if ((int)n.tip > (int)DugumTip::Ithal && n.tip != DugumTip::Tel && n.tip != DugumTip::Yuzey) continue; if (!n.brep || !n.brep->gecerliMi()) continue; // brepErtele=true → ağır BinTools serialize'ı worker'a ertele (yalnız handle al). std::string bayt; if (!brepErtele) { bayt = geometri::govdeBaytYaz(*n.brep); if (bayt.empty()) continue; // serileşemedi → atla (çökme yok) } FikoDugum fd; fd.kimlik = n.kimlik; if (const HiyerarsiBilesen* h = d.bul(n.kimlik)) fd.ust = h->ust; fd.tip = (u8)n.tip; fd.gorunur = n.gorunur ? 1 : 0; fd.renk = n.renk; fd.saydamlik = n.saydamlik; fd.gorselOran = n.gorselOran; fd.p1 = n.p1; fd.p2 = n.p2; fd.p3 = n.p3; fd.aciZDerece = n.aciZDerece; fd.konum[0] = n.donusum.konum.x; fd.konum[1] = n.donusum.konum.y; fd.konum[2] = n.donusum.konum.z; fd.yonelim[0] = n.donusum.yonelim.x; fd.yonelim[1] = n.donusum.yonelim.y; fd.yonelim[2] = n.donusum.yonelim.z; fd.yonelim[3] = n.donusum.yonelim.w; fd.olcek[0] = n.donusum.olcek.x; fd.olcek[1] = n.donusum.olcek.y; fd.olcek[2] = n.donusum.olcek.z; fd.ad = n.ad; if (brepErtele) fd.canliBrep = n.brep; // shared_ptr snapshot → worker serialize eder else fd.brep = std::move(bayt); // Per-yüz renk (BinTools taşımaz → ayrı sakla). ÖNCE brep->yuzRenkleri; boşsa // CANLI mesh'ten türet (cpuRenk = render'ın kullandığı per-vertex renk, cpuAlt = // yüz ordinali). İçe aktarım deep-copy'si (brep_io govdeDerinKopya) brep // yuzRenkleri'yi sıyırabildiğinden ekrandaki gerçek renk yalnız mesh'te olabilir. fd.yuzRenkleri = perYuzRenkTuret(n); // KYA kalıcı kimlik (v1.13): brep etiketleri ayrı sakla (BinTools taşımaz). Etiketli değilse boş. if (n.brep && n.brep->kimlikliMi()) { fd.yuzKid = n.brep->yuzKimlikleri(); fd.kenarKid = n.brep->kenarKimlikleri(); fd.noktaKid = n.brep->noktaKimlikleri(); } belge.dugumler.push_back(std::move(fd)); // Per-öğe görsel override'ları (yüz/kenar/nokta) — alfa/görünür/stil, sadece renk değil // (v1.6 OGOZ). Yalnız override edilmiş ordinaller (seyrek) → saydam/gizli öğe korunur. const auto ogeTopla = [](const std::unordered_map& m, std::vector& out) { out.reserve(m.size()); for (const auto& [ord, o] : m) { FikoOgeOz f; f.ord = ord; f.renk = o.renk; f.alfa = o.alfa; f.gorunur = o.gorunur ? 1 : 0; f.stil = (u8)o.stil; f.kalinlik = o.kalinlik; f.noktaBoyut = o.noktaBoyut; f.sekil = (u8)o.sekil; f.metalik = o.metalik; f.puruz = o.puruz; out.push_back(f); } }; FikoDugumOz oz; oz.dugum = n.kimlik; ogeTopla(n.yuzOz, oz.yuz); ogeTopla(n.kenarOz, oz.kenar); ogeTopla(n.noktaOz, oz.nokta); // Gövde-seviye öğe varsayılanları tip-varsayılanından farklıysa kaydet (v1.9). if (n.yuzVars != ogeVarsayilan(OgeTip::Yuz) || n.kenarVars != ogeVarsayilan(OgeTip::Kenar) || n.noktaVars != ogeVarsayilan(OgeTip::Nokta)) { const auto ogeCevir = [](const OgeOzellik& o) { FikoOgeOz f; f.renk = o.renk; f.alfa = o.alfa; f.gorunur = o.gorunur ? 1 : 0; f.stil = (u8)o.stil; f.kalinlik = o.kalinlik; f.noktaBoyut = o.noktaBoyut; f.sekil = (u8)o.sekil; f.metalik = o.metalik; f.puruz = o.puruz; return f; }; oz.varsVar = 1; oz.yuzVars = ogeCevir(n.yuzVars); oz.kenarVars = ogeCevir(n.kenarVars); oz.noktaVars = ogeCevir(n.noktaVars); } if (!oz.yuz.empty() || !oz.kenar.empty() || !oz.nokta.empty() || oz.varsVar) belge.ogeOzellikleri.push_back(std::move(oz)); } // Global parametreler (CATIA Parameters): ad/ifade/birim/deger — formül metni dahil. for (auto [v, kok] : d.depo()) { if (!kok) continue; if (const auto* pn = dynamic_cast(kok.get())) { FikoParametre pr; pr.ad = pn->ad(); pr.ifade = pn->ifade(); pr.birim = pn->birim(); pr.deger = pn->deger(); belge.parametreler.push_back(std::move(pr)); } } // Parametrik SKETCH'ler (SketchNesnesi): düzlem dünya-dönüşümü + EskizVeri seri baytları. // Self-contained (düzlem transform sketch ile taşınır → yüklemede origin düzlemine remap // gerekmez). Feature'ın ön koşulu; feature yoksa da (serbest sketch) korunur. for (auto [v, kok] : d.depo()) { if (!kok) continue; const auto* sk = dynamic_cast(kok.get()); if (!sk) continue; FikoSketch fs; fs.kimlik = v; if (const HiyerarsiBilesen* h = d.bul(v)) fs.ust = h->ust; if (const Dugum* sd = sahne.bul(v)) fs.ad = sd->ad; if (const Dugum* dz = sahne.bul(sk->duzlem())) { fs.duzlemKonum[0] = dz->donusum.konum.x; fs.duzlemKonum[1] = dz->donusum.konum.y; fs.duzlemKonum[2] = dz->donusum.konum.z; fs.duzlemYon[0] = dz->donusum.yonelim.x; fs.duzlemYon[1] = dz->donusum.yonelim.y; fs.duzlemYon[2] = dz->donusum.yonelim.z; fs.duzlemYon[3] = dz->donusum.yonelim.w; fs.duzlemOlcek[0] = dz->donusum.olcek.x; fs.duzlemOlcek[1] = dz->donusum.olcek.y; fs.duzlemOlcek[2] = dz->donusum.olcek.z; } sk->eskiz().disaAktar(fs.eskiz); belge.sketchler.push_back(std::move(fs)); } // Part Design FEATURE ağacı (partD verildiyse): tip/ad/referanslar + param + formül + durum. if (partD) { for (const parca::PartDesignSistemi::FeatureKalici& k : partD->kaliciCikar()) { FikoFeature ff; ff.kimlik = k.kimlik; ff.tip = k.tip; ff.ad = k.ad; ff.sketch = k.sketch; ff.hedefDugum = k.hedefDugum; ff.sonucDugum = k.sonucDugum; ff.bastirildi = k.bastirildi ? 1 : 0; ff.kilitli = k.kilitli ? 1 : 0; for (const auto& [a, dv] : k.parametreler) ff.parametreler.emplace_back(a, dv); for (const auto& [a, i] : k.formuller) ff.formuller.emplace_back(a, i); ff.uretilenYuzler = k.uretilenYuzler; ff.yuzGeriHarita.assign(k.yuzGeriHarita.begin(), k.yuzGeriHarita.end()); belge.featureler.push_back(std::move(ff)); } } // CATIA Reference Elements (datum Nokta/Çizgi/Düzlem): YALNIZ "Referans" geometrik seti // altındakiler serileşir → origin L-köşe düzlemleri, yüz düzlemleri ve sketch düzlemleri // (SKCH kendi self-contained kurar) hariç kalır (çift-oluşturma yok). refGrup yoksa (0) // hiç referans datum yok demektir → atlanır. const u32 refG = sahne.refGrupKimlik(); if (refG != 0) { for (const Dugum& n : d.depo().yogun()) { if (n.tip != DugumTip::Nokta && n.tip != DugumTip::Cizgi && n.tip != DugumTip::Duzlem) continue; const HiyerarsiBilesen* h = d.bul(n.kimlik); if (!h || h->ust != refG) continue; // yalnız Referans setindeki datumlar FikoDatum dt; dt.kimlik = n.kimlik; dt.ust = h->ust; dt.tip = (u8)n.tip; dt.gorunur = n.gorunur ? 1 : 0; dt.renk = n.renk; dt.gorselOran = n.gorselOran; dt.konum[0] = n.donusum.konum.x; dt.konum[1] = n.donusum.konum.y; dt.konum[2] = n.donusum.konum.z; if (n.tip == DugumTip::Cizgi) { // İkinci uç = yerel uç noktasının (cpuKenar[1]) dünya konumu (p0 + delta). Vec3d p1 = n.donusum.konum; if (n.cpuKenar.size() >= 2) p1 = n.donusum.noktaUygula( {(f64)n.cpuKenar[1].x, (f64)n.cpuKenar[1].y, (f64)n.cpuKenar[1].z}); dt.yon[0] = p1.x; dt.yon[1] = p1.y; dt.yon[2] = p1.z; } else if (n.tip == DugumTip::Duzlem) { const Vec3d nrm = n.donusum.yonelim.dondur({0, 0, 1}); // dünya normali (yerel +Z) dt.yon[0] = nrm.x; dt.yon[1] = nrm.y; dt.yon[2] = nrm.z; } // Parametrik tanım (ofset düzlem): kaynak taban düzlem Varlik + mesafe. if (const Sahne::DatumTanim* t = sahne.datumTanim(n.kimlik); t && t->tip == Sahne::DatumTanim::OfsetDuzlem) { dt.tanimTip = 1; dt.kaynak = t->kaynak; dt.mesafe = t->mesafe; } dt.ad = n.ad; belge.datumlar.push_back(std::move(dt)); } } // ÖLÇÜMLER (Kumpas/Cetvel + zincirler) — v1.7 OLCM. Yalnız kaynak link + kullanıcı // özelleştirmesi (ofset/açı/uzatma/mod); değer/metin/geometri yüklemede yeniden türetilir. if (olcum) { for (const Olcum& o : olcum->hepsi()) { FikoOlcum fo; fo.kimlik = o.kimlik; fo.tur = (u8)o.tur; fo.mod1 = (u8)o.mod1; fo.mod2 = (u8)o.mod2; fo.k1 = linkCikar(o.k1); fo.k2 = linkCikar(o.k2); fo.ofset = o.ofset; fo.aci = o.aci; fo.uzatma1 = o.uzatma1; fo.uzatma2 = o.uzatma2; fo.taban1 = o.taban1; fo.taban2 = o.taban2; belge.olcumler.push_back(std::move(fo)); } for (const OlcumZincir& z : olcum->zincirler()) { FikoOlcumZincir fz; fz.kimlik = z.kimlik; fz.kapali = z.kapali ? 1 : 0; fz.noktalar.reserve(z.noktalar.size()); for (const OlcumBaglanti& l : z.noktalar) fz.noktalar.push_back(linkCikar(l)); belge.olcumZincirleri.push_back(std::move(fz)); } } // PMI (3B GD&T) — v1.15 PMIA. Defter + düğüm meta; capa/surum önbelleği YAZILMAZ. if (pmiSis) { // Düğüm eşlemesi: DugumTip::Pmi düğümlerinden pmiKimlik → (Varlik, ust, ad). for (const Dugum& dg : const_cast(sahne).dugumler()) { if (dg.tip != DugumTip::Pmi) continue; const NesneKok* nk = d.bul(dg.kimlik); const auto* pn = (nk && *nk) ? dynamic_cast(nk->get()) : nullptr; if (!pn) continue; const pmi::PmiOge* o = pmiSis->defter().bul(pn->pmiKimlik()); if (!o) continue; FikoPmi q; q.kimlik = o->kimlik; q.dugumKimlik = dg.kimlik; if (const HiyerarsiBilesen* h = d.bul(dg.kimlik)) q.ust = h->ust; q.ad = dg.ad; q.tip = (u8)o->tip; q.yerlesim = (u8)o->yerlesim; for (const pmi::PmiHedef& h2 : o->hedefler) { FikoOlcumLink l; l.var = h2.govde != 0; l.govde = h2.govde; l.alt = h2.alt; l.kip = h2.kip; l.kid = h2.kid; q.hedefler.push_back(l); } q.ofsetYerel = o->ofsetYerel; q.duzlemNormal = o->duzlemNormal; q.duzlemSag = o->duzlemSag; q.liderVar = o->liderVar ? 1 : 0; q.goster = o->goster ? 1 : 0; q.gorselOran = o->gorselOran; q.gdtSatirSayi = o->gdtSatirSayi; for (int i = 0; i < 2; ++i) { const pmi::GdtSatir& g = o->gdt[i]; FikoPmiGdtSatir& fg = q.gdt[i]; fg.karakter = (u8)g.karakter; fg.tolerans = g.tolerans; fg.capsal = g.capsal ? 1 : 0; fg.kosul = (u8)g.kosul; fg.projeksiyonlu = g.projeksiyonlu ? 1 : 0; fg.projeksiyonUzunluk = g.projeksiyonUzunluk; for (int j = 0; j < 3; ++j) { fg.datum[j] = g.datum[j]; fg.datumKosul[j] = (u8)g.datumKosul[j]; } } q.datumHarf = o->datumHarf; q.metin = o->metin; q.ozelAlanlar = o->ozelAlanlar; q.renk = o->stil.renk; q.yaziBoyu = o->stil.yaziBoyu; q.cizgiKalinlik = o->stil.cizgiKalinlik; q.sembolOlcek = o->stil.sembolOlcek; q.alfa = o->stil.alfa; belge.pmiler.push_back(std::move(q)); } } // PAFTALAR (teknik resim) — v1.15 PFTA. Yalnız veri; çizim önbelleği YAZILMAZ. for (const Dugum& dg : const_cast(sahne).dugumler()) { if (dg.tip != DugumTip::Pafta) continue; const pafta::Pafta* pv = paftaVerisi(const_cast(d), dg.kimlik); if (!pv) continue; FikoPafta fp; fp.kimlik = dg.kimlik; if (const HiyerarsiBilesen* h = d.bul(dg.kimlik)) fp.ust = h->ust; fp.ad = dg.ad; fp.sayfa = (u8)pv->sayfa; fp.ozelEn = pv->ozelOlcu.en; fp.ozelBoy = pv->ozelOlcu.boy; fp.olcekPay = pv->olcek.pay; fp.olcekPayda = pv->olcek.payda; fp.antetGoster = pv->antet.goster ? 1 : 0; fp.antetEn = pv->antet.en; fp.antetBoy = pv->antet.boy; fp.proje = pv->antet.proje; fp.parca = pv->antet.parca; fp.cizen = pv->antet.cizen; fp.tarih = pv->antet.tarih; fp.malzeme = pv->antet.malzeme; fp.revizyon = pv->antet.revizyon; fp.aciklama = pv->antet.aciklama; for (const pafta::Gorunum& g : pv->gorunumler()) { FikoPaftaGorunum fg; fg.kimlik = g.kimlik; fg.kaynak = g.kaynak; fg.ust = g.ust; fg.yon = (u8)g.yon; fg.hiza = (u8)g.hiza; fg.olcekMiras = g.olcekMiras ? 1 : 0; fg.gizliCizgi = g.gizliCizgi ? 1 : 0; fg.goster = g.goster ? 1 : 0; fg.olcekPay = g.olcek.pay; fg.olcekPayda = g.olcek.payda; fg.konum[0] = g.konum.x; fg.konum[1] = g.konum.y; fg.boyut[0] = g.boyut.x; fg.boyut[1] = g.boyut.y; fg.ad = g.ad; fg.kesitMi = g.kesitMi ? 1 : 0; fg.taramaGoster = g.taramaGoster ? 1 : 0; fg.kesitAnaGorunum = g.kesitAnaGorunum; fg.kesitA[0] = g.kesitA.x; fg.kesitA[1] = g.kesitA.y; fg.kesitB[0] = g.kesitB.x; fg.kesitB[1] = g.kesitB.y; fg.kesitHarf = g.kesitHarf; fg.detayMi = g.detayMi ? 1 : 0; fg.detayAnaGorunum = g.detayAnaGorunum; fg.detayMerkez[0] = g.detayMerkez.x; fg.detayMerkez[1] = g.detayMerkez.y; fg.detayYaricap = g.detayYaricap; fg.detayHarf = g.detayHarf; fg.pmiGoster = g.pmiGoster ? 1 : 0; fp.gorunumler.push_back(std::move(fg)); } for (const pafta::Olcu& o : pv->olculer()) { FikoPaftaOlcu fo; fo.kimlik = o.kimlik; fo.gorunum = o.gorunum; fo.tip = (u8)o.tip; fo.otoDeger = o.otoDeger ? 1 : 0; fo.goster = o.goster ? 1 : 0; fo.p1[0] = o.p1.x; fo.p1[1] = o.p1.y; fo.p2[0] = o.p2.x; fo.p2[1] = o.p2.y; fo.tepe[0] = o.tepe.x; fo.tepe[1] = o.tepe.y; fo.ofset = o.ofset; fo.elleDeger = o.elleDeger; fo.onEk = o.onEk; fo.sonEk = o.sonEk; fp.olculer.push_back(std::move(fo)); } belge.paftalar.push_back(std::move(fp)); } return belge; } // WORKER: brepErtele ile snapshot'lanan canlı gövdeleri PARALEL BinTools serialize eder. // Farklı bağımsız TopoDS_Shape'lerin salt-okunur BinTools::Write'ı thread-güvenli // (her çağrı kendi ShapeSet'ini kurar); shared_ptr snapshot değişmez → sahne eşzamanlı // düzenlense de tutarlı. Serileşemeyen (boş) düğümler elenir. bool belgeBrepSerilestir(FikoBelge& belge, const Ilerleme& ilerle, const std::function& iptal) { const size_t toplam = belge.dugumler.size(); std::atomic kuyruk{0}, biten{0}; std::atomic durduruldu{false}; const auto isci = [&] { for (;;) { const size_t i = kuyruk.fetch_add(1); if (i >= toplam || durduruldu.load(std::memory_order_relaxed)) return; if (iptal && iptal()) { durduruldu.store(true); return; } FikoDugum& fd = belge.dugumler[i]; if (fd.canliBrep && fd.canliBrep->gecerliMi()) fd.brep = geometri::govdeBaytYaz(*fd.canliBrep); // AĞIR (saf CPU, salt-okunur) fd.canliBrep.reset(); const size_t b = biten.fetch_add(1) + 1; if (ilerle && toplam) ilerle(0.05f + 0.35f * (f32)b / (f32)toplam, "Gövdeler serileştiriliyor (paralel)"); } }; const unsigned isciSayi = std::min( std::max(1u, std::thread::hardware_concurrency() - 1u), (unsigned)std::max(toplam, 1)); if (isciSayi > 1 && toplam > 1) { std::vector isciler; isciler.reserve(isciSayi); for (unsigned t = 0; t < isciSayi; ++t) isciler.emplace_back(isci); for (auto& t : isciler) t.join(); } else { isci(); } if (durduruldu.load()) return false; // Serileşemeyen (boş brep) düğümleri ele — inline yolun "atla" davranışıyla eş. belge.dugumler.erase( std::remove_if(belge.dugumler.begin(), belge.dugumler.end(), [](const FikoDugum& d) { return d.brep.empty(); }), belge.dugumler.end()); return true; } // Atomik yazma (geçici dosya + rename → yarım dosya asla geçerli sayılmaz). // Saf disk işi → worker thread'te güvenli. İptal/hata → hedef dokunulmaz. bool dosyayaYaz(const std::string& yol, const std::string& veri, std::string& hata) { const std::string gecici = yol + ".tmp"; { std::ofstream f(gecici, std::ios::binary | std::ios::trunc); if (!f) { hata = "Dosya yazılamadı: " + yol; return false; } f.write(veri.data(), (std::streamsize)veri.size()); f.flush(); // güç kesintisine karşı: rename öncesi tampon boşalt if (!f) { hata = "Dosya yazma hatası: " + yol; return false; } } std::remove(yol.c_str()); // varsa hedefi kaldır (Windows rename üstüne yazmaz) if (std::rename(gecici.c_str(), yol.c_str()) != 0) { std::remove(gecici.c_str()); hata = "Dosya adlandırılamadı: " + yol; return false; } return true; } bool fikoKaydet(const Sahne& sahne, const OrbitKamera& kamera, const std::string& yol, std::string& hata) { const FikoBelge belge = belgeCikar(sahne, kamera); // snapshot (ana-thread) std::string veri; if (!fikoYaz(belge, veri, hata)) return false; if (!dosyayaYaz(yol, veri, hata)) return false; gunluk::bilgi(".fikocad kaydedildi: {} ({} grup, {} gövde, {} bayt)", yol, belge.gruplar.size(), belge.dugumler.size(), veri.size()); return true; } // WORKER (saf CPU, Vulkan/Sahne YOK): FikoBelge → mesh'li HazirYukleme. // govdeBaytOku (BinTools deserialize) + per-yuz renk + ucgenle/kenarMesh/noktaMesh // (ASIL donma kaynagi buydu → artik worker'da). GPU/sahne'ye HIC dokunmaz. bool belgeCoz(const FikoBelge& belge, HazirYukleme& cikti, const Ilerleme& ilerle, const std::function& iptal) { cikti.kamera = belge.kamera; cikti.gruplar = belge.gruplar; cikti.parametreler = belge.parametreler; // saf veri (belgeUygula sahneye kurar) cikti.sketchler = belge.sketchler; // saf veri (belgeUygula düzlem+sketch kurar) cikti.featureler = belge.featureler; // saf veri (belgeUygula feature ağacı kurar) cikti.datumlar = belge.datumlar; // saf veri (belgeUygula referans datumları kurar) cikti.ogeOzellikleri = belge.ogeOzellikleri; // saf veri (belgeUygula remap + ogeRenkYenile) cikti.olcumler = belge.olcumler; // saf veri (belgeUygula remap + olcumEkle) cikti.paftalar = belge.paftalar; // saf veri (belgeUygula pafta düğümü kurar) cikti.pmiler = belge.pmiler; // saf veri (belgeUygula PMI kurar) cikti.uzuvlar = belge.uzuvlar; // saf veri (kinematik; çağıran çevirir) cikti.mafsallar = belge.mafsallar; cikti.yasalar = belge.yasalar; cikti.caeKurulumlar = belge.caeKurulumlar; // v1.19 CAEK (çağıran düğümü remap eder) cikti.malzemeler = belge.malzemeler; // saf veri (cagiran kutuphaneye kurar) cikti.malzemeAtamalari = belge.malzemeAtamalari; // saf veri (cagiran remap edip atar) cikti.bodyler = belge.bodyler; // body grupları (belgeUygula remap + bodyKaydet) cikti.aktifBody = belge.aktifBody; // In Work Object (belgeUygula remap + aktifBodyAyarla) cikti.olcumZincirleri = belge.olcumZincirleri; cikti.dugumler.clear(); cikti.dugumler.reserve(belge.dugumler.size()); const size_t toplam = belge.dugumler.size(); // FAZ 1 — SERİ deserialize (ucuz): her düğüm BAĞIMSIZ BinTools akışından çözülür // (STEP'in aksine düğümler-arası paylaşımlı Geom YOK → derin kopya gereksiz). // Gövdeyi + rengi + per-yüz rengi hazırla; ağ üretimini FAZ 2'ye ertele. for (const FikoDugum& fd : belge.dugumler) { if (iptal && iptal()) return false; // iptal → erken cikar (finalize kurmaz) geometri::BrepGovde govde = geometri::govdeBaytOku(fd.brep); if (!govde.gecerliMi()) { gunluk::uyari(".fikocad: geçersiz B-rep atlandı ({})", fd.ad); continue; } // Per-yüz renkleri ucgenle'den ÖNCE ata → mesh yüzleri kendi rengiyle boyanır // (BinTools bunu taşımaz, ayrı chunk'tan gelir). if (!fd.yuzRenkleri.empty()) govde.yuzRenkleriAta(fd.yuzRenkleri); // KYA kalıcı kimlik geri yükle (v1.13): etiketler brep'e döner → aynı yüz string ile seçilebilir. if (!fd.yuzKid.empty() || !fd.kenarKid.empty() || !fd.noktaKid.empty()) govde.kimlikleriYukle(fd.yuzKid, fd.kenarKid, fd.noktaKid); HazirDugumYukle h; h.meta = fd; h.meta.brep.clear(); // govde ig'de → brep string tekrar tutulmaz h.meta.yuzRenkleri.clear(); h.ig.govde = std::move(govde); h.ig.renk = fd.renk; h.ig.renkVar = true; cikti.dugumler.push_back(std::move(h)); } if (ilerle) ilerle(0.15f, "Ağ üretiliyor"); // FAZ 2 — gövdeler-arası PARALEL tessellation (STEP import kalıbı). Her düğümün // gövdesi özel/bağımsız olduğundan iş-çalma kuyruğu ile güvenli. ucgenle/kenar/nokta // saf CPU; GPU/sahne temas yok (belgeUygula ana-thread'e ertelenmiş). const size_t n = cikti.dugumler.size(); std::atomic kuyruk{0}, biten{0}; std::atomic durduruldu{false}; const auto isci = [&] { for (;;) { const size_t i = kuyruk.fetch_add(1); if (i >= n || durduruldu.load(std::memory_order_relaxed)) return; if (iptal && iptal()) { durduruldu.store(true); return; } HazirDugumYukle& h = cikti.dugumler[i]; const Vec3f renk = h.ig.renk; h.yuzey = h.ig.govde.ucgenle(renk); // AĞIR (saf CPU) h.kenar = h.ig.govde.kenarMesh(); h.nokta = h.ig.govde.noktaMesh(); const size_t b = biten.fetch_add(1) + 1; if (ilerle && toplam) ilerle(0.15f + 0.8f * (f32)b / (f32)toplam, "Ağ üretiliyor (paralel)"); } }; const unsigned isciSayi = std::min( std::max(1u, std::thread::hardware_concurrency() - 1u), (unsigned)std::max(n, 1)); if (isciSayi > 1 && n > 1) { std::vector isciler; isciler.reserve(isciSayi); for (unsigned t = 0; t < isciSayi; ++t) isciler.emplace_back(isci); for (auto& t : isciler) t.join(); } else { isci(); // tek gövde / tek çekirdek → seri } return !durduruldu.load(); } // ANA-THREAD finalize: HazirYukleme → Sahne (grup + üst bağ + toplu GPU yükleme + // kamera). GPU teması yalnız burada (Vulkan tek-thread güvenliği). void belgeUygula(Sahne& sahne, OrbitKamera& kamera, HazirYukleme& hazir, parca::PartDesignSistemi* partD, OlcumSistemi* olcum, PmiSistemi* pmiSis, std::unordered_map* dugumHarita) { // eski Varlik → yeni Varlik haritası (grup + düğüm + sketch remap; feature referansları). std::unordered_map harita; // 1) Grupları oluştur (parent henüz köke; 2. geçişte bağlanır). for (const FikoGrup& g : hazir.gruplar) { const Varlik yeni = sahne.grupEkle(g.ad, VARLIK_YOK); harita[g.kimlik] = yeni; if (!g.gorunur) sahne.dunya().ekle(yeni, GorunurBilesen{false}); if (g.renkVar) sahne.dunya().ekle(yeni, GrupRenkBilesen{g.renk}); // v1.12 renk-kodu } // 2) Grup üst bağlarını çöz. for (const FikoGrup& g : hazir.gruplar) { if (g.ust == 0) continue; auto it = harita.find(g.ust); if (it != harita.end()) sahne.ustAyarla(harita[g.kimlik], it->second); } // 2b) CATIA body kaydı: kaydedilmiş body grupları (eski Varlik) → harita → bodyKaydet (canlı ise). // Graceful: harita/canlılık başarısızsa body atlanır (çökme/bozulma yok). aktifBody da remap. for (u32 eski : hazir.bodyler) { auto it = harita.find(eski); if (it != harita.end() && sahne.dunya().yasiyor(it->second)) sahne.bodyKaydet(it->second); } if (hazir.aktifBody) { auto it = harita.find(hazir.aktifBody); if (it != harita.end() && sahne.dunya().yasiyor(it->second)) sahne.aktifBodyAyarla(it->second); } // 3) Düğümleri kur (toplu GPU yükleme oturumu — TEK submit + fence). sahne.vulkan().bekle(); sahne.vulkan().topluYuklemeBasla(); for (HazirDugumYukle& h : hazir.dugumler) { Varlik ust = VARLIK_YOK; if (h.meta.ust != 0) { auto it = harita.find(h.meta.ust); if (it != harita.end()) ust = it->second; } Dugum& d = sahne.ithalEkleHazir(std::move(h.ig), std::move(h.yuzey), std::move(h.kenar), std::move(h.nokta), ust); harita[h.meta.kimlik] = d.kimlik; // düğüm eski→yeni (feature hedef/sonuç remap) // Kaydedilmiş öz nitelikleri geri uygula. d.tip = (DugumTip)h.meta.tip; d.ad = h.meta.ad; d.gorunur = h.meta.gorunur != 0; d.renk = h.meta.renk; d.saydamlik = h.meta.saydamlik; d.gorselOran = h.meta.gorselOran; d.p1 = h.meta.p1; d.p2 = h.meta.p2; d.p3 = h.meta.p3; d.aciZDerece = h.meta.aciZDerece; d.donusum.konum = {h.meta.konum[0], h.meta.konum[1], h.meta.konum[2]}; d.donusum.yonelim = {h.meta.yonelim[0], h.meta.yonelim[1], h.meta.yonelim[2], h.meta.yonelim[3]}; d.donusum.olcek = {h.meta.olcek[0], h.meta.olcek[1], h.meta.olcek[2]}; } sahne.vulkan().topluYuklemeBitir(); // 3b) Global parametreleri kur: parametreEkle (ad/deger/birim) + ifade (formül) geri // yaz, sonunda TEK parametreleriCoz → tüm formüller topolojik çözülür. HAM ifadeAyarla // özyineleme yapmaz (senkron cb'yi parametreEkle bağladı). for (const FikoParametre& pr : hazir.parametreler) { const u32 v = sahne.parametreEkle(pr.ad, pr.deger, pr.birim); if (NesneKok* kok = sahne.dunya().bul(v)) if (auto* pn = dynamic_cast(kok->get())) pn->ifadeAyarla(pr.ifade); } if (!hazir.parametreler.empty()) sahne.parametreleriCoz(); // 3c) Parametrik SKETCH'ler: her sketch KENDİ düzlemini taşır (self-contained) → düzlem // referans düğümü geri kur + sketch oluştur + EskizVeri'yi yükle. Eski→yeni haritaya // yaz (feature.sketch remap). Bozuk eskiz → iceAktar false, sketch boş kalır (çökme yok). for (const FikoSketch& fs : hazir.sketchler) { Donusumd dz; dz.konum = {fs.duzlemKonum[0], fs.duzlemKonum[1], fs.duzlemKonum[2]}; dz.yonelim = {fs.duzlemYon[0], fs.duzlemYon[1], fs.duzlemYon[2], fs.duzlemYon[3]}; dz.olcek = {fs.duzlemOlcek[0], fs.duzlemOlcek[1], fs.duzlemOlcek[2]}; Varlik ust = sahne.partBodyAl(); if (auto it = harita.find(fs.ust); it != harita.end()) ust = it->second; const Varlik duzlem = sahne.referansDuzlemGeriYukle(dz, "Sketch Düzlemi", ust); const Varlik yeniSketch = sahne.sketchEkle(duzlem); if (NesneKok* nk = sahne.dunya().bul(yeniSketch)) if (auto* sn = dynamic_cast(nk->get())) if (!fs.eskiz.empty()) sn->eskiz().iceAktar(fs.eskiz.data(), fs.eskiz.size()); if (Dugum* sd = sahne.bul(yeniSketch); sd && !fs.ad.empty()) sd->ad = fs.ad; sahne.ustAyarla(yeniSketch, ust); sahne.sketchKenarYenile(yeniSketch); // 2B seçim/render kenarlarını üret harita[fs.kimlik] = yeniSketch; } // 3d) Part Design FEATURE ağacı (partD verildiyse): referansları remap et + kur. recompute // YOK → yüklenmiş sonuç geometrisi korunur (hızlı + çökme yok). Kullanıcı parametre // düzenleyince yenidenInsa taze üretir (sketch/hedef/param hepsi kurulu). Referans // remap edilemezse (harita'da yok) 0 kalır — feature kurulur, düzenlenene dek zarar yok. if (partD && !hazir.featureler.empty()) { const auto remap = [&](u32 eski) -> u32 { if (eski == 0) return 0; auto it = harita.find(eski); return it != harita.end() ? it->second : 0; }; for (const FikoFeature& ff : hazir.featureler) { parca::PartDesignSistemi::FeatureKalici k; k.kimlik = ff.kimlik; k.tip = ff.tip; k.ad = ff.ad; k.sketch = remap(ff.sketch); k.hedefDugum = remap(ff.hedefDugum); k.sonucDugum = remap(ff.sonucDugum); k.bastirildi = ff.bastirildi != 0; k.kilitli = ff.kilitli != 0; for (const auto& [a, dv] : ff.parametreler) k.parametreler[a] = dv; for (const auto& [a, i] : ff.formuller) k.formuller[a] = i; k.uretilenYuzler = ff.uretilenYuzler; k.yuzGeriHarita.assign(ff.yuzGeriHarita.begin(), ff.yuzGeriHarita.end()); partD->kaliciGeriYukle(k); } } // 3e) CATIA Reference Elements (datum Nokta/Çizgi/Düzlem): tipe göre yeniden kur + öz // nitelik + parametrik tanım. Üst grup harita'dan remap edilir (Referans seti TREE'de). // İki geçiş: önce tüm düğümler (kaynak başka datum olabilir → eski→yeni haritası dolsun), // sonra ofset tanımları remap edilip kurulur; en sonda datumRecompute ile taze konum. for (const FikoDatum& dt : hazir.datumlar) { Varlik ust = VARLIK_YOK; if (dt.ust != 0) if (auto it = harita.find(dt.ust); it != harita.end()) ust = it->second; const Vec3d konum{dt.konum[0], dt.konum[1], dt.konum[2]}; Varlik v = VARLIK_YOK; if (dt.tip == (u8)DugumTip::Nokta) { v = sahne.referansNoktaEkle(konum, dt.ad, ust); } else if (dt.tip == (u8)DugumTip::Cizgi) { v = sahne.referansCizgiEkle(konum, {dt.yon[0], dt.yon[1], dt.yon[2]}, dt.ad, ust); } else if (dt.tip == (u8)DugumTip::Duzlem) { v = sahne.referansDuzlemEkle(konum, {dt.yon[0], dt.yon[1], dt.yon[2]}, dt.ad, ust); } if (v == VARLIK_YOK) continue; // dejenere (p0==p1 / normal sıfır) → atla, çökme yok harita[dt.kimlik] = v; if (Dugum* nd = sahne.bul(v)) { nd->gorunur = dt.gorunur != 0; nd->renk = dt.renk; nd->gorselOran = dt.gorselOran; } } bool datumTanimVar = false; for (const FikoDatum& dt : hazir.datumlar) { if (dt.tanimTip != 1) continue; // yalnız parametrik ofset düzlem auto itv = harita.find(dt.kimlik); if (itv == harita.end()) continue; Sahne::DatumTanim t; t.tip = Sahne::DatumTanim::OfsetDuzlem; t.mesafe = dt.mesafe; if (dt.kaynak != 0) if (auto k = harita.find(dt.kaynak); k != harita.end()) t.kaynak = k->second; sahne.datumTanimKur(itv->second, t); datumTanimVar = true; } if (datumTanimVar) sahne.datumRecompute(); // kaynak taşınmışsa ofset düzlemleri tazele // 3f) Per-öğe görsel override'ları (OGOZ v1.6): düğüm remap + yuzOz/kenarOz/noktaOz geri // kur → per-öğe ALFA/GÖRÜNÜR/stil KORUNUR (import brep→yuzOz köprüsünün üstüne yazılır: // kaydedilen gerçek durum kazanır). ogeRenkYenile ile mesh renk/alfa GPU'ya tazelenir. for (const FikoDugumOz& oz : hazir.ogeOzellikleri) { auto it = harita.find(oz.dugum); if (it == harita.end()) continue; Dugum* d = sahne.bul(it->second); if (!d) continue; const auto uygula = [](const std::vector& src, std::unordered_map& dst) { for (const FikoOgeOz& f : src) { OgeOzellik o; o.renk = f.renk; o.alfa = f.alfa; o.gorunur = f.gorunur != 0; o.stil = (KenarStil)f.stil; o.kalinlik = f.kalinlik; o.noktaBoyut = f.noktaBoyut; o.sekil = (NoktaSekil)f.sekil; o.metalik = f.metalik; o.puruz = f.puruz; dst[f.ord] = o; } }; uygula(oz.yuz, d->yuzOz); uygula(oz.kenar, d->kenarOz); uygula(oz.nokta, d->noktaOz); if (oz.varsVar) { // gövde-seviye öğe varsayılanları (v1.9) const auto ozCevir = [](const FikoOgeOz& f) { OgeOzellik o; o.renk = f.renk; o.alfa = f.alfa; o.gorunur = f.gorunur != 0; o.stil = (KenarStil)f.stil; o.kalinlik = f.kalinlik; o.noktaBoyut = f.noktaBoyut; o.sekil = (NoktaSekil)f.sekil; o.metalik = f.metalik; o.puruz = f.puruz; return o; }; d->yuzVars = ozCevir(oz.yuzVars); d->kenarVars = ozCevir(oz.kenarVars); d->noktaVars = ozCevir(oz.noktaVars); } if (!oz.yuz.empty()) sahne.ogeRenkYenile(*d); // yüz renk/alfa mesh → GPU tazele } // 3g) ÖLÇÜMLER (OLCM v1.7): kaynak link govde'lerini remap et + olcumEkle/zincirEkle ile // kur (değer/metin/geometri canlı brep'ten yeniden türetilir; ofset/açı/mod korunur). if (olcum) { const auto linkKur = [&](const FikoOlcumLink& f) { OlcumBaglanti l; l.var = f.var != 0; if (auto it = harita.find(f.govde); it != harita.end()) l.govde = it->second; else l.govde = f.govde; // remap yoksa (grup/ham) aynen — refCoz zaten geçersizse çizmez l.alt = f.alt; l.kip = (SecimKip)f.kip; l.serbest = f.serbest != 0; l.yerel = f.yerel; l.kid = f.kid; // KYA kalıcı kimlik geri yükle return l; }; for (const FikoOlcum& fo : hazir.olcumler) { Olcum o; o.kimlik = fo.kimlik; o.tur = (OlcumTur)fo.tur; o.mod1 = (MesafeModu)fo.mod1; o.mod2 = (MesafeModu)fo.mod2; o.k1 = linkKur(fo.k1); o.k2 = linkKur(fo.k2); o.ofset = fo.ofset; o.aci = fo.aci; o.uzatma1 = fo.uzatma1; o.uzatma2 = fo.uzatma2; o.taban1 = fo.taban1; o.taban2 = fo.taban2; olcum->olcumEkle(o); } for (const FikoOlcumZincir& fz : hazir.olcumZincirleri) { OlcumZincir z; z.kimlik = fz.kimlik; z.kapali = fz.kapali != 0; z.noktalar.reserve(fz.noktalar.size()); for (const FikoOlcumLink& l : fz.noktalar) z.noktalar.push_back(linkKur(l)); olcum->zincirEkle(z); } } // 3g) PAFTALAR (v1.15): pafta düğümü kur + veriyi doldur; görünüm kaynakları remap. for (const FikoPafta& fp : hazir.paftalar) { const Varlik v = sahne.paftaEkle(fp.ad); if (fp.ust) { const auto it = harita.find(fp.ust); if (it != harita.end()) sahne.ustAyarla(v, it->second); } harita[fp.kimlik] = v; pafta::Pafta* pv = paftaVerisi(sahne.dunya(), v); if (!pv) continue; pv->ad = fp.ad; pv->sayfa = (pafta::SayfaBoyu)fp.sayfa; pv->ozelOlcu = {fp.ozelEn, fp.ozelBoy}; pv->olcek = {fp.olcekPay, fp.olcekPayda}; pv->antet.goster = fp.antetGoster != 0; pv->antet.en = fp.antetEn; pv->antet.boy = fp.antetBoy; pv->antet.proje = fp.proje; pv->antet.parca = fp.parca; pv->antet.cizen = fp.cizen; pv->antet.tarih = fp.tarih; pv->antet.malzeme = fp.malzeme; pv->antet.revizyon = fp.revizyon; pv->antet.aciklama = fp.aciklama; for (const FikoPaftaGorunum& fg : fp.gorunumler) { pafta::Gorunum g; g.kimlik = fg.kimlik; // Kaynak gövde remap: haritada yoksa 0 kalır (görünüm boş çizilir, çökme yok). if (fg.kaynak) { const auto it = harita.find(fg.kaynak); g.kaynak = it != harita.end() ? (u32)it->second : 0u; } g.ust = fg.ust; // pafta-içi görünüm kimliği (Varlik değil) → remap gerekmez g.yon = (geometri::Gorunum)fg.yon; g.hiza = (pafta::Gorunum::Hiza)fg.hiza; g.olcekMiras = fg.olcekMiras != 0; g.gizliCizgi = fg.gizliCizgi != 0; g.goster = fg.goster != 0; g.olcek = {fg.olcekPay, fg.olcekPayda}; g.konum = {fg.konum[0], fg.konum[1]}; g.boyut = {fg.boyut[0], fg.boyut[1]}; g.ad = fg.ad; g.kesitMi = fg.kesitMi != 0; g.taramaGoster = fg.taramaGoster != 0; g.kesitAnaGorunum = fg.kesitAnaGorunum; g.kesitA = {fg.kesitA[0], fg.kesitA[1]}; g.kesitB = {fg.kesitB[0], fg.kesitB[1]}; g.kesitHarf = fg.kesitHarf; g.detayMi = fg.detayMi != 0; g.detayAnaGorunum = fg.detayAnaGorunum; g.detayMerkez = {fg.detayMerkez[0], fg.detayMerkez[1]}; g.detayYaricap = fg.detayYaricap; g.detayHarf = fg.detayHarf; g.pmiGoster = fg.pmiGoster != 0; pv->gorunumEkle(g); } for (const FikoPaftaOlcu& fo : fp.olculer) { pafta::Olcu o; o.kimlik = fo.kimlik; o.gorunum = fo.gorunum; o.tip = (pafta::OlcuTip)fo.tip; o.otoDeger = fo.otoDeger != 0; o.goster = fo.goster != 0; o.p1 = {fo.p1[0], fo.p1[1]}; o.p2 = {fo.p2[0], fo.p2[1]}; o.tepe = {fo.tepe[0], fo.tepe[1]}; o.ofset = fo.ofset; o.elleDeger = fo.elleDeger; o.onEk = fo.onEk; o.sonEk = fo.sonEk; pv->olcuEkle(o); } } // 3h) PMI (v1.15): defter öğesi + ürün ağacı düğümü kur; hedef gövdeler remap; çapa çöz. if (pmiSis) { for (const FikoPmi& q : hazir.pmiler) { pmi::PmiOge o; o.kimlik = q.kimlik; o.tip = (pmi::PmiTip)q.tip; o.yerlesim = (pmi::Yerlesim)q.yerlesim; for (const FikoOlcumLink& l : q.hedefler) { pmi::PmiHedef h; const auto it = harita.find(l.govde); h.govde = it != harita.end() ? (u32)it->second : l.govde; h.alt = l.alt; h.kip = l.kip; h.kid = l.kid; o.hedefler.push_back(h); } o.ofsetYerel = q.ofsetYerel; o.duzlemNormal = q.duzlemNormal; o.duzlemSag = q.duzlemSag; o.liderVar = q.liderVar != 0; o.goster = q.goster != 0; o.gorselOran = q.gorselOran; o.gdtSatirSayi = q.gdtSatirSayi; for (int i = 0; i < 2; ++i) { const FikoPmiGdtSatir& fg = q.gdt[i]; pmi::GdtSatir& g = o.gdt[i]; g.karakter = (pmi::GdtKarakteristik)fg.karakter; g.tolerans = fg.tolerans; g.capsal = fg.capsal != 0; g.kosul = (pmi::MalzemeKosulu)fg.kosul; g.projeksiyonlu = fg.projeksiyonlu != 0; g.projeksiyonUzunluk = fg.projeksiyonUzunluk; for (int j = 0; j < 3; ++j) { g.datum[j] = fg.datum[j]; g.datumKosul[j] = (pmi::MalzemeKosulu)fg.datumKosul[j]; } } o.datumHarf = q.datumHarf; o.metin = q.metin; o.ozelAlanlar = q.ozelAlanlar; o.stil.renk = q.renk; o.stil.yaziBoyu = q.yaziBoyu; o.stil.cizgiKalinlik = q.cizgiKalinlik; o.stil.sembolOlcek = q.sembolOlcek; o.stil.alfa = q.alfa; const u32 pk = pmiSis->defter().ekle(o); const Varlik v = sahne.pmiEkle(pmiSis, pk, q.ad); if (q.ust) { const auto it = harita.find(q.ust); if (it != harita.end()) sahne.ustAyarla(v, it->second); } if (pmi::PmiOge* oo = pmiSis->defter().bul(pk)) pmiSis->capaCoz(*oo); } } // 4) Kamerayı aynen uygula (aynı bakış noktası). kamera.durumAta( Quatf{hazir.kamera.yonelim[0], hazir.kamera.yonelim[1], hazir.kamera.yonelim[2], hazir.kamera.yonelim[3]}, Vec3f{hazir.kamera.odak[0], hazir.kamera.odak[1], hazir.kamera.odak[2]}, hazir.kamera.mesafe, hazir.kamera.fovDeg, hazir.kamera.ortografik != 0); kamera.orbitHassasiyetAta(hazir.kamera.orbitHassas); kamera.panHassasiyetAta(hazir.kamera.panHassas); kamera.zoomOranAta(hazir.kamera.zoomOran); kamera.yumusatmaAta(hazir.kamera.yumusatma); // 5) Dugum kimlik haritasini disari ver (malzeme atamalari gibi io'ya bagimli // OLMAYAN sistemler remap'i cagiranda yapar). if (dugumHarita) dugumHarita->insert(harita.begin(), harita.end()); } bool fikoYukle(Sahne& sahne, OrbitKamera& kamera, const std::string& yol, std::string& hata) { // Tek geniş read → bellek-içi parse. std::string veri; { std::ifstream f(yol, std::ios::binary | std::ios::ate); if (!f) { hata = "Dosya açılamadı: " + yol; return false; } const std::streamsize n = f.tellg(); if (n <= 0) { hata = "Boş dosya: " + yol; return false; } veri.resize((size_t)n); f.seekg(0); f.read(veri.data(), n); } FikoBelge belge; if (!fikoOku(veri, belge, hata)) return false; HazirYukleme hazir; belgeCoz(belge, hazir); // worker isi (senkron yolda ana-thread'te) belgeUygula(sahne, kamera, hazir); // GPU + sahne + kamera gunluk::bilgi(".fikocad yüklendi: {} ({} grup, {} gövde)", yol, hazir.gruplar.size(), hazir.dugumler.size()); return true; } } // namespace fiko::io