#include "fiko/pafta/pafta.hpp" #include #include namespace fiko::pafta { namespace { // ISO 5455 kademe dizisi (küçültme + büyütme). Keyfi ölçek üretmeyiz. constexpr i32 kKademe[] = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000}; } // namespace SayfaOlcu sayfaOlcusu(SayfaBoyu b) { switch (b) { case SayfaBoyu::A4Dikey: return {210, 297}; case SayfaBoyu::A4Yatay: return {297, 210}; case SayfaBoyu::A3Yatay: return {420, 297}; case SayfaBoyu::A2Yatay: return {594, 420}; case SayfaBoyu::A1Yatay: return {841, 594}; case SayfaBoyu::A0Yatay: return {1189, 841}; default: return {420, 297}; } } const char* sayfaAdi(SayfaBoyu b) { switch (b) { case SayfaBoyu::A4Dikey: return "A4 Dikey"; case SayfaBoyu::A4Yatay: return "A4 Yatay"; case SayfaBoyu::A3Yatay: return "A3 Yatay"; case SayfaBoyu::A2Yatay: return "A2"; case SayfaBoyu::A1Yatay: return "A1"; case SayfaBoyu::A0Yatay: return "A0"; default: return "Özel"; } } std::string Olcek::metin() const { return std::to_string(pay) + ":" + std::to_string(payda); } Olcek standartOlcek(f64 hedefOran) { if (!(hedefOran > 0) || !std::isfinite(hedefOran)) return {1, 1}; Olcek enIyi{1, 1}; f64 enIyiHata = 1e300; // Aday küme: 1:k (küçültme) ve k:1 (büyütme). Karşılaştırma LOG uzayında — // 1:2 ile 2:1 hedefe eşit uzaklıkta sayılsın (oran ölçeği çarpımsaldır). const f64 hedefLog = std::log(hedefOran); for (i32 k : kKademe) { const Olcek adaylar[2] = {{1, k}, {k, 1}}; for (const Olcek& a : adaylar) { const f64 hata = std::abs(std::log(a.oran()) - hedefLog); if (hata < enIyiHata - 1e-12) { enIyiHata = hata; enIyi = a; } } } return enIyi; } u32 Pafta::gorunumEkle(Gorunum g) { if (g.kimlik == 0) g.kimlik = sonrakiKimlik_++; else sonrakiKimlik_ = std::max(sonrakiKimlik_, g.kimlik + 1); const u32 k = g.kimlik; gorunumler_.push_back(std::move(g)); return k; } bool Pafta::gorunumSil(u32 kimlik) { const auto it = std::find_if(gorunumler_.begin(), gorunumler_.end(), [kimlik](const Gorunum& g) { return g.kimlik == kimlik; }); if (it == gorunumler_.end()) return false; gorunumler_.erase(it); // Görünümün ölçüleri onunla gider (yetim ölçü sayfada asılı kalmaz). std::erase_if(olculer_, [kimlik](const Olcu& o) { return o.gorunum == kimlik; }); // Yetim çocuklar bağımsızlaşır — silinmez (kullanıcının çizimi kaybolmasın). for (Gorunum& g : gorunumler_) if (g.ust == kimlik) { g.ust = 0; g.hiza = Gorunum::Hiza::Bagimsiz; } return true; } u32 Pafta::olcuEkle(Olcu o) { if (o.kimlik == 0) o.kimlik = sonrakiOlcuKimlik_++; else sonrakiOlcuKimlik_ = std::max(sonrakiOlcuKimlik_, o.kimlik + 1); const u32 k = o.kimlik; olculer_.push_back(std::move(o)); return k; } bool Pafta::olcuSil(u32 kimlik) { const auto it = std::find_if(olculer_.begin(), olculer_.end(), [kimlik](const Olcu& o) { return o.kimlik == kimlik; }); if (it == olculer_.end()) return false; olculer_.erase(it); return true; } Olcu* Pafta::olcuBul(u32 kimlik) { for (Olcu& o : olculer_) if (o.kimlik == kimlik) return &o; return nullptr; } std::vector Pafta::gorunumunOlculeri(u32 gorunumKimlik) const { std::vector s; for (const Olcu& o : olculer_) if (o.gorunum == gorunumKimlik) s.push_back(o.kimlik); return s; } Gorunum* Pafta::gorunumBul(u32 kimlik) { for (Gorunum& g : gorunumler_) if (g.kimlik == kimlik) return &g; return nullptr; } const Gorunum* Pafta::gorunumBul(u32 kimlik) const { return const_cast(this)->gorunumBul(kimlik); } void Pafta::gorunumTasi(u32 kimlik, Vec2d yeniKonum) { Gorunum* g = gorunumBul(kimlik); if (!g) return; // Hizalı görünüm ebeveyninin ekseninde kilitlidir (teknik resimde ön/üst/yan // görünümler asla kaymaz — kaydırılırsa çizim standart dışı olur). if (g->ust) { if (const Gorunum* ust = gorunumBul(g->ust)) { if (g->hiza == Gorunum::Hiza::Yatay) yeniKonum.y = ust->konum.y; else if (g->hiza == Gorunum::Hiza::Dikey) yeniKonum.x = ust->konum.x; } } const Vec2d delta{yeniKonum.x - g->konum.x, yeniKonum.y - g->konum.y}; g->konum = yeniKonum; // Ebeveyn taşındıysa hizalı çocuklar aynı deltayla gider (hiza korunur). for (Gorunum& c : gorunumler_) if (c.ust == kimlik && c.hiza != Gorunum::Hiza::Bagimsiz) { c.konum.x += delta.x; c.konum.y += delta.y; } } bool Pafta::sayfayaSigar(const Gorunum& g, f64 kenarPayi) const { const SayfaOlcu s = olcu(); const f64 yariEn = g.boyut.x * 0.5, yariBoy = g.boyut.y * 0.5; return g.konum.x - yariEn >= kenarPayi && g.konum.y - yariBoy >= kenarPayi && g.konum.x + yariEn <= s.en - kenarPayi && g.konum.y + yariBoy <= s.boy - kenarPayi; } Olcek Pafta::sigdiranOlcek(f64 cizimEn, f64 cizimBoy, f64 kenarPayi) const { const SayfaOlcu s = olcu(); f64 kullanEn = s.en - 2 * kenarPayi; f64 kullanBoy = s.boy - 2 * kenarPayi; if (antet.goster) kullanBoy -= antet.boy; // antet alt şeridi yer kaplar if (cizimEn <= 0 || cizimBoy <= 0 || kullanEn <= 0 || kullanBoy <= 0) return {1, 1}; const f64 oran = std::min(kullanEn / cizimEn, kullanBoy / cizimBoy); const Olcek s1 = standartOlcek(oran); // standartOlcek en YAKIN kademeyi verir; sığmayı garantilemek için taşarsa bir // kademe küçült (1:2 → 1:5 …). Çizim sayfadan taşmaktansa küçük olsun. if (s1.oran() * cizimEn <= kullanEn && s1.oran() * cizimBoy <= kullanBoy) return s1; Olcek en{1, 1}; f64 enIyi = -1; for (i32 k : kKademe) { const Olcek adaylar[2] = {{1, k}, {k, 1}}; for (const Olcek& a : adaylar) { if (a.oran() * cizimEn > kullanEn || a.oran() * cizimBoy > kullanBoy) continue; if (a.oran() > enIyi) { // sığanların EN BÜYÜĞÜ enIyi = a.oran(); en = a; } } } return en; } void Pafta::ucGorunumKur(u32 kaynak, f64 parcaEn, f64 parcaBoy, f64 parcaYuk, f64 istenenOran) { gorunumler_.clear(); olculer_.clear(); sonrakiKimlik_ = 1; sonrakiOlcuKimlik_ = 1; // Ön görünüm düzlemi: en × yük. Üst: en × boy. Sol: boy × yük. const f64 toplamEn = parcaEn + parcaBoy; const f64 toplamBoy = parcaYuk + parcaBoy; olcek = istenenOran > 0 ? standartOlcek(istenenOran) : sigdiranOlcek(toplamEn, toplamBoy); const f64 o = olcek.oran(); const SayfaOlcu s = olcu(); const f64 bosluk = 20.0; // görünümler arası nefes payı (mm, sayfa uzayında) const f64 anteYer = antet.goster ? antet.boy : 0.0; // ÖN görünüm merkezi: yerleşimin sol-üst bloğu; ÜST altında, SOL sağında (ISO E). const f64 onEn = parcaEn * o, onBoy = parcaYuk * o; const f64 ustBoy = parcaBoy * o; const f64 solEn = parcaBoy * o; const f64 blokEn = onEn + bosluk + solEn; const f64 blokBoy = onBoy + bosluk + ustBoy; const f64 solKenar = (s.en - blokEn) * 0.5; const f64 altKenar = anteYer + (s.boy - anteYer - blokBoy) * 0.5; Gorunum on; on.ad = "Ön Görünüm"; on.kaynak = kaynak; on.yon = geometri::Gorunum::On; on.boyut = {onEn, onBoy}; on.konum = {solKenar + onEn * 0.5, altKenar + ustBoy + bosluk + onBoy * 0.5}; const u32 onId = gorunumEkle(on); Gorunum ust; ust.ad = "Üst Görünüm"; ust.kaynak = kaynak; ust.yon = geometri::Gorunum::Ust; ust.boyut = {onEn, ustBoy}; ust.ust = onId; ust.hiza = Gorunum::Hiza::Dikey; // ön görünümle aynı x ust.konum = {on.konum.x, altKenar + ustBoy * 0.5}; gorunumEkle(ust); Gorunum sol; sol.ad = "Sol Görünüm"; sol.kaynak = kaynak; sol.yon = geometri::Gorunum::Sol; sol.boyut = {solEn, onBoy}; sol.ust = onId; sol.hiza = Gorunum::Hiza::Yatay; // ön görünümle aynı y sol.konum = {solKenar + onEn + bosluk + solEn * 0.5, on.konum.y}; gorunumEkle(sol); } } // namespace fiko::pafta