#include "fiko/cam/apt.hpp" #include #include #include #include #include #include #include #include #include #include namespace fiko::cam { namespace { // CATIA GOTO alani: "%11.5f" — 248.45516 / -0.14037 hizalanir (isaret bosluk yer). void gotoAlani(std::string& s, f64 v) { char b[32]; std::snprintf(b, sizeof(b), "%11.5f", v); s += b; } // FEDRAT/CUTTER/TLAXIS alanlari 6-ondalik ("%.6f"/"%.4f" spec bicimi). void devirAlani(std::string& s, f64 v) { char b[32]; std::snprintf(b, sizeof(b), "%.4f", v); s += b; } } // namespace // ============================================================================ // YAZICI // ============================================================================ void aptYaz(const TakimYolu& yol, const Takim& takim, std::string& cikti, const AptSecenek& sec) { cikti.clear(); // Kaba on-rezervasyon: hamle basina ~40 bayt (GOTO satiri) + baslik. cikti.reserve(yol.hamleler.size() * 42 + 512); if (sec.baslikYaz) { cikti += "$$ -----------------------------------------------------------------\n"; cikti += "$$ FIKATIA APT VERSION 1.0\n"; cikti += "$$ -----------------------------------------------------------------\n"; cikti += "$$ " + sec.programAdi + "\n"; } cikti += "PARTNO " + sec.partNo + "\n"; // Takim ekseni Z disi ise TLAXIS yaz (5-eksen). Yon bilgisi yolda tasinmadigi // icin secenekten degil, Z varsayilan; ileride Hamle takimEkseni eklenebilir. // MVP: sabit Z ekseni — TLAXIS/0,0,1 (CATIA her operasyon basinda yazar). cikti += "TLAXIS/ 0.000000, 0.000000, 1.000000\n"; // CUTTER: cap, koseYaricap, ... boy (APT 7-param; web D,r,...,h alir). { char b[128]; std::snprintf(b, sizeof(b), "CUTTER/ %.6f, %.6f, 0.000000, %.6f, 0.000000,$\n" " 0.000000, %.6f\n", takim.cap, takim.koseYaricap, takim.koseYaricap, takim.boy); cikti += b; } if (sec.spindl && sec.devir > 0.0) { cikti += "SPINDL/ "; devirAlani(cikti, sec.devir); cikti += ",RPM,CLW\n"; } const f64 rapidEsik = sec.rapidIlerleme; f64 sonIlerleme = -1.0; for (const Hamle& h : yol.hamleler) { const bool hizli = (h.tip == HamleTip::Hizli); // FEDRAT: kesme hamlesinde ilerleme degisince yaz. if (!hizli && h.ilerleme > 0.0 && std::abs(h.ilerleme - sonIlerleme) > 0.5) { cikti += "FEDRAT/"; devirAlani(cikti, h.ilerleme); cikti += ",MMPM\n"; sonIlerleme = h.ilerleme; } // Rapid isareti: tip Hizli VEYA ilerleme rapid esigi ustunde. const bool rapid = hizli || (rapidEsik > 0.0 && h.ilerleme >= rapidEsik); if (rapid) { cikti += "RAPID\n"; sonIlerleme = -1.0; // rapid sonrasi FEDRAT tekrar yazilsin } cikti += "GOTO /"; gotoAlani(cikti, h.nokta.x); cikti += ","; gotoAlani(cikti, h.nokta.y); cikti += ","; gotoAlani(cikti, h.nokta.z); cikti += "\n"; } if (sec.spindl && sec.devir > 0.0) cikti += "SPINDL/OFF\n"; cikti += "REWIND/0\n"; cikti += "FINI\n"; } std::string aptYaz(const TakimYolu& yol, const Takim& takim, const AptSecenek& sec) { std::string s; aptYaz(yol, takim, s, sec); return s; } bool aptDosyaYaz(const std::string& yol, const TakimYolu& yol_veri, const Takim& takim, const AptSecenek& sec) { std::ofstream f(yol, std::ios::binary); if (!f) return false; const std::string s = aptYaz(yol_veri, takim, sec); f.write(s.data(), (std::streamsize)s.size()); return (bool)f; } // ============================================================================ // OKUYUCU — HIZLI PARSER (tek buffer + pointer tarama, from_chars, string_view) // ---------------------------------------------------------------------------- // Tasarim: Dosya TEK seferde bir buffer'a alinir (aptOku fread; aptCoz metnin // kendisi). Satirlar '\n' ile pointer-taranir; '\r' + '$'-devami yerinde // islenir, kopyasiz. Sayilar std::from_chars ile locale-siz parse edilir, // hicbir std::string/vector alokasyonu satir basina yok (string_view). // Rapid esigi tek gecisde toplanir (maxFedrat), sonra hamle vektoru uzerinde // O(n) ikinci gecis ile isaretlenir — metin YENIDEN taranmaz. Hata toleransi // korunur (bozuk GOTO say+atla). Round-trip semantigi birebir eskiyle ayni. namespace { // Sondaki '\r' + bosluklari kirp (string_view daraltma). inline std::string_view sagKirp(std::string_view s) { std::size_t n = s.size(); while (n > 0 && (s[n - 1] == '\r' || s[n - 1] == ' ' || s[n - 1] == '\t' || s[n - 1] == '\n')) --n; return s.substr(0, n); } inline std::string_view solKirp(std::string_view s) { std::size_t i = 0; while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) ++i; return s.substr(i); } // Komut adini (bas harf blogu, '/' oncesi) buyuk-harf 8-bayt kod olarak esle — // string alokasyonu YOK. Yaygin komutlar sabit u64 imza ile karsilastirilir. // Dondurulen: ilk alfabetik token'in ilk 6 harfi memcmp icin (upper-cased). // Kolaylik: bir komut kontrol fonksiyonu. inline bool komutuMu(std::string_view s, const char* ad) { s = solKirp(s); std::size_t i = 0; while (i < s.size() && ad[i] && (char)std::toupper((unsigned char)s[i]) == ad[i]) ++i; if (ad[i] != '\0') return false; // Komut biteli: sonraki karakter harf OLMAMALI (GOTO ≠ GOTOX). return i >= s.size() || !std::isalpha((unsigned char)s[i]); } // Satirdaki sayilari string_view uzerinde from_chars ile cikar — cik'e yaz, // en fazla maxN. Hata toleransli: gecersiz token atlanir. Doner: cikarilan adet. inline std::size_t sayilariCikar(std::string_view s, f64* cik, std::size_t maxN) { const char* p = s.data(); const char* son = p + s.size(); std::size_t say = 0; while (p < son && say < maxN) { const char c = *p; const bool basla = (c >= '0' && c <= '9') || ((c == '-' || c == '+' || c == '.') && p + 1 < son && ((p[1] >= '0' && p[1] <= '9') || p[1] == '.')); if (!basla) { ++p; continue; } f64 v; auto r = std::from_chars(p, son, v); if (r.ec == std::errc()) { cik[say++] = v; p = r.ptr; } else { ++p; // parse edilemedi → ilerle (guvenlik) } } return say; } // Tum sayilari say (adet sinirsiz; sadece maxFedrat/eksen icin gerektiginde). inline std::size_t sayilariCikarTum(std::string_view s, std::vector& cik) { const char* p = s.data(); const char* son = p + s.size(); cik.clear(); while (p < son) { const char c = *p; const bool basla = (c >= '0' && c <= '9') || ((c == '-' || c == '+' || c == '.') && p + 1 < son && ((p[1] >= '0' && p[1] <= '9') || p[1] == '.')); if (!basla) { ++p; continue; } f64 v; auto r = std::from_chars(p, son, v); if (r.ec == std::errc()) { cik.push_back(v); p = r.ptr; } else ++p; } return cik.size(); } // Satirda ANAHTAR KELIME var mi (buyuk/kucuk harf duyarsiz, tam kelime). // "FEDRAT/MMPM,1000" icinde MMPM'i bulmak icin — komut adindan SONRAKI modifier'lar. inline bool kelimeVar(std::string_view s, const char* kelime) { const std::size_t n = std::strlen(kelime); if (s.size() < n) return false; for (std::size_t i = 0; i + n <= s.size(); ++i) { std::size_t j = 0; while (j < n && (char)std::toupper((unsigned char)s[i + j]) == kelime[j]) ++j; if (j != n) continue; // Tam kelime: onceki ve sonraki karakter harf olmamali (ON ≠ COOLNT'in "ON"u degil, // ayirici sonrasi olmali). const bool solOk = (i == 0) || !std::isalpha((unsigned char)s[i - 1]); const bool sagOk = (i + n >= s.size()) || !std::isalpha((unsigned char)s[i + n]); if (solOk && sagOk) return true; } return false; } // Yay bolumleme: merkez c, birim normal nrm, yaricap r; bas→son noktasi arasindaki // yayi sagitta toleransina gore ara noktalara boler (bas ve son HARIC; cagiran son // noktayi kendi ekler). Sag-el kurali: nrm yonunde POZITIF donus. void yayBol(Vec3d bas, Vec3d son, Vec3d c, Vec3d nrm, f64 r, f64 tolMm, std::vector& cik) { cik.clear(); const f64 nLen = std::sqrt(nrm.x * nrm.x + nrm.y * nrm.y + nrm.z * nrm.z); if (nLen < 1e-12 || r <= 1e-9) return; nrm = nrm * (1.0 / nLen); // Duzleme izdusur (bas/son yay uzerinde varsayilir; kucuk sapmalari at). Vec3d u = bas - c; u = u - nrm * u.nokta(nrm); Vec3d w = son - c; w = w - nrm * w.nokta(nrm); const f64 uLen = std::sqrt(u.nokta(u)), wLen = std::sqrt(w.nokta(w)); if (uLen < 1e-9 || wLen < 1e-9) return; u = u * (1.0 / uLen); w = w * (1.0 / wLen); // v = nrm × u → (u,v) duzlem tabani; hedef aci [0, 2π) sag-el yonunde. const Vec3d v = nrm.capraz(u); f64 aci = std::atan2(w.nokta(v), w.nokta(u)); if (aci <= 1e-9) aci += 2.0 * 3.14159265358979323846; // tam tur / negatif → pozitife sar // Sagitta: tol = r(1-cos(dAci/2)) → dAci = 2·acos(1 - tol/r). const f64 oran = 1.0 - std::clamp(tolMm, 1e-9, r * 0.99) / r; const f64 dAci = 2.0 * std::acos(std::clamp(oran, -1.0, 1.0)); int adet = (dAci > 1e-9) ? (int)std::ceil(aci / dAci) : 1; adet = std::clamp(adet, 1, 4096); // dejenere/asiri bolme tavani cik.reserve((std::size_t)adet); for (int i = 1; i < adet; ++i) { // ara noktalar (son haric) const f64 a = aci * (f64)i / (f64)adet; const Vec3d p = c + (u * std::cos(a) + v * std::sin(a)) * r; cik.push_back(p); } } // Ortak buffer-tabanli cozucu: [veri, veri+boyut) tek gecisde parse edilir. void aptCozBuffer(const char* veri, std::size_t boyut, AptSonuc& sonuc, const AptOkuSecenek& sec) { // Satir tahmini (ort ~40 bayt/satir) → hamle vektoru on-rezervasyonu. const std::size_t tahminSatir = boyut / 32 + 16; sonuc.yol.hamleler.clear(); sonuc.yol.hamleler.reserve(tahminSatir); f64 maxFedrat = 0.0; f64 sonIlerleme = 0.0; bool rapidBayrak = false; bool takimGoruldu = false; // Aktivite (operasyon blogu) durumu — web APTCAT ile ayni: takim/eksen/devir // bloklar ARASI tasinir, her blokta yeniden bildirilmesi gerekmez. Takim aktifTakim; int aktifTakimNo = 0; auto aktiviteKapat = [&] { if (!sonuc.aktiviteler.empty()) { AptAktivite& a = sonuc.aktiviteler.back(); a.hamleAdet = sonuc.yol.hamleler.size() - a.hamleBas; } }; auto aktiviteAc = [&](std::string ad) { AptAktivite a; a.ad = std::move(ad); a.hamleBas = sonuc.yol.hamleler.size(); a.takim = aktifTakim; a.takimNo = aktifTakimNo; a.takimEkseni = sonuc.takimEkseni; a.devir = sonuc.devir; sonuc.aktiviteler.push_back(std::move(a)); }; std::vector baslikEksen; baslikEksen.reserve(12); std::vector tmp; // eksen/CUTTER gibi seyrek satirlar icin (sicak yolda YOK) // Her hamlenin FEDRAT'ini gecici tut → ikinci geciste rapid isaretle. // (Rapid bayragi zaten anlik; FEDRAT-esik kontrolu sonda yapilir.) std::vector hamleFedrat; // hamle basina ilerleme (rapid esigi icin) hamleFedrat.reserve(tahminSatir); // ---- Tam APT kapsami durumu ---- Vec3d konum{}; // guncel takim ucu (FROM/GODLTA/yay bunu kullanir) Vec3d aktifEksen{0, 0, 1}; // guncel takim ekseni (TLAXIS veya GOTO'nun i,j,k'si) bool eksenDizi = false; // hamleEksen dizisi devrede mi (6-degerli GOTO gorulunce) AptCevrim cevrim; bool cevrimAcik = false; bool yayBekliyor = false; // CIRCLE goruldu, yayin SONU sonraki GOTO Vec3d yayMerkez{}, yayNormal{0, 0, 1}; f64 yayR = 0.0; std::vector yayNoktalar; // Hamle ekle (TEK yer): yol + rapid izi + (varsa) hamle-basi eksen + konum takibi. auto hamleEkle = [&](Vec3d nokta, bool rapid, f64 ilerleme) { Hamle h; h.nokta = nokta; h.tip = rapid ? HamleTip::Hizli : HamleTip::Kesme; h.ilerleme = ilerleme; sonuc.yol.hamleler.push_back(h); hamleFedrat.push_back(rapid ? -1.0f : (f32)ilerleme); if (eksenDizi) sonuc.hamleEksen.push_back({(f32)aktifEksen.x, (f32)aktifEksen.y, (f32)aktifEksen.z}); konum = nokta; }; // 5-eksen ilk goruldugunde diziyi ac: o ana kadarki hamleleri guncel eksenle doldur // (dizi doluysa boyu HEP hamleler ile birebir kalir). auto eksenDiziAc = [&] { if (eksenDizi) return; eksenDizi = true; sonuc.hamleEksen.assign(sonuc.yol.hamleler.size(), {(f32)aktifEksen.x, (f32)aktifEksen.y, (f32)aktifEksen.z}); }; // Ilerlemeyi mm/dk'ya cevir (MMPR/IPR devire baglidir). auto ilerlemeNormal = [&](f64 ham) -> f64 { const f64 rpm = sonuc.devir > 0.0 ? sonuc.devir : 1.0; switch (sonuc.ilerlemeBirim) { case AptIlerlemeBirim::InchDk: return ham * 25.4; case AptIlerlemeBirim::MmDev: return ham * rpm; case AptIlerlemeBirim::InchDev: return ham * 25.4 * rpm; default: return ham; } }; const char* p = veri; const char* son = veri + boyut; f64 nbuf[8]; while (p < son) { // Satir sinirini bul. const char* satBas = p; const char* nl = static_cast(std::memchr(p, '\n', son - p)); const char* satSon = nl ? nl : son; p = nl ? nl + 1 : son; std::string_view sv(satBas, (std::size_t)(satSon - satBas)); sv = sagKirp(sv); // '\r' + bosluk kirp // '$' satir-devami: satir sonu '$' ise sonraki fiziksel satirlari yut. // (CUTTER cok satirli — sayilar birlesik gorulmeli.) Kopyasiz genislet: // sv'yi satBas..(devam satirinin sonu) araligina uzat. Aradaki '$'+bosluk // rakam olmadigi icin sayilariCikar tarafindan zaten atlanir. while (!sv.empty() && sv.back() == '$' && p < son) { const char* dnl = static_cast(std::memchr(p, '\n', son - p)); const char* dSon = dnl ? dnl : son; p = dnl ? dnl + 1 : son; sv = sagKirp(std::string_view(satBas, (std::size_t)(dSon - satBas))); } std::string_view t = solKirp(sv); if (t.empty()) continue; const char c0 = t[0]; // Sicak yol: GOTO (dosyanin ~%95'i). Ilk 4 harf 'GOTO'. // 3 deger = x,y,z; 6 deger = x,y,z,i,j,k (hamle-basi takim ekseni — 5 eksen). if ((c0 == 'G' || c0 == 'g') && komutuMu(t, "GOTO")) { const std::size_t n = sayilariCikar(t, nbuf, 6); if (n < 3) { ++sonuc.bilinmeyenSatir; continue; } ++sonuc.gotoSayisi; const Vec3d hedef{nbuf[0], nbuf[1], nbuf[2]}; if (n >= 6) { aktifEksen = {nbuf[3], nbuf[4], nbuf[5]}; sonuc.takimEkseni = aktifEksen; eksenDiziAc(); } if (cevrimAcik) { // sabit cevrim acik → bu GOTO bir DELIK konumu sonuc.yol.delikler.push_back(hedef); ++sonuc.cevrimDelik; } if (yayBekliyor) { // onceki CIRCLE'in yayi: konum → hedef arasi bolumlenir yayBol(konum, hedef, yayMerkez, yayNormal, yayR, sec.yayToleransMm, yayNoktalar); for (const Vec3d& a : yayNoktalar) { hamleEkle(a, rapidBayrak, sonIlerleme); ++sonuc.yayNokta; } yayBekliyor = false; } hamleEkle(hedef, rapidBayrak, sonIlerleme); rapidBayrak = false; continue; } // FROM/x,y,z[,i,j,k] — programin baslangic konumu (hamle olarak islenir). if ((c0 == 'F' || c0 == 'f') && komutuMu(t, "FROM")) { const std::size_t n = sayilariCikar(t, nbuf, 6); if (n >= 3) { if (n >= 6) { aktifEksen = {nbuf[3], nbuf[4], nbuf[5]}; sonuc.takimEkseni = aktifEksen; eksenDiziAc(); } hamleEkle({nbuf[0], nbuf[1], nbuf[2]}, true, 0.0); // baslangic = hizli konumlama } continue; } // GODLTA/dx,dy,dz (artimli) veya GODLTA/d (takim ekseni boyunca). Eskiden // TAMAMEN atlaniyordu → bu hamleler KAYIPTI. if ((c0 == 'G' || c0 == 'g') && komutuMu(t, "GODLTA")) { const std::size_t n = sayilariCikar(t, nbuf, 3); Vec3d d{}; if (n >= 3) d = {nbuf[0], nbuf[1], nbuf[2]}; else if (n == 1) d = aktifEksen * nbuf[0]; else { ++sonuc.bilinmeyenSatir; continue; } hamleEkle(konum + d, rapidBayrak, sonIlerleme); rapidBayrak = false; continue; } // CIRCLE/xc,yc,zc,i,j,k,r (merkez+eksen+yaricap) veya CIRCLE/xc,yc,zc,r. // Yay SONU sonraki GOTO'dur; arasi toleransa gore bolumlenir. if ((c0 == 'C' || c0 == 'c') && komutuMu(t, "CIRCLE")) { sayilariCikarTum(t, tmp); if (tmp.size() >= 7) { yayMerkez = {tmp[0], tmp[1], tmp[2]}; yayNormal = {tmp[3], tmp[4], tmp[5]}; yayR = tmp[6]; } else if (tmp.size() >= 4) { yayMerkez = {tmp[0], tmp[1], tmp[2]}; yayNormal = aktifEksen; yayR = tmp[3]; } else { ++sonuc.bilinmeyenSatir; continue; } yayBekliyor = yayR > 1e-9; continue; } // CYCLE/,derinlik,FEDRAT,f,... — sabit cevrim ac; CYCLE/OFF kapatir. if ((c0 == 'C' || c0 == 'c') && komutuMu(t, "CYCLE")) { if (kelimeVar(t, "OFF")) { cevrimAcik = false; cevrim = AptCevrim{}; } else { cevrim = AptCevrim{}; cevrim.tip = kelimeVar(t, "DEEP") ? AptCevrimTip::Derin : kelimeVar(t, "BRKCHP") ? AptCevrimTip::Kirici : kelimeVar(t, "TAP") ? AptCevrimTip::Kilavuz : kelimeVar(t, "BORE") ? AptCevrimTip::Bara : kelimeVar(t, "REAM") ? AptCevrimTip::Rayba : (kelimeVar(t, "CSINK") || kelimeVar(t, "FACE")) ? AptCevrimTip::Punta : AptCevrimTip::Delme; sayilariCikarTum(t, tmp); if (tmp.size() >= 1) cevrim.derinlik = tmp[0]; if (tmp.size() >= 2) cevrim.ilerleme = ilerlemeNormal(tmp[1]); if (tmp.size() >= 3) cevrim.adim = tmp[2]; if (tmp.size() >= 4 && kelimeVar(t, "DWELL")) cevrim.bekleme = tmp[3]; if (kelimeVar(t, "RAPTO") || kelimeVar(t, "CLEAR")) cevrim.guvenli = tmp.empty() ? 0.0 : tmp.back(); cevrimAcik = true; // Aktivite kaydi "bu blokta KULLANILAN cevrim"dir; CYCLE/OFF uzerine YAZMAZ // (yoksa kapanista silinir ve delik operasyonu cevrimsiz gorunur). if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().cevrim = cevrim; } continue; } // FEDRAT/[MMPM|MMPR|IPM|IPR,]f veya FEDRAT/RAPID. Dahili birim HEP mm/dk. if ((c0 == 'F' || c0 == 'f') && komutuMu(t, "FEDRAT")) { if (kelimeVar(t, "MMPM")) sonuc.ilerlemeBirim = AptIlerlemeBirim::MmDk; else if (kelimeVar(t, "MMPR")) sonuc.ilerlemeBirim = AptIlerlemeBirim::MmDev; else if (kelimeVar(t, "IPM")) sonuc.ilerlemeBirim = AptIlerlemeBirim::InchDk; else if (kelimeVar(t, "IPR")) sonuc.ilerlemeBirim = AptIlerlemeBirim::InchDev; if (kelimeVar(t, "RAPID")) { rapidBayrak = true; continue; } const std::size_t n = sayilariCikar(t, nbuf, 1); if (n >= 1) { sonIlerleme = ilerlemeNormal(nbuf[0]); if (sonIlerleme > maxFedrat) maxFedrat = sonIlerleme; } continue; } // Bagimsiz birim ifadeleri (sonraki FEDRAT'lari etkiler). if (komutuMu(t, "MMPM")) { sonuc.ilerlemeBirim = AptIlerlemeBirim::MmDk; continue; } if (komutuMu(t, "MMPR")) { sonuc.ilerlemeBirim = AptIlerlemeBirim::MmDev; continue; } if (komutuMu(t, "IPM")) { sonuc.ilerlemeBirim = AptIlerlemeBirim::InchDk; continue; } if (komutuMu(t, "IPR")) { sonuc.ilerlemeBirim = AptIlerlemeBirim::InchDev; continue; } if ((c0 == 'R' || c0 == 'r') && komutuMu(t, "RAPID")) { rapidBayrak = true; continue; } // SPINDL/[RPM,]n[,CLW|CCLW] veya SPINDL/ON|OFF. if ((c0 == 'S' || c0 == 's') && komutuMu(t, "SPINDL")) { if (kelimeVar(t, "CCLW")) sonuc.igYonu = AptIgYonu::SaatTers; else if (kelimeVar(t, "CLW")) sonuc.igYonu = AptIgYonu::Saat; const std::size_t n = sayilariCikar(t, nbuf, 1); if (n >= 1 && nbuf[0] > 0.0) { sonuc.devir = nbuf[0]; if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().devir = nbuf[0]; } continue; } // COOLNT/ON|OFF|FLOOD|MIST|THRU|TAP if ((c0 == 'C' || c0 == 'c') && komutuMu(t, "COOLNT")) { sonuc.sogutma = kelimeVar(t, "FLOOD") ? AptSogutma::Sel : kelimeVar(t, "MIST") ? AptSogutma::Sis : kelimeVar(t, "THRU") ? AptSogutma::Icten : kelimeVar(t, "TAP") ? AptSogutma::Kilavuz : kelimeVar(t, "OFF") ? AptSogutma::Kapali : AptSogutma::Sel; // COOLNT/ON → sel if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().sogutma = sonuc.sogutma; continue; } if (komutuMu(t, "MULTAX")) { // 5-eksen kip bildirimi (dizi 6-degerli GOTO ile acilir) sonuc.multax = !kelimeVar(t, "OFF"); continue; } if ((c0 == 'T' || c0 == 't') && komutuMu(t, "TLAXIS")) { const std::size_t n = sayilariCikar(t, nbuf, 3); if (n >= 3) { sonuc.takimEkseni = {nbuf[0], nbuf[1], nbuf[2]}; aktifEksen = sonuc.takimEkseni; if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().takimEkseni = sonuc.takimEkseni; } continue; } if (komutuMu(t, "ORIGIN")) { if (sayilariCikar(t, nbuf, 3) >= 3) sonuc.origin = {nbuf[0], nbuf[1], nbuf[2]}; continue; } if (komutuMu(t, "CLEARP")) { if (sayilariCikar(t, nbuf, 1) >= 1) sonuc.clearP = nbuf[0]; continue; } // PPRINT/INSERT: operator mesaji / ham NC satiri — sirayla saklanir. if (komutuMu(t, "PPRINT") || komutuMu(t, "INSERT")) { const std::size_t eg = t.find('/'); std::string_view m = (eg == std::string_view::npos) ? t.substr(6) : t.substr(eg + 1); m = sagKirp(solKirp(m)); if (!m.empty() && sonuc.mesajlar.size() < 4096) sonuc.mesajlar.emplace_back(m); continue; } if (komutuMu(t, "MACHIN")) { const std::size_t eg = t.find('/'); if (eg != std::string_view::npos && sonuc.makine.empty()) { std::string_view m = sagKirp(solKirp(t.substr(eg + 1))); const std::size_t v = m.find(','); if (v != std::string_view::npos) m = sagKirp(m.substr(0, v)); if (!m.empty()) sonuc.makine.assign(m); } continue; } // CUTTER: HER takim degisimi islenir (eskiden yalniz ilki → cok takimli // programda sonraki operasyonlar yanlis takimla geliyordu). sonuc.takim ILK // takim olarak kalir (geriye donuk); aktif takim aktiviteye yazilir. if ((c0 == 'C' || c0 == 'c') && komutuMu(t, "CUTTER")) { sayilariCikarTum(t, tmp); // CUTTER 7 param (devam-birlesik) if (!tmp.empty()) { aktifTakim = Takim{}; aktifTakim.cap = tmp[0]; if (tmp.size() >= 2) aktifTakim.koseYaricap = tmp[1]; if (tmp.size() >= 7) aktifTakim.boy = tmp[6]; else if (tmp.size() >= 3) aktifTakim.boy = tmp.back(); // CUTTER/d,r,e,f,alpha,beta,h → TAKIM TIPI. Eskiden tip hic dolmuyordu → // varsayilan ParmakFreze kaliyor, kuresel/torus takim DUZ UC ciziliyordu. // r ≈ d/2 → kuresel (ball); 0 < r < d/2 → torus (bull); r ≈ 0 → duz (flat). // alpha (5. param) anlamli aciysa konik/V-uc. { const f64 R = tmp[0] * 0.5; const f64 r = (tmp.size() >= 2) ? tmp[1] : 0.0; const f64 alpha = (tmp.size() >= 5) ? tmp[4] : 0.0; const f64 tolR = std::max(R * 0.02, 1e-3); // %2 bant (CATIA ondalik yuvarlamasi) if (r >= R - tolR) aktifTakim.tip = TakimTip::KureselFreze; else if (r > tolR) aktifTakim.tip = TakimTip::TorusFreze; else if (alpha > 1.0 && alpha < 89.0) { aktifTakim.tip = TakimTip::KonikFreze; aktifTakim.ucAci = 2.0 * alpha; // APT yarim-aci verir; ucAci tam acidir } else { aktifTakim.tip = TakimTip::ParmakFreze; } } aktifTakim.ad = "APT Ø" + std::to_string((int)std::lround(tmp[0])); if (!takimGoruldu) { sonuc.takim = aktifTakim; takimGoruldu = true; } if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().takim = aktifTakim; } continue; } // LOADTL: takim numarasi (web parser tanir; eskiden sessiz atlaniyordu). if ((c0 == 'L' || c0 == 'l') && komutuMu(t, "LOADTL")) { const std::size_t n = sayilariCikar(t, nbuf, 1); if (n >= 1) { aktifTakimNo = (int)nbuf[0]; if (!sonuc.aktiviteler.empty()) sonuc.aktiviteler.back().takimNo = aktifTakimNo; } continue; } if ((c0 == 'P' || c0 == 'p') && komutuMu(t, "PARTNO")) { if (sonuc.programAdi.empty()) { std::string_view ad = solKirp(t.substr(6)); // "PARTNO" sonrasi ad = sagKirp(ad); if (!ad.empty()) sonuc.programAdi.assign(ad); } continue; } // $$ yorum: OPERATION NAME + baslik eksen (3x4). Diger $ satirlari atla. if (c0 == '$') { if (t.size() >= 2 && t[1] == '$') { const std::size_t op = t.find("OPERATION NAME"); if (op != std::string_view::npos) { // HER operasyon bir aktivite sinir(i) (eskiden yalniz ilki okunup // gerisi atiliyordu → tek dev blok gorunuyordu, segment/aktivite yok). std::string ad; const std::size_t col = t.find(':', op); if (col != std::string_view::npos) { std::string_view a = sagKirp(solKirp(t.substr(col + 1))); ad.assign(a); } if (sonuc.operasyonAdi.empty() && !ad.empty()) sonuc.operasyonAdi = ad; aktiviteKapat(); aktiviteAc(std::move(ad)); continue; } // Baslik eksen: op ismi gorulmeden once, 4-sayili $$ satirlarini topla. if (sonuc.operasyonAdi.empty() && baslikEksen.size() < 12) { sayilariCikarTum(t, tmp); if (tmp.size() == 4) baslikEksen.insert(baslikEksen.end(), tmp.begin(), tmp.end()); } } continue; } // Davranisa etkisi olmayan / post katmaninin urettigi ifadeler: sessiz atla. // Gercekten taninmayan satir asagida sayilir (tani). if (komutuMu(t, "REWIND") || komutuMu(t, "CATMAT") || komutuMu(t, "END") || komutuMu(t, "FINI") || komutuMu(t, "MODE") || komutuMu(t, "DELAY") || komutuMu(t, "OPSTOP") || komutuMu(t, "STOP") || komutuMu(t, "SEQNO") || komutuMu(t, "RETRCT") || komutuMu(t, "INDIRV") || komutuMu(t, "TURRET") || komutuMu(t, "SELCTL") || komutuMu(t, "TRANS") || komutuMu(t, "MATRIX") || komutuMu(t, "COUPLE") || komutuMu(t, "LINTOL") || komutuMu(t, "THICK") || komutuMu(t, "TOLER") || komutuMu(t, "INTOL") || komutuMu(t, "OUTTOL") || komutuMu(t, "PSIS") || komutuMu(t, "DSIS") || komutuMu(t, "CSIS") || komutuMu(t, "AUXFUN") || komutuMu(t, "PREFUN") || komutuMu(t, "AIR") || komutuMu(t, "AUTO") || komutuMu(t, "AVOID") || komutuMu(t, "AVSOR") || komutuMu(t, "CLAMP") || komutuMu(t, "AVOTO")) continue; ++sonuc.bilinmeyenSatir; } aktiviteKapat(); // son operasyon blogunun hamle araligini kapat // Baslik eksen (3x4) → eksen vektorleri + origin (eski semantik). if (baslikEksen.size() >= 12) { sonuc.eksenX = {baslikEksen[0], baslikEksen[4], baslikEksen[8]}; sonuc.eksenY = {baslikEksen[1], baslikEksen[5], baslikEksen[9]}; sonuc.eksenZ = {baslikEksen[2], baslikEksen[6], baslikEksen[10]}; sonuc.eksenOrigin = {baslikEksen[3], baslikEksen[7], baslikEksen[11]}; } // ---- Rapid isareti: hamle vektoru uzerinde O(n) (metin YENIDEN taranmaz) ---- const f64 rapidEsik = maxFedrat > 0.0 ? maxFedrat * 0.95 : 1e300; auto& H = sonuc.yol.hamleler; for (std::size_t i = 0; i < H.size(); ++i) { const f32 f = hamleFedrat[i]; const bool anlikRapid = (f < 0.0f); // RAPID satiri sonrasi const bool rapid = anlikRapid || ((f64)f >= rapidEsik); H[i].tip = rapid ? HamleTip::Hizli : HamleTip::Kesme; H[i].ilerleme = rapid ? 0.0 : (f64)f; } // Hamle-basi eksen dizisi doluysa boyu hamlelerle BIREBIR olmali (sozlesme). if (!sonuc.hamleEksen.empty() && sonuc.hamleEksen.size() != H.size()) sonuc.hamleEksen.resize(H.size(), {(f32)sonuc.takimEkseni.x, (f32)sonuc.takimEkseni.y, (f32)sonuc.takimEkseni.z}); sonuc.yol.istatistikGuncelle(); sonuc.basarili = true; } } // namespace AptSonuc aptCoz(const std::string& metin, const AptOkuSecenek& sec) { AptSonuc sonuc; aptCozBuffer(metin.data(), metin.size(), sonuc, sec); return sonuc; } AptSonuc aptOku(const std::string& dosyaYolu, const AptOkuSecenek& sec) { AptSonuc sonuc; // Dosyayi TEK seferde binary oku (fread → tek buffer). getline yok. std::FILE* f = nullptr; #if defined(_WIN32) fopen_s(&f, dosyaYolu.c_str(), "rb"); #else f = std::fopen(dosyaYolu.c_str(), "rb"); #endif if (!f) { sonuc.hata = "APT dosyasi acilamadi: " + dosyaYolu; return sonuc; } std::fseek(f, 0, SEEK_END); const long uz = std::ftell(f); std::fseek(f, 0, SEEK_SET); if (uz <= 0) { std::fclose(f); sonuc.hata = "APT dosyasi bos: " + dosyaYolu; return sonuc; } std::string buf; buf.resize((std::size_t)uz); const std::size_t okunan = std::fread(buf.data(), 1, (std::size_t)uz, f); std::fclose(f); buf.resize(okunan); aptCozBuffer(buf.data(), buf.size(), sonuc, sec); return sonuc; } } // namespace fiko::cam