-- ArchiFrame Randek cnc-writer -- See www.lua.org for Lua manual. -- Extension functions - see manual --------------------------------------------------------------------------- -- CODE SHARED WITH ARCHIFRAME START --> EPS=0.0001 PI=3.141592653589793 PI2=PI/2.0 PI180=PI/180.0 PI1800=PI/1800.0 -- # Frame machinings types EMcFrAngledBegOld = 100 EMcFrAngledBeg = 101 EMcFrAngledBegTenon = 110 -- Also dovetail EMcFrBegHiddenShoe = 111 EMcVCutBeg = 114 EMcFrAngledEndOld = 200 EMcFrAngledEnd = 201 EMcFrAngledEndTenon = 210 EMcFrEndHiddenShoe = 211 EMcVCutEnd = 214 EMcFrOpening = 300 -- Opening - unused now EMcFrGroove = 301 -- Logsin tapainen vapaa ura EMcFrDrill = 302 -- Drilling EMcFrMarking = 303 -- Marking EMcFrReinforce = 304 EMcFrSaw = 305 EMcFrNailGroup = 306 EMcFrNailLine = 307 EMcFrTenonSide = 400 -- Also dovetail EMcFrBalkJoint = 401 -- Narrowed balk EMcFrBalkShoe = 1000 --------------------------------------------------------------------------- -- ARCHIFRAME & ARCHILOGS COMMON FUNCTIONS function toLog(str) ac_environment("tolog", str) end -- Dumps given variable into string function DumpTblInt(o) local s if type(o) == 'table' then s = '{ ' for k,v in pairs(o) do if type(k) ~= 'number' then k = '"'..k..'"' end s = s .. '['..k..'] = ' .. DumpTblInt(v) .. ',' end s=s .. '} ' else s=tostring(o) end return s end function DumpTbl(o) ac_environment("tolog", DumpTblInt(o)) end -- Table copy values function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end -- Returns 32bit binary number string "010011100..." function NumToBin(nVal) local nExp, sBin nExp=2147483648 sBin="" repeat if nVal+0.1>=nExp then nVal=nVal-nExp sBin=sBin .. "1" else sBin=sBin .. "0" end nExp=nExp/2 until nExp<0.9 if string.len(sBin)~=32 then error( "NumToBin failed" ) end return sBin end function BitTest(nVal, nBit0based) local s, s2 s=NumToBin(nVal) s2=string.sub(s, 32-nBit0based, 32-nBit0based) if s2=="0" then return 0 end if s2=="1" then return 1 end error( string.format("BitTest failed (s=%s, s2=%s)", s, s2) ) end -- Removes spaces from beg and end function TrimStr(str) local res, start, endIndex, len len=string.len(str) start=1 while start<=len and string.sub(str,start,start)==" " do start=start+1 end endIndex=len while endIndex>0 and string.sub(str,endIndex,endIndex)==" " do endIndex=endIndex-1 end return string.sub(str,start, endIndex) end -- Aiheuttaa virheilmoituksen, jonka Logs osaa tulkita käyttäjälle näytettäväksi viestiksi -- Ilmoitus voi olla tyhjä, jolloin ei näytetä mitään (peruttu) function RaiseError(msg) msg="###>" .. msg .. "<###" error( msg ) end gnCncErrCount=0 -- Notices for the log -- Adds cnc error message to gTblCncErr function AddErrMsg(sLogId, nPos, sText) if nPos==nil then error("AddCncErr/nPos") end if sText==nil then error("AddCncErr/sText") end if gnCncErrCount==0 then gTblCncErr={} end gnCncErrCount=gnCncErrCount+1 gTblCncErr[gnCncErrCount] = {} gTblCncErr[gnCncErrCount].guid=gsCurrentLogGuid gTblCncErr[gnCncErrCount].logid=sLogId gTblCncErr[gnCncErrCount].pos=nPos gTblCncErr[gnCncErrCount].text=sText end -- Adds cnc error message to gTblCncErr function AddCncErr(nPos, sText) AddErrMsg(gsCurrentLogId, nPos, sText) end gtblUsedIds = {} -- Tänne asetetaan ["id"]=1, että löydetään samalla ID:llä olevat hirret function CheckId( sId ) if sId=="" then local guid guid=ac_objectget("#guid") if guid==nil then guid="" else guid=" GUID=" .. guid end AddCncErr( 0, string.format("LOG/FRAME EMPTY ID FOUND" .. guid) ) elseif gtblUsedIds[sId]~=null then AddCncErr( 0, string.format("LOG/FRAME ID %s USED AT LEAST TWICE", sId) ) else gtblUsedIds[sId]=1 end end -- User entered values may be small if millimeters were used function NormalizeType(nNum) if math.abs(nNum)<0.1 then nNum=math.floor(nNum*1000+0.5) end return nNum end --------------------------------------------------------------------------- -- ARCHIFRAME & ARCHILOGS GEOMETRY FUNCTIONS -- ### Alustaa muuttujan tranTbl[] pyörittämään ja siirtämään pistettä -- Katso http://gregs-blog.com/category/3d-mathematics/ -- in: -- vecX,vecY,vecZ Vektori, jonka ympärillä pyöritellään. Yksikkövektori!! -- addX,addY,addZ Siirto -- angle Pyörityskulma -- out: -- tranTbl[12] function Rotate3Dinit(vecX, vecY, vecZ, addX, addY, addZ, angle) local cosAngle, sinAngle, ucosAngle, tranTbl cosAngle=math.cos(angle) sinAngle=math.sin(angle) ucosAngle=1-cosAngle tranTbl={} -- Tehdään yksikkövektori --_ulen=1/sqr(vecX*vecX+vecY*vecY+vecZ*vecZ) --vecX=vecX*_ulen --vecY=vecY*_ulen --vecZ=vecZ*_ulen tranTbl[1]=ucosAngle*vecX*vecX+cosAngle tranTbl[2]=ucosAngle*vecX*vecY-vecZ*sinAngle tranTbl[3]=ucosAngle*vecZ*vecX+vecY*sinAngle tranTbl[4]=addX tranTbl[5]=ucosAngle*vecX*vecY+vecZ*sinAngle tranTbl[6]=ucosAngle*vecY*vecY+cosAngle tranTbl[7]=ucosAngle*vecY*vecZ-vecX*sinAngle tranTbl[8]=addY tranTbl[9]=ucosAngle*vecZ*vecX-vecY*sinAngle tranTbl[10]=ucosAngle*vecY*vecZ+vecX*sinAngle tranTbl[11]=ucosAngle*vecZ*vecZ+cosAngle tranTbl[12]=addZ --tranTbl[13]=0 --tranTbl[14]=0 --tranTbl[15]=0 --tranTbl[16]=1 return tranTbl end -- ### Pyörittää 3D-pistettä annetun vektorin ympäri. Kutsu Rotate3Dinit ennen tätä. -- in: -- xin, yin, zin -- out: -- x, y, z function Rotate3D(tranTbl, xin, yin, zin) local x, y, z x=tranTbl[1]*xin + tranTbl[2]*yin + tranTbl[3]*zin + tranTbl[4] y=tranTbl[5]*xin + tranTbl[6]*yin + tranTbl[7]*zin + tranTbl[8] z=tranTbl[9]*xin + tranTbl[10]*yin + tranTbl[11]*zin + tranTbl[12] return x,y,z end -- ### Pyörittää 3D-pistettä annetun vektorin ympäri pitäen edellisen Rotate3DInit-arvot kuosissa -- in: -- xin, yin, zin, angle -- vecX, vecY, vecZ Minkä vektorin ympäri pyöritellään -- out: -- _x, _y, _z function RotateSingle3D(xin, yin, zin, vecX, vecY, vecZ, angle) local x, y, z, tranTbl tranTbl = Rotate3Dinit(vecX, vecY, vecZ, 0, 0, 0, angle) x,y,z=Rotate3D(tranTbl,xin, yin, zin) return x,y,z end -- Calculates cross product of two vectors -- Katsele http://en.wikipedia.org/wiki/Cross_product: On se suunta tälläkin tiedossa: vec1 on oikean käden etusormi, vec2 keskari ja refRes on sitten peukalo ylös -- returns x,y,z function CalcCross3D( x1, y1, z1, x2, y2, z2 ) local x,y,z x = y1 * z2 - z1 * y2 y = z1 * x2 - x1 * z2 z = x1 * y2 - y1 * x2 return x,y,z end -- Sets len to 1 -- Returns x,y,z,bOkVec (true/false=zero len) function ToUnitVec3(x, y, z) local d d=math.sqrt(x*x+y*y+z*z) if d<0.0001 then return 0,0,0,false end d=1/d return x*d,y*d,z*d,true end -- Duunaa tason yhtälön ax+bx+cx+dx=0 tason normaalista ja yhdestä pisteestä x1,y1,z1 -- Huom-- plane constant eri etumerkillä kuin wykobissa -- in: -- tnx, tny, tnz Vektori tason normaalista, lasketaan täällä yksikkövektoriksi -- x1,y1,z1 Piste tasolla -- out: -- ta, tb, tc, td Tason yhtälö (ta,tb,tc=tnx,tny,tnz normalisoituna) function MakePlaneNormal(tnx, tny, tnz, x1, y1, z1) -- template -- inline plane make_plane(const T& x1, const T& y1, const T& z1, -- const T& x2, const T& y2, const T& z2, -- const T& x3, const T& y3, const T& z3) -- { -- plane plane_; -- vector3d v1 = makevector(x2 - x1, y2 - y1, z2 - z1); -- vector3d v2 = makevector(x3 - x1, y3 - y1, z3 - z1); -- plane_.normal = normalize(v1 * v2); -- plane_.constant = dot_product(plane_.normal,makevector(x1,y1,z1)); -- return plane_; -- } local mul, ta, tb, tc, td -- Tässä hypätään suoraan vakion laskentaan mul=1/math.sqrt(tnx*tnx+tny*tny+tnz*tnz) ta=tnx*mul tb=tny*mul tc=tnz*mul td=-(ta*x1+tb*y1+tc*z1) return ta, tb, tc, td end -- ### Suoran ja tason leikkauspiste -- in: -- ta,tb,tc,td Tason yhtälö, a-c=kohtisuora ja d on vakio -- x1, y1, z1 Suora -- x2, y2, z2 Suora -- out: -- hasX Oliko leikkausta -- x, y, z Piste -- dist Etäisyys pisteestä x1,y1,z1 suoran suuntaisesti function LinePlaneX(ta, tb, tc, td, x1, y1, z1, x2, y2, z2 ) -- Tuollainen koodi "käännetty" wykobi-kirjastosta -- template -- inline point3d intersection_point(const line& line, -- const plane& plane) -- { -- vector3d linevec = line[1] - line[0]; -- T denom = dot_product(linevec,plane.normal); -- point3d ipoint = degenerate_point3d(); -- if (not_equal(denom,T(0.0))) -- { -- T t = -distance(line[0],plane) / denom; -- ipoint = line[0] + t * (line[1] - line[0]); -- } -- return ipoint; -- } local x, y, z, dist, denom dist=0 x=x2-x1 y=y2-y1 z=z2-z1 denom=x*ta + y*tb + z*tc -- Pistetulo suora ja tason normaali if math.abs(denom)<1E-5 then -- Tason suuntainen suora return false end -- Pisteen etäisyys tasolta -- (plane.normal.x * point.x + plane.normal.y * point.y + plane.normal.z * point.z ) - plane.constant; dist=-(ta*x1 + tb*y1 + tc*z1 + td)/denom -- Huom-- td eri etumerkillä kuin wykobissa (kun siellä oli puki) x=x1 + x*dist y=y1 + y*dist z=z1 + z*dist return true, x, y, z, dist end -- Returns unit vector 90 degrees left x,y for given vector function GetUnitVecLeft(x, y) local len len=math.sqrt(x*x+y*y) if len(x2,y2) and line2 is (x3,y3)->(x4,y4) -- See http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ -- Returns three values: -- 1. bool, true=has intersection -- 2. number, x -- 3. number, y function GetLinesX( x1, y1, x2, y2, x3, y3, x4, y4 ) local ua, divisor divisor=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1) if math.abs(divisor)straighty1 then straighty1=y1 end if not straighty2 or y2straighty2 then -- Should not happen? AddCncErr(0, string.format("WARNING: Unexpected straight y-coordinates in ending cuts, y1=%f y2=%f. Setting to mid.", straighty1, straighty2)) straighty1=(straighty1+straighty2)*0.5 straighty2=straighty1 end return straighty1,straighty2 end -- Pass possible groove saw cut here. Call only if nCuts>=1 -- xend X-coordinate at the current end (0=begin, len=end of the plank) -- Returns cnc-text for cuts function AddCuts(tblCuts, nCuts, isBeg, xend, rotated) local i, v, angle, bevel, s, tblInfo, tblRes s="" --toLog(string.format("isBeg=%s", tostring(isBeg))) -- Plank orientation: bottom (3) towards operator and front (2) pointing up -- Calc cut lines for i=1,nCuts do v=tblCuts[i] tblInfo={} tblInfo.guid = gsCurrentLogGuid tblInfo.mcindex = v.mcindex tblInfo.cutlineside=4 -- On back surface pointing down against the table tblRes = af_request("mc_getcutinfo", tblInfo) if rotated then -- Swapped top&bottom or in other words rotated 180 deg tblRes.y1=gnCurrHeight-tblRes.y1 tblRes.y2=gnCurrHeight-tblRes.y2 tblRes.btl_p06=PI-tblRes.btl_p06 tblRes.btl_p07=PI-tblRes.btl_p07 end angle=tblRes.btl_p06*180/PI bevel=180-tblRes.btl_p07*180/PI --toLog(string.format("tblInfo.mcindex=%d: angle=%f bevel=%f", tblInfo.mcindex, angle, bevel)) tblRes.angle=angle tblRes.bevel=bevel if tblRes.y1>tblRes.y2 then -- Make line from bottom to top tblRes.x1,tblRes.y1,tblRes.x2,tblRes.y2=tblRes.x2,tblRes.y2,tblRes.x1,tblRes.y1 end v.cutinfo=tblRes --toLog(string.format("x1=%f y1=%f x2=%f y2=%f", tblRes.x1,tblRes.y1,tblRes.x2,tblRes.y2)) end table.sort(tblCuts, function (v1, v2) return v1.cutinfo.y1 > v2.cutinfo.y1 end) if nCuts>2 then AddCncErr(xend, string.format("WARNING: Plank has %d cuts - taking only two first ones", nCuts)) nCuts=2 end -- calc in plank surface coords local straighty1, straighty2 --toLog(string.format("v.cutinfo.x1=%f, v.cutinfo.y1=%f, v.cutinfo.x2=%f, v.cutinfo.y2=%f", v.cutinfo.x1, v.cutinfo.y1, v.cutinfo.x2, v.cutinfo.y2)) v=tblCuts[1] if math.abs(xend-v.cutinfo.x2)<0.001 and v.cutinfo.y2+0.00010.0001 then -- Straight at bottom straighty1,straighty2=AddStraight(straighty1,straighty2, 0, v.cutinfo.y1) end if nCuts>1 then -- Add second cut which must be lower than first one v=tblCuts[2] if math.abs(xend-v.cutinfo.x2)<0.001 and v.cutinfo.y2+0.00010.0001 then -- Straight at bottom straighty1,straighty2=AddStraight(straighty1,straighty2, 0, v.cutinfo.y1) end if math.abs(tblCuts[1].cutinfo.bevel-90)>0.1 and math.abs(tblCuts[2].cutinfo.bevel-90)>0.1 then -- Can be hip cut that we don't support now AddCncErr(xend, string.format("WARNING: Plank has multiple bevel cuts - hip cut not supported, please check the result")) end end -- Build table having straight cut also if straighty1 and math.abs(straighty1-straighty2)>0.001 then -- Add straight cut also local t t={} t.cutinfo={} t.cutinfo.y1=straighty1 t.cutinfo.x1=xend t.cutinfo.y2=straighty2 t.cutinfo.x2=xend t.cutinfo.angle=90 t.cutinfo.bevel=90 t.mcindex=0 -- Should never be used t.straight=true nCuts=nCuts+1 tblCuts[nCuts]=t end table.sort(tblCuts, function (v1, v2) return v1.cutinfo.y1 > v2.cutinfo.y1 end) local basea -- Base index for angle local baseb, nbevel -- Base index for inclination -- Calc first cut basea=1 baseb=1 nbevel=0 -- if isBeg then basea=4 baseb=3 end for i=1,nCuts do v=tblCuts[i] s=s .. string.format("fdtSaw_Angle[%d] := %0.1f\n", basea+i-1, v.cutinfo.angle) if not v.straight then -- Straight cut will not have bevel s=s .. string.format("fdtSaw_Inclination[%d] := %0.1f\n", baseb+nbevel, v.cutinfo.bevel) nbevel=nbevel+1 end end while nCuts<3 do s=s .. string.format("fdtSaw_Angle[%d] := -1\n", basea+nCuts) nCuts=nCuts+1 end while nbevel<2 do s=s .. string.format("fdtSaw_Inclination[%d] := -1\n", baseb+nbevel) nbevel=nbevel+1 end -- Forget about hip cut for now local stop, sbot stop="-1" sbot=stop --toLog(string.format("straighty1=%s straighty2=%s", tostring(straighty1), tostring(straighty2))) if straighty1 then local y1, y2 y1=gnProfHeight-straighty2 -- Swap coordinate dir y2=gnProfHeight-straighty1 sbot=RandekLen2Str(y2) stop=RandekLen2Str(y1) if math.abs(y2-y1)gnCurrWidth and math.abs(groAngle)gnCurrWidth) then if nDrills==10 then AddCncErr( x1, "WARNING: DRILLING SKIPPED, TOO MANY - MAX 10 ALLOWED" ) end local t t={} t.x1=x1 t.y1=y1 t.dia=groWidth nDrills=nDrills+1 tblDrills[nDrills]=t else AddCncErr( x1, "WARNING: UNSUITABLE DRILL SKIPPED FOR RANDEK" ) end elseif nType==EMcFrSaw then -- Lengthwise sawing logFace =ac_objectget("iMc", i, 2) xStart =ac_objectget("iMc", i, 3) -- +begExtra dWidth =ac_objectget("iMc", i, 4) dDepthTop =ac_objectget("iMc", i, 5) dYoffTop =ac_objectget("iMc", i, 6) dAngleY2Deg =ac_objectget("iMc", i, 7) dAngleY1Deg =ac_objectget("iMc", i, 8) BtlAddSaw( sPieceNum, logFace, xStart, dWidth, dDepthTop, dYoffTop, dAngleY2Deg, dAngleY1Deg ) AddCncErr( ac_objectget("iMc", i, 2), "LENGTHWISE CUT SKIPPED FOR RANDEK" ) elseif nType==EMcFrBalkShoe or nType==EMcFrReinforce or nType==EMcFrNailLine then -- NOP on purpose elseif nType~=0 then AddCncErr( ac_objectget("iMc", i, 2), string.format("UNSUPPORTED MACHINING %d", nType) ) end end local rotated -- If need to rotate for grooves if #tblGrosBot>0 then if #tblGrosTop==0 then -- Rotate the plank so that the bottom will be towards the milling unit and top towards the operator local k,v for k,v in ipairs(tblDrills) do v.y1=gnCurrHeight-v.y1 end tblGrosTop,tblGrosBot=tblGrosBot,tblGrosTop rotated=true else AddCncErr( 0, "WARNING: MILLINGS ON BOTH TOP AND BOTTOM SIDE OF THE PLANK - ONLY TOP ONES IN THE CNC-FILE" ) end end -- Randek plank placement: begin at left, end at right, base line towards operator, face 2/front pointing up local tblInfo, tblRes if nEndCuts>0 then gsCncText = gsCncText .. AddCuts(tblEndCuts, nEndCuts, false, gnCurrTotLen, rotated) else -- Add straight cut to left s="fdtSaw_Angle[1] := 90\n" s=s .. "fdtSaw_Angle[2] := -1\n" s=s .. "fdtSaw_Angle[3] := -1\n" s=s .. "fdtSaw_Inclination[1] := 90\n" s=s .. "fdtSaw_Inclination[2] := -1\n" s=s .. "fdtSaw_Centerline_Top_Right := -1\n" s=s .. "fdtSaw_Centerline_Bottom_Right := -1\n" s=s .. "fdtSaw_Hipend_Height_Right := -1\n" gsCncText = gsCncText .. s end if nBegCuts>0 then gsCncText = gsCncText .. AddCuts(tblBegCuts, nBegCuts, true, 0, rotated) else -- Add straight cut to left s="fdtSaw_Angle[4] := 90\n" s=s .. "fdtSaw_Angle[5] := -1\n" s=s .. "fdtSaw_Angle[6] := -1\n" s=s .. "fdtSaw_Inclination[3] := 90\n" s=s .. "fdtSaw_Inclination[4] := -1\n" s=s .. "fdtSaw_Centerline_Top_Left := -1\n" s=s .. "fdtSaw_Centerline_Bottom_Left := -1\n" s=s .. "fdtSaw_Hipend_Height_Left := -1\n" gsCncText = gsCncText .. s end if nDrills>0 then local v s="" for i=1,nDrills do v=tblDrills[i] s=s .. string.format("fdtLeftDrillLength[%d] := %s\nfdtDrillCenterline[%d] := %s\nfdtDrillDiameter[%d] := %s\n", i, RandekLen2Str(v.x1), i, RandekLen2Str(v.y1), i, RandekLen2Str(v.dia)) end while nDrills<10 do nDrills=nDrills+1 s=s .. string.format("fdtLeftDrillLength[%d] := 0\nfdtDrillCenterline[%d] := 0\nfdtDrillDiameter[%d] := 0\n", nDrills, nDrills, nDrills) end gsCncText = gsCncText .. s end if #tblGrosTop>0 then -- Only top grooves can be written (perhaps swapped earlier) local v, left, right i=0 while true do i=i+1 v=tblGrosTop[i] if not v then break end left=0 right=0 -- Beginning is at the right hand side, prefer left --toLog(string.format("v.x1=%f v.x2=%f", v.x1, v.x2)) left=v.x1 if math.abs(left)<0.001 then left=0 right=-gnCurrTotLen+v.x1 -- Must be negative! end s="" s=s .. string.format("fdtLeftMillLength[%d] := %0.0f\nfdtMillLength[%d] := %0.0f\nfdtRightMillLength[%d] := %0.0f\n", i, 1000*left, i, 1000*(v.x2-v.x1), i, 1000*right) s=s .. string.format("fdtMillDepth[%d] := %0.0f\nfdtMillAngle[%d] := 90\n", i, 1000*v.depth, i) gsCncText = gsCncText .. s end end end -- Called before writing new cnc-file - resets globals function BvnOnInit() gnCncErrCount=0 gtblUsedIds = {} end -- CODE SHARED WITH ARCHIFRAME END <-- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- ARCHIFRAME ONLY -- Called before save as dialog is showed -- strPlnFileName -> Full path file name of current pln WITHOUT extension (.pln removed) -- Return values (multiple ret values): -- 1=listing file name WITH extension, ""=Just prompt with file dlg, starting with *=result contains full path name - do not prompt -- 2=file extension to be used in save as dialog function OnInit(strPlnFileName) local projNum = ac_environment("parsetext", "") BvnOnInit() sFileName=projNum .. ".001" sExt="001" return sFileName, sExt end function SettingsDlg() return true --[[ local tblSettings tblSettings={} tblSettings[1] ={} tblSettings[1].cfgonly =1 tblSettings[1].type =3 tblSettings[1].prompt ="Start and end offset (extra at begin and end of each piece)" tblSettings[1].key ="btlbeoffsets" tblSettings[1].defvalue =0.020 bRes,sErr=ac_optiondlg("LDRW", "Randek-writing settings", tblSettings) if not bRes then return false end gnRandekStartEndOffset=tblSettings[1].value return true ]] end -- Returns path,file name and extension. nil=cannot find function SplitFileName(strPathName) local path, fname, ext local i, c, extIndex i=string.len(strPathName) extIndex=i while i>0 do c=string.sub(strPathName, i, i) if ext==nil and c=="." then ext=string.sub(strPathName, i, string.len(strPathName)) extIndex=i-1 elseif fname==nil and (c=="\\" or c=="/") then fname=string.sub(strPathName, i+1, extIndex) path=string.sub(strPathName, 1, i) break end i=i-1 end return path,fname,ext end -- Called to do all that needs to be done -- strFileName is full path name for the result file function OnSaveList(strFileName) if not SettingsDlg() then gbCancel=true return end local i, v, nSimilarCount, fileNum, fileName, path, fname, ext, hFile path, fname, ext=SplitFileName(strFileName) -- Remove all files until fails fileNum=0 while true do fileNum=fileNum+1 fileName=string.format("%s%s.%03d", path, fname, fileNum) if not os.remove(fileName) then break end end if fileNum>1 then toLog(string.format("Deleted files %s%s.001 ... %s%s.%03d", path, fname, path, fname, fileNum-1)) end -- Start writing i=1 fileNum=0 while true do v=gTblPlanks[i] if v==nil then break end ac_objectopen(v) gsCurrentLogId=ac_objectget("#id") CheckId(gsCurrentLogId) -- Lasketaan montako on samalla id:llä ja täräytetään ne kerralla nSimilarCount=1 ac_objectclose() while gTblPlanks[i+nSimilarCount]~=nil do ac_objectopen(gTblPlanks[i+nSimilarCount]) if gsCurrentLogId~=ac_objectget("#id") then ac_objectclose() break end nSimilarCount=nSimilarCount+1 ac_objectclose() end ac_objectopen(v) WriteRandekPlank(v, nSimilarCount) ac_objectclose(v) -- To file fileNum=fileNum+1 fileName=string.format("%s%s.%03d", path, fname, fileNum) hFile=io.open(fileName, "wt") if not hFile then toLog(string.format("Failed to open file %s for writing", fileName)) else io.output( hFile ) io.write( gsCncText ) io.close( hFile ) end i=i+nSimilarCount end toLog(string.format("Wrote files %s%s.001 ... %s%s.%03d", path, fname, path, fname, fileNum)) gsCncText=nil end ----------------------------------------------------------------------------- -- Randek specific constants