diff --git a/BatchProcess.lua b/BatchProcess.lua index 25a3dd3..1040de1 100644 --- a/BatchProcess.lua +++ b/BatchProcess.lua @@ -1,8 +1,11 @@ --- BatchProcess.lua by Egaltech s.r.l. 2020/12/03 +-- BatchProcess.lua by Egaltech s.r.l. 2021/03/08 -- Gestione calcolo batch disposizione e lavorazioni per Pareti -- 2020/07/24 Nuvola di punti riferita allo Zero Tavola. -- 2020/10/28 Corretto spostamento pezzi per rotazioni (0 o 180) e inversioni( 0, 90, 180, o 270). --- 2020/12/03 Ora riconosciute rotazioni di inversione con angoli negativi. +-- 2020/12/03 Ora riconosciute rotazioni di inversione con angoli negativi. +-- 2021/03/05 Aggiunta gestione altri angoli di inversione e rotazione combinati. +-- 2021/03/06 La creazione del file ori si fa solo alla fine se non ci sono stati errori o se edit. +-- 2021/03/08 Aggiunta gestione lavorazione su macchine per travi. -- Intestazioni @@ -181,8 +184,6 @@ if bToProcess then PostErrView( WALL.ERR, WALL.MSG) return end - -- faccio copia del file btl originale - EgtCopyFile( WALL.FILE, sDir..sTitle..'.ori'..sExt) -- altrimenti Nge, lo apro else if not EgtOpenFile( WALL.FILE) then @@ -192,8 +193,6 @@ if bToProcess then PostErrView( WALL.ERR, WALL.MSG) return end - -- faccio copia del file originale - EgtCopyFile( WALL.FILE, sDir..sTitle..'.ori'..sExt) end -- Aggiorno eventuali dati ausiliari @@ -312,6 +311,8 @@ if bToProcess then vWall[i].PosX = vWall[i].PosX - vWall[i].Box:getDimX() if abs( dRotAng - 0) < GEO.EPS_ANG_SMALL then vWall[i].PosZ = vWall[i].PosZ - vWall[i].Box:getDimY() + elseif abs( dRotAng - 180) < GEO.EPS_ANG_SMALL or abs( dRotAng + 180) < GEO.EPS_ANG_SMALL then + vWall[i].PosX = vWall[i].PosX + vWall[i].Box:getDimX() end elseif abs( dInvAng - 270) < GEO.EPS_ANG_SMALL or abs( dInvAng + 90) < GEO.EPS_ANG_SMALL then if abs( dRotAng - 0) < GEO.EPS_ANG_SMALL then @@ -420,6 +421,11 @@ if bToProcess then -- Salvo il progetto EgtSaveFile( sNgeFile) + -- Se non ci sono errori o modalità modifica, salvo il file originale + if nErrCnt == 0 or WALL.FLAG == 1 then + EgtCopyFile( WALL.FILE, sDir..sTitle..'.ori'..sExt) + end + -- Visualizzazione avvisi o errori if #sOutput > 0 then EgtOutLog( sOutput) end if nErrCnt > 0 then diff --git a/LuaLibs/WMachiningLib.lua b/LuaLibs/WMachiningLib.lua index 8fb75e5..35d2dcc 100644 --- a/LuaLibs/WMachiningLib.lua +++ b/LuaLibs/WMachiningLib.lua @@ -1,4 +1,4 @@ --- MachiningLib.lua by Egaltech s.r.l. 2020/06/24 +-- MachiningLib.lua by Egaltech s.r.l. 2021/03/05 -- Libreria ricerca lavorazioni per Pareti -- Tabella per definizione modulo @@ -55,6 +55,19 @@ function WMachiningLib.FindMilling( sType, dDepth, sTuuidMstr) end end +--------------------------------------------------------------------- +function WMachiningLib.FindNailing( nType) + for i = 1, #Millings do + local Milling = Millings[i] + if Milling.On and Milling.Type == 'Nailing' and SetCurrMachiningAndTool( Milling.Name) then + local sTName = EgtTdbGetCurrToolParam( MCH_TP.NAME) + if sTName == tostring( nType) then + return Milling.Name + end + end + end +end + --------------------------------------------------------------------- function WMachiningLib.FindPocketing( sType, dMaxDiam, dDepth) for i = 1, #Pocketings do diff --git a/LuaLibs/WProcessDrill.lua b/LuaLibs/WProcessDrill.lua index 5944089..640f8a5 100644 --- a/LuaLibs/WProcessDrill.lua +++ b/LuaLibs/WProcessDrill.lua @@ -138,6 +138,7 @@ function WPD.Make( Proc, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- eventuale inversione diff --git a/LuaLibs/WProcessFreeContour.lua b/LuaLibs/WProcessFreeContour.lua index 8ca5890..010fd7f 100644 --- a/LuaLibs/WProcessFreeContour.lua +++ b/LuaLibs/WProcessFreeContour.lua @@ -128,6 +128,11 @@ local function VerifyCornerType( Proc) return nConeCut end +--------------------------------------------------------------------- +local function IsPointOnRawLongEdges( ptCen, b3Raw) + return ( abs( ptCen:getY() - b3Raw:getMin():getY()) < 0.1 or abs( ptCen:getY() - b3Raw:getMax():getY()) < 0.1) +end + --------------------------------------------------------------------- local function GetOtherRegions( nPartId) local vOthers = {} @@ -215,7 +220,6 @@ end --------------------------------------------------------------------- local function RemoveBottomFaceAndReorder( Proc, nAddGrpId, nFaceToDel) - -- copio la superfice nel gruppo ausiliario local nNewProc = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL EgtSurfTmRemoveFacet( nNewProc, nFaceToDel) @@ -225,38 +229,17 @@ local function RemoveBottomFaceAndReorder( Proc, nAddGrpId, nFaceToDel) end --------------------------------------------------------------------- -local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMaxDepth, dToolThick, nAddGrpId, bDeleteBottomface, nMasterNewProc) - +local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMaxDepth, dToolThick, nAddGrpId, b3Raw, nMasterNewProc) + --se richiesto, copio la superficie nel gruppo ausiliario local nNewProc if nMasterNewProc then nNewProc = nMasterNewProc else nNewProc = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL end - -- copio la superfice nel gruppo ausiliario - local nNumFacet - if bDeleteBottomface then - -- recupero la faccia che ha versore Z maggiore delle altre per escluderla - local dZMax = -1 - local dBottomFace = 0 - for i = 1, Proc.Fct do - local _, vtN = EgtSurfTmFacetCenter( nNewProc, i-1, GDB_ID.ROOT) - if vtN:getZ() > dZMax then - dZMax = vtN:getZ() - dBottomFace = i - end - end - if dBottomFace > 0 then - EgtSurfTmRemoveFacet( nNewProc, dBottomFace-1) - end - nNumFacet = EgtSurfTmFacetCount( nNewProc) - nNewProc = ReorderFaces( nNewProc, nNumFacet) - else - nNumFacet = EgtSurfTmFacetCount( nNewProc) - end - - local vFace = {} -- recupero i dati di tutte le facce + local vFace = {} + local nNumFacet = EgtSurfTmFacetCount( nNewProc) for i = 1, nNumFacet do -- indice faccia corrente e precedente local nFac = EgtIf( bOpposite, nNumFacet - i, i - 1) @@ -272,8 +255,11 @@ local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMa local _, dLen, dWidth = WL.GetFaceHvRefDim( nNewProc, nFac) -- recupero l'angolo con la faccia precedente local bAdj, ptLocP1, ptLocP2, dAng = EgtSurfTmFacetsContact( nNewProc, nPrecFac, nFac, GDB_ID.ROOT) + local dPrevAng = EgtIf( bAdj, dAng, 0) + -- calcolo l'angolo di inclinazione (dalla verticale) + local dSideAng = asin( vtN:getZ()) -- salvo i dati - vFace[i] = { Fac = nFac, Cen = ptCen, Norm = vtN, Len = dLen, Width = dWidth, AngPrev = EgtIf( bAdj, dAng, 0)} + vFace[i] = { Fac = nFac, Cen = ptCen, Norm = vtN, Len = dLen, Width = dWidth, PrevAng = dPrevAng, SideAng = dSideAng} if bAdj then if ptLocP1:getZ() < ptLocP2:getZ() then vFace[i].PPrev = ptLocP1 @@ -300,11 +286,11 @@ local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMa -- determino la lunghezza del taglio passante e il tipo di attacco e uscita local dLen = vFace[i].Len local nType = 0 - if vFace[i].AngPrev < -0.1 then + if vFace[i].PrevAng < -0.1 or ( WD.BEAM_MACHINE and not IsPointOnRawLongEdges( vFace[i].Cen, b3Raw)) then dLen = dLen - EgtIf( bCalclForBlade, dWhisk, 0) nType = nType + 1 end - if vFace[EgtIf( i < nNumFacet, i + 1, 1)].AngPrev < -0.1 then + if vFace[EgtIf( i < nNumFacet, i + 1, 1)].PrevAng < -0.1 or ( WD.BEAM_MACHINE and not IsPointOnRawLongEdges( vFace[i].Cen, b3Raw)) then dLen = dLen - EgtIf( bCalclForBlade, dWhisk, 0) nType = nType + 2 end @@ -378,22 +364,22 @@ local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMa end end -- se ciclo chiuso - if ( abs( vFace[1].AngPrev) > 0.1) then - -- verifico se c'è un solo tipo 3 e nessun tipo 1 o 2 + if ( abs( vFace[1].PrevAng) > 0.1) then + -- verifico se c'è un solo tipo 3 e nessun tipo 0, 1 o 2 local nInd3 local nTot3 = 0 - local nTot12 = 0 + local nTot012 = 0 for i = 1, #vFace do local Face = vFace[i] - if Face.Type == 1 or Face.Type == 2 then - nTot12 = nTot12 + 1 + if Face.Type == 0 or Face.Type == 1 or Face.Type == 2 then + nTot012 = nTot012 + 1 elseif Face.Type == 3 then nTot3 = nTot3 + 1 nInd3 = i end end -- se trovato il caso, trasformo il 3 in 4 (per evitare problemi con fresature con la stessa faccia a inizio e fine) - if nTot3 == 1 and nTot12 == 0 then + if nTot3 == 1 and nTot012 == 0 then vFace[nInd3].Type = 4 end end @@ -401,8 +387,8 @@ local function GetFacesData( Proc, bOpposite, bCalclForBlade, dToolDiam, dToolMa for i = 1, #vFace do local Face = vFace[i] local sOut = 'Face '..tostring( Face.Fac)..' C'..tostring( Face.Cen)..' N'..tostring( Face.Norm).. - ' L='..EgtNumToString( Face.Len, 1)..' W='..EgtNumToString( Face.Width, 1)..' Ap='..EgtNumToString( Face.AngPrev, 1).. - ' D='..EgtNumToString( Face.Depth, 1)..' B='..EgtNumToString( Face.Whisk, 1)..' T='..tostring( Face.Type) + ' L='..EgtNumToString( Face.Len, 1)..' W='..EgtNumToString( Face.Width, 1)..' Ap='..EgtNumToString( Face.PrevAng, 1).. + ' D='..EgtNumToString( Face.Depth, 1)..' B='..EgtNumToString( Face.Whisk, 1).. ' As='..EgtNumToString( Face.SideAng, 1)..' T='..tostring( Face.Type) EgtOutLog( sOut) end @@ -687,7 +673,7 @@ local function MakeLocalSurf( ptP1, ptP2, ptP3, nAddGrpId) end --------------------------------------------------------------------- -local function AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, +local function AddMillCornerMachining( nPartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, dOffsAng, dDepthMach, bThruThick, dThSurf, dDiam1, dDiam2, dTall1, dTall2, dDiam3, dTall3, bMakeLocSurf, vFace) @@ -887,6 +873,7 @@ local function AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', nPartId) -- se flag lavorazione spessore passante setto la nota per spostarla dopo i tagli di lama if bThruThick and nTypeConeCut == 1 then EgtSetInfo( nMchId, 'MOVE_AFTER', 1) @@ -1003,7 +990,7 @@ local function AddMillCorner( nTypeConeCut, vFace, Proc, nRawId, b3Raw, bMakeLocSurf = true end -- verifico se ciclo chiuso - local bClosed = ( abs( vFace[1].AngPrev) > 0.1) + local bClosed = ( abs( vFace[1].PrevAng) > 0.1) -- ciclo di inserimento delle fresate sulle facce del contorno in esame local i = 1 -- se faccia finale con fine non lavorato, forzo partenza da prima faccia non tutta saltata (tipo 4) @@ -1057,20 +1044,20 @@ local function AddMillCorner( nTypeConeCut, vFace, Proc, nRawId, b3Raw, if nTypeConeCut == 1 and bMakeTwinCut and (dAng + 90) > 2 then local dAngOffs = (dAng + 90) / 2 -- primo taglio - local bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, -dAngOffs, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) if not bOk then return bOk, sErr end -- secondo taglio - bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, dAngOffs, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) if not bOk then return bOk, sErr end -- altrimenti ho un solo percorso else - local bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, 0, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) @@ -1105,7 +1092,7 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd end end -- verifico se ciclo chiuso - local bClosed = ( abs( vFace[1].AngPrev) > 0.1) + local bClosed = ( abs( vFace[1].PrevAng) > 0.1) -- ciclo di inserimento delle fresate sulle facce del contorno in esame local i = 1 -- se faccia finale con fine non lavorato, forzo partenza da prima faccia non tutta saltata (tipo 4) @@ -1119,11 +1106,8 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd if bAllType4 then i = 1 end while i <= #vFace do -- se inizio faccia senza taglio e non è successiva di senza taglio, inserisco una fresatura - local j - if abs( vFace[i].AngPrev) > 0.1 then - j = EgtIf( i == 1, #vFace, i - 1) - end - if ( vFace[i].Type & 1) ~= 0 and ( not j or ( vFace[j].Type == 0 or vFace[j].Type == 1)) then + local j = EgtIf( i > 1, i - 1, EgtIf( bClosed, #vFace, nil)) + if ( vFace[i].Type & 1) ~= 0 and ( not j or ( vFace[j].Type == 0 or vFace[j].Type == 1) or abs( vFace[j].SideAng - vFace[i].SideAng) > 0.1) then -- inserisco la lavorazione local sName = 'Free_' .. ( EgtGetName( Proc.PartId) or tostring( Proc.PartId)) local nMchId = EgtAddMachining( sName, sMilling) @@ -1132,6 +1116,7 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd EgtOutLog( sErr) return 0, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- calcolo l'affondamento local dDepth = vFace[i].Width + WD.CUT_EXTRA dThick = dDepth @@ -1184,6 +1169,7 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd EgtOutLog( sErr) return 0, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- calcolo l'affondamento local dDepth = vFace[i].Width + WD.CUT_EXTRA dThick = dDepth @@ -1203,9 +1189,10 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd local vGeom = {{ Proc.Id, vFace[i].Fac}} local dSal = EgtIf( ( vFace[i].Type & 2) ~= 0, vFace[i].Whisk - vFace[i].Len, 0) local dEal = 0 + local OrigI = i i = i + 1 local j = EgtIf( i <= #vFace, i, EgtIf( bAllType4, nil, 1)) - while j and ( ( vFace[j].Type & 1) ~= 0 or vFace[j].Type == 4) do + while j and ( ( vFace[j].Type & 1) ~= 0 or vFace[j].Type == 4) and abs( vFace[j].SideAng - vFace[OrigI].SideAng) < 0.1 do table.insert( vGeom, { Proc.Id, vFace[j].Fac}) dEal = EgtIf( ( vFace[j].Type & 1) ~= 0, vFace[j].Whisk - vFace[j].Len, 0) if ( vFace[j].Type & 1) ~= 0 then @@ -1288,6 +1275,61 @@ local function AddMillings( sMilling, vFace, Proc, nRawId, b3Raw, nConeCut, nAdd i = i + 1 end end + -- aggiungo eventuali fresature a metà faccia + for i =1, #vFace do + if vFace[i].Split then + -- inserisco la lavorazione + local sName = 'Free_' .. ( EgtGetName( Proc.PartId) or tostring( Proc.PartId)) .. '_M' + local nMchId = EgtAddMachining( sName, sMilling) + if not nMchId then + local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling + EgtOutLog( sErr) + return 0, sErr + end + EgtSetInfo( nMchId, 'Part', Proc.PartId) + -- calcolo l'affondamento + local dDepth = vFace[i].Width + WD.CUT_EXTRA + dThick = dDepth + local vtNz = vFace[i].Norm:getZ() + if vtNz < 0 then + dDepth = dDepth - dMillDiam * abs( vtNz) / sqrt( 1 - vtNz * vtNz) + end + -- se affondamento superiore ai limiti della fresa + if dDepth > dMaxDepth then + dOriDepth = dDepth + -- lo limito e tolgo eventuali Tabs + dDepth = dMaxDepth + EgtSetMachiningParam( MCH_MP.LEAVETAB, false) + bNotThrou = true + end + -- aggiungo geometria + EgtSetMachiningGeometry( {{ Proc.Id, vFace[i].Fac}}) + local dSal = vFace[i].Whisk - vFace[i].Len / 2 + local dEal = vFace[i].Whisk - vFace[i].Len / 2 + EgtSetMachiningParam( MCH_MP.STARTADDLEN, dSal) + EgtSetMachiningParam( MCH_MP.ENDADDLEN, dEal) + -- percorso da non invertire + EgtSetMachiningParam( MCH_MP.INVERT, false) + -- assegno utilizzo faccia + EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.PARAL_DOWN) + -- assegno affondamento + EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) + -- assegno lato di lavoro + EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.RIGHT) + -- posizione braccio porta testa + local nSCC = MCH_SCC.ADIR_ZP + if abs( vFace[i].Norm:getZ()) < GEO.EPS_SMALL then + nSCC = MCH_SCC.ADIR_YP + end + EgtSetMachiningParam( MCH_MP.SCC, nSCC) + -- eseguo + if not EgtApplyMachining( true, false) then + local _, sErr = EgtGetLastMachMgrError() + EgtSetOperationMode( nMchId, false) + return 0, sErr + end + end + end -- se fresature non sono passanti if bNotThrou then return 2, dMillDiam, dThick @@ -1324,6 +1366,7 @@ local function AddSawings( sSawing, vFace, Proc, nRawId, b3Raw) EgtOutLog( sErr) return 0, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- calcolo l'affondamento -- local dDepth = min( vFace[i].Width + WD.CUT_EXTRA, dMaxDepth) local dDepth = vFace[i].Width + WD.CUT_EXTRA @@ -1365,6 +1408,7 @@ local function AddSawings( sSawing, vFace, Proc, nRawId, b3Raw) EgtOutLog( sErr) return 0, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- calcolo l'affondamento -- local dDepth = min( vFace[i].Width + WD.CUT_EXTRA, dMaxDepth) local dDepth = vFace[i].Width + WD.CUT_EXTRA @@ -1411,8 +1455,10 @@ end local function AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) -- ciclo di inserimento dei tagli sulle facce del contorno in esame for i = 1, #vFace do + -- verifico se faccia da saltare, perchè macchina travi e faccia su bordo longitudinale esterno già finito + local bToSkip = ( WD.BEAM_MACHINE and IsPointOnRawLongEdges( vFace[i].Cen, b3Raw)) -- se non è faccia da saltare, inserisco il taglio di lama - if vFace[i].Type ~= 4 then + if not bToSkip and vFace[i].Type ~= 4 then -- indice del successivo local j = EgtIf( i < #vFace, i + 1, 1) -- inserisco la lavorazione @@ -1423,6 +1469,7 @@ local function AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( { { Proc.Id, vFace[i].Fac}}) -- assegno affondamento @@ -1446,7 +1493,7 @@ local function AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) nLeadIn = MCH_SAW_LI.STRICT end EgtSetMachiningParam( MCH_MP.LEADINTYPE, nLeadIn) - if ( not bInvert and vFace[i].AngPrev < -0.1) or ( bInvert and vFace[j].AngPrev < -0.1) then + if ( not bInvert and vFace[i].PrevAng < -0.1) or ( bInvert and vFace[j].PrevAng < -0.1) then EgtSetMachiningParam( MCH_MP.STARTADDLEN, -WHISK_SAFE) end -- assegno i dati di uscita (sicurezza solo se angolo interno) @@ -1455,7 +1502,7 @@ local function AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) nLeadOut = MCH_SAW_LO.STRICT end EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, nLeadOut) - if ( not bInvert and vFace[j].AngPrev < -0.1) or ( bInvert and vFace[i].AngPrev < -0.1) then + if ( not bInvert and vFace[j].PrevAng < -0.1) or ( bInvert and vFace[i].PrevAng < -0.1) then EgtSetMachiningParam( MCH_MP.ENDADDLEN, -WHISK_SAFE) end -- posizione braccio porta testa @@ -1466,13 +1513,28 @@ local function AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) EgtSetOperationMode( nMchId, false) return false, sErr end + -- se limite lunghezza di taglio e taglio lo supera + if WD.CUT_MAX_LENGTH and vFace[i].Len > WD.CUT_MAX_LENGTH then + -- sdoppio la lavorazione + local sSouName = EgtGetName( nMchId) + local nNewMchId = EgtCopyMachining( sSouName..'_B', sSouName) + --accorciamento iniziale della seconda + EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_SAW_LI.STRICT) + EgtSetMachiningParam( MCH_MP.STARTADDLEN, -vFace[i].Len/2) + --accorciamento finale della prima + EgtSetCurrMachining( nMchId) + EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_SAW_LO.STRICT) + EgtSetMachiningParam( MCH_MP.ENDADDLEN, -vFace[i].Len/2) + -- segnalo spezzatura lavorazione faccia + vFace[i].Split = true + end end end return true end --------------------------------------------------------------------- -local function MakeByCut( Proc, nRawId, b3Raw, bDeleteBottomFacet) +local function MakeByCut( Proc, nRawId, b3Raw) -- ingombro del pezzo local Ls = EgtGetFirstNameInGroup( Proc.PartId, 'Box') local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD) @@ -1505,7 +1567,7 @@ local function MakeByCut( Proc, nRawId, b3Raw, bDeleteBottomFacet) -- gruppo ausiliario local nAddGrpId = WL.GetAddGroup( Proc.PartId) -- recupero i dati di tutte le facce - local vFace, dMaxWidth, nNewProc = GetFacesData( Proc, bOpposite, true, dSawDiam, dSawMaxDepth, dSawThick, nAddGrpId, bDeleteBottomFacet) + local vFace, dMaxWidth, nNewProc = GetFacesData( Proc, bOpposite, true, dSawDiam, dSawMaxDepth, dSawThick, nAddGrpId, b3Raw, nil) -- inserimento dei tagli di lama local bCtOk, sCtErr = AddCuts( sCutting, vFace, Proc, nRawId, b3Raw, dSawThick) if not bCtOk then return bCtOk, sCtErr end @@ -1555,7 +1617,7 @@ local function MakeByCut( Proc, nRawId, b3Raw, bDeleteBottomFacet) if not bMcok then return bMcok, sMcErr end else if nConeCut == 1 then - local sErr = 'Clean corner 60° not applid because Sawing not thru the thickness' + local sErr = 'Clean corner 60° not applied because Sawing not thru the thickness' EgtOutLog( sErr) elseif nConeCut == 2 then local sErr = 'Not possible apply Clean corner 30° after use sawing' @@ -1589,7 +1651,7 @@ local function MakeByMill( Proc, nRawId, b3Raw) local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) local b3Aux = EgtGetBBoxGlob( AuxId, GDB_BB.STANDARD) local bToolInv = ( vtExtr:getZ() < -0.1) - -- recupero la lavorazione + -- recupero la lavorazione local sMilling = WM.FindMilling( 'FreeContour') if not sMilling then local sErr = 'Error : milling not found in library' @@ -1623,6 +1685,7 @@ local function MakeByMill( Proc, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- percorso da non invertire @@ -1656,6 +1719,66 @@ local function MakeByMill( Proc, nRawId, b3Raw) return true end +--------------------------------------------------------------------- +local function MakeByNail( Proc, nRawId, b3Raw) + -- ingombro del pezzo + local Ls = EgtGetFirstNameInGroup( Proc.PartId, 'Box') + local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD) + if not b3Solid then + local sErr = 'Error : part box not found' + EgtOutLog( sErr) + return false, sErr + end + -- recupero e verifico l'entità curva + local AuxId = EgtGetInfo( Proc.Id, 'AUXID', 'i') or 0 + if AuxId then AuxId = AuxId + Proc.Id end + if not AuxId or ( EgtGetType( AuxId) & GDB_FY.GEO_CURVE) == 0 then + local sErr = 'Error : missing profile geometry' + EgtOutLog( sErr) + return false, sErr + end + -- recupero i dati della curva e del profilo + local dDepth = abs( EgtCurveThickness( AuxId)) + local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) + local b3Aux = EgtGetBBoxGlob( AuxId, GDB_BB.STANDARD) + local bToolInv = ( vtExtr:getZ() < -0.1) + -- recupero la lavorazione + local sNailing = WM.FindNailing( 11) + if not sNailing then + local sErr = 'Error : nailing not found in library' + EgtOutLog( sErr) + return false, sErr + end + -- inserisco la lavorazione + local sName = 'Nail_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) + local nMchId = EgtAddMachining( sName, sNailing) + if not nMchId then + local sErr = 'Error adding machining ' .. sName .. '-' .. sNailing + EgtOutLog( sErr) + return false, sErr + end + EgtSetInfo( nMchId, 'Part', Proc.PartId) + -- aggiungo geometria + EgtSetMachiningGeometry( {{ AuxId, -1}}) + -- percorso da non invertire + EgtSetMachiningParam( MCH_MP.INVERT, false) + -- se estrusione da sotto, inverto direzione fresa + if bToolInv then + EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) + end + -- assegno affondamento + EgtSetMachiningParam( MCH_MP.DEPTH, 2) + -- assegno lato di lavoro + EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.CENTER) + -- eseguo + if not EgtApplyMachining( true, false) then + local _, sErr = EgtGetLastMachMgrError() + EgtSetOperationMode( nMchId, false) + return false, sErr + end + return true +end + --------------------------------------------------------------------- local function MakeByPocket( Proc, nRawId, b3Raw) -- recupero e verifico l'entità curva @@ -1746,6 +1869,7 @@ local function MakeByPocket( Proc, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchFId, 'Part', Proc.PartId) -- aggiungo geometria if bPocketBotface then EgtSetMachiningGeometry( {{ Proc.Id, nFacet}}) @@ -1787,7 +1911,7 @@ local function MakeByPocket( Proc, nRawId, b3Raw) local nConeCut = VerifyCornerType( Proc) -- recupero i dati di tutte le facce local vFace, dMaxWidth - vFace, dMaxWidth, nNewProc = GetFacesData( Proc, bOpposite, false, dMillDiam, dMaxDepth, (dMillDiam/2), nAddGrpId, false, nNewProc) + vFace, dMaxWidth, nNewProc = GetFacesData( Proc, bOpposite, false, dMillDiam, dMaxDepth, (dMillDiam/2), nAddGrpId, b3Raw, nNewProc) -- se abilitata la lavorazione corner con stop macchina e lavorazione precedente passante if nConeCut == 1 then local bMcok, sMcErr = AddMillCorner( nConeCut, vFace, Proc, nRawId, b3Raw, @@ -1806,17 +1930,22 @@ end --------------------------------------------------------------------- -- Applicazione della lavorazione function WPF.Make( Proc, nRawId, b3Raw) - -- recupero la tipologia + -- recupero la tipologia (contorno o tasca) local bPocket = ( EgtGetInfo( Proc.Id, 'PCKT', 'i') == 1) -- se svuotatura if bPocket then return MakeByPocket( Proc, nRawId, b3Raw) - -- se lati diritti, taglio con lama e pulizia angoli con fresa - elseif true then - return MakeByCut( Proc, nRawId, b3Raw) - -- altrimenti contornatura + -- altrimenti contorno else - return MakeByMill( Proc, nRawId, b3Raw) + -- recupero il tipo di lavorazione + local nCntType = EgtGetInfo( Proc.Id, 'CNT_TYPE', 'i') or 0 + -- se chiodatura + if nCntType == 20 then + return MakeByNail( Proc, nRawId, b3Raw) + -- altrimenti, taglio con lama e pulizia angoli con fresa + else + return MakeByCut( Proc, nRawId, b3Raw) + end end end diff --git a/LuaLibs/WProcessLapJoint.lua b/LuaLibs/WProcessLapJoint.lua index a18e147..a5f3406 100644 --- a/LuaLibs/WProcessLapJoint.lua +++ b/LuaLibs/WProcessLapJoint.lua @@ -575,7 +575,7 @@ local function MakeLocalSurf( ptP1, ptP2, ptP3, nAddGrpId) end --------------------------------------------------------------------- -local function AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, +local function AddMillCornerMachining( nPartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, dOffsAng, dDepthMach, bThruThick, dThSurf, dDiam1, dDiam2, dTall1, dTall2, dDiam3, dTall3, bMakeLocSurf, vFace) @@ -777,6 +777,7 @@ local function AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', nPartId) -- se flag lavorazione spessore passante setto la nota per spostarla dopo i tagli di lama if bThruThick and nTypeConeCut == 1 then EgtSetInfo( nMchId, 'MOVE_AFTER', 1) @@ -947,20 +948,20 @@ local function AddMillCorner( nTypeConeCut, vFace, Proc, nRawId, b3Raw, if nTypeConeCut == 1 and bMakeTwinCut and (dAng + 90) > 2 then local dAngOffs = (dAng + 90) / 2 -- primo taglio - local bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, -dAngOffs, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) if not bOk then return bOk, sErr end -- secondo taglio - bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, dAngOffs, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) if not bOk then return bOk, sErr end -- altrimenti ho un solo percorso else - local bOk, sErr = AddMillCornerMachining( nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, + local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nTypeConeCut, nAddGrpId, dToolDiam, dThick, sMilling, 0, dDepthMach, bThruThick, dDepth, dMillDiam, dMillTotDiam, abs(dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace) @@ -1057,6 +1058,7 @@ local function MakeByChainSaw( Proc, nFacet, nRawId, b3Raw, dElev, dH, dV) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchFId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacAdj}}) -- imposto uso faccia @@ -1139,6 +1141,7 @@ local function MakeByMill( Proc, nFacet, nOthFac, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchFId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacet}}) -- imposto posizione braccio porta testa @@ -1206,6 +1209,7 @@ local function MakeSideGrooveByMill( Proc, nFacet, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchFId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacet}}) -- imposto posizione braccio porta testa @@ -1289,6 +1293,7 @@ local function MakeByPocketing( Proc, nFacet, nRawId, b3Raw, bCheckQPar) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchFId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacet}}) -- imposto posizione braccio porta testa @@ -1361,6 +1366,7 @@ local function MakeOneFace( Proc, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( { { Proc.Id, 0}}) -- percorso da non invertire @@ -1452,6 +1458,7 @@ local function MakeTwoFaces( Proc, nRawId, b3Raw) EgtOutLog( sErr) return false, sErr end + EgtSetInfo( nMchId, 'Part', Proc.PartId) -- aggiungo geometria EgtSetMachiningGeometry( { { Proc.Id, nOrd[i]}}) -- percorso da non invertire diff --git a/LuaLibs/WallExec.lua b/LuaLibs/WallExec.lua index 9176eec..ca22091 100644 --- a/LuaLibs/WallExec.lua +++ b/LuaLibs/WallExec.lua @@ -231,18 +231,19 @@ local function MoveMachiningsAtEnd( nPhase, nType, sStartName, sProperty) end ------ Ordinamento dei tagli, delle fresature e delle forature ------- -local function SortMach( nPhase, LastMch, nType, sStartName, bExistName, sInfo, bExistInfo) +local function SortMach( nPhase, PrevMch, nPartId, nType, sStartName, bExistName, sInfo, bExistInfo) -- dichiarazione tabella local TabCut = {} -- Recupero gli identificativi delle lavorazioni e annullo eventuali allungamenti e Id di altre lavorazioni rappresentate - local nOperId = EgtGetPhaseDisposition( nPhase) + local nOperId = EgtGetNextOperation( PrevMch) while nOperId do -- Se appartiene alla fase corrente e taglio con lama non da sopra (sempre su 1 sola entità) if EgtGetOperationPhase( nOperId) == nPhase and EgtGetOperationType( nOperId) == nType and - ( not sStartName or ( string.sub( EgtGetName( nOperId), 1, #sStartName) == sStartName and bExistName) or - ( string.sub( EgtGetName( nOperId), 1, #sStartName) ~= sStartName and not bExistName)) and - ( not sInfo or ( EgtGetInfo( nOperId, sInfo, 'i') == 1 and bExistInfo) or - ( EgtGetInfo( nOperId, sInfo, 'i') ~= 1 and not bExistInfo)) then + ( not nPartId or EgtGetInfo( nOperId, 'Part', 'i') == nPartId) and + ( not sStartName or ( bExistName and string.sub( EgtGetName( nOperId), 1, #sStartName) == sStartName) or + ( not bExistName and string.sub( EgtGetName( nOperId), 1, #sStartName) ~= sStartName)) and + ( not sInfo or ( bExistInfo and EgtGetInfo( nOperId, sInfo, 'i') == 1) or + ( not bExistInfo and EgtGetInfo( nOperId, sInfo, 'i') ~= 1)) then -- rendo comunque attiva la lavorazione EgtSetOperationMode( nOperId, true) EgtSetCurrMachining( nOperId) @@ -277,42 +278,34 @@ local function SortMach( nPhase, LastMch, nType, sStartName, bExistName, sInfo, -- applico ordinamento calcolato if vOrd then for i = 1, #vOrd do - EgtRelocateGlob( TabCut[vOrd[i]].Mch, LastMch, GDB_IN.AFTER) - LastMch = TabCut[vOrd[i]].Mch + EgtRelocateGlob( TabCut[vOrd[i]].Mch, PrevMch, GDB_IN.AFTER) + PrevMch = TabCut[vOrd[i]].Mch end end - return LastMch + return PrevMch end ------------------------------------------------------------------------------------------------------------- -local function SortMachinings() - -- Recupero la fase corrente - local nPhase = 1 - local LastMch = EgtGetLastOperation() - -- ordino i tagli di lama e li metto alla fine - LastMch = SortMach( nPhase, LastMch, MCH_OY.SAWING) - -- ordino i tagli con segacatena che non hanno nel nome la parte indicata - -- e li metto nelle prime posizioni - local LastMchMort = EgtGetPhaseDisposition( nPhase) - LastMchMort = SortMach( nPhase, LastMchMort, MCH_OY.MORTISING, 'Csaw_', false) - -- ordino i tagli con segacatena che hanno nel nome la parte indicata - -- e li metto nelle ultime - LastMch = SortMach( nPhase, LastMch, MCH_OY.MORTISING, 'Csaw_', true) - -- ordino le fresature che non hanno la nota indicata e le metto alla fine degli eventuali tagli di sega-catena - LastMchMort = SortMach( nPhase, LastMchMort, MCH_OY.MILLING, 'Clean_', false, 'MOVE_AFTER', false) - -- ordino le svuotature e le metto alla fine degli eventuali tagli di sega-catena - LastMchMort = SortMach( nPhase, LastMchMort, MCH_OY.POCKETING) - -- ordino le fresature che hanno la nota indicata e le metto alla fine - LastMch = SortMach( nPhase, LastMch, MCH_OY.MILLING, nil, nil, 'MOVE_AFTER', true) - -- lascio commentate gli spostamenti delle lavorazioni nel caso ci sarà qualche lavorazione - -- non ancora contemplata che richiede queste funzioni - -- Sposto i tagli di lama alla fine --- MoveMachiningsAtEnd( nPhase, MCH_OY.SAWING) - -- Sposto i tagli con sega a catena che hanno un certo nome dopo i tagli di lama (i tagli del freecontour con segacatena non vengono spostati perchè hanno un nome diverso) --- MoveMachiningsAtEnd( nPhase, MCH_OY.MORTISING, 'Csaw_') - -- Sposto le lavorazioni di pulitura spigolo passanti dopo i tagli di lama e con sega a catena --- MoveMachiningsAtEnd( nPhase, MCH_OY.MILLING, nil, 'MoveAfter') +local function SortMachinings( nPhase, PrevMch, nPartId) + -- Chiodature + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MILLING, 'Nail_', true) + -- Tagli con sega a catena che sono rifiniture di spigoli + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MORTISING, 'Csaw_', false) + -- Fresature che sono rifiniture di spigoli + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MILLING, 'Clean_', false, 'MOVE_AFTER', false) + -- Svuotature + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.POCKETING) + -- Fresature che sono puliture di spigoli + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MILLING, 'Clean_', true, 'MOVE_AFTER', false) + -- Tagli con lama + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.SAWING) + -- Qui rimozione sfridi (se ci sono lavorazioni successive) + -- Tagli con sega a catena che vanno fatti dopo i tagli con lama + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MORTISING, 'Csaw_', true) + -- Fresature (puliture di spigoli) che vanno fatte dopo i tagli con lama + PrevMch = SortMach( nPhase, PrevMch, nPartId, MCH_OY.MILLING, nil, nil, 'MOVE_AFTER', true) + return PrevMch end ------------------------------------------------------------------------------------------------------------- @@ -323,19 +316,24 @@ function WallExec.ProcessFeatures() -- recupero il grezzo e il suo box local nRawId = EgtGetFirstRawPart() local b3Raw = EgtGetRawPartBBox( nRawId) - -- raccolgo l'elenco delle feature da lavorare, ciclando sui pezzi - local vProc = {} + -- raccolgo l'elenco dei pezzi + local vPart = {} local nPartId = EgtGetFirstPartInRawPart( nRawId) while nPartId do - -- recupero le feature di lavorazione della parete - local vPartProc = CollectFeatures( nPartId, b3Raw) - vProc = EgtJoinTables( vProc, vPartProc) + local Ls = EgtGetFirstNameInGroup( nPartId, 'Box') + local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD) + table.insert( vPart, {Id=nPartId, Box=b3Solid}) nPartId = EgtGetNextPartInRawPart( nPartId) end + -- raccolgo l'elenco delle feature da lavorare, ciclando sui pezzi + local vProc = {} + for i = 1, #vPart do + -- recupero le feature di lavorazione della parete + local vPartProc = CollectFeatures( vPart[i].Id, b3Raw) + vProc = EgtJoinTables( vProc, vPartProc) + end -- classifico le feature ClassifyFeatures( vProc, b3Raw) - -- ordino le feature - -- *** TODO *** -- debug if EgtGetDebugLevel() >= 1 then PrintFeatures( vProc) @@ -359,11 +357,26 @@ function WallExec.ProcessFeatures() table.insert( Stats, {Err=1, Msg=sMsg, Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) end end - -- riordino le lavorazioni - SortMachinings() - -- se macchina travi - if WD.BEAM_MACHINE then - -- dati su prima disposizione + -- se macchina pareti + if not WD.BEAM_MACHINE then + -- riordino le lavorazioni tra tutti i pezzi + local nPhase = 1 + local PrevMch = EgtGetPhaseDisposition( nPhase) + SortMachinings( nPhase, PrevMch) + -- altrimenti macchina travi + else + -- ordino i pezzi secondo le X decrescenti + local function CompareParts( P1, P2) + return P1.Box:getCenter():getX() > P2.Box:getCenter():getX() + end + table.sort( vPart, CompareParts) + -- riordino le lavorazioni sui singoli pezzi + local nPhase = 1 + local PrevMch = EgtGetPhaseDisposition( nPhase) + for i = 1, #vPart do + PrevMch = SortMachinings( nPhase, PrevMch, vPart[i].Id) + end + -- aggiungo dati su prima disposizione local nDispId = EgtGetPhaseDisposition( 1) EgtSetInfo( nDispId, 'TYPE', 'START') EgtSetInfo( nDispId, 'ORD', 1) @@ -378,6 +391,15 @@ function WallExec.ProcessFeatures() local nDisp2Id = EgtGetPhaseDisposition( 2) EgtSetInfo( nDisp2Id, 'TYPE', 'END') EgtSetInfo( nDisp2Id, 'ORD', 1) + -- Aggiornamento finale di tutto + EgtSetCurrPhase( 1) + local bApplOk, sApplErrors, sApplWarns = EgtApplyAllMachinings() + if not bApplOk then + nTotErr = nTotErr + 1 + table.insert( Stats, {Err = 1, Msg=sApplErrors, Rot=0, CutId=0, TaskId=0}) + elseif sApplWarns and #sApplWarns > 0 then + -- non interessano perchè riguardano lo scarico delle travi + end end -- restituzione risultati return ( nTotErr == 0), Stats