--24/10/09 ASSEMBLER : File per gestire le operazioni su Part nel VeinMatch3D -- creato da D.B. -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() EgtEnableDebug( false) -- mi preparo a ricevere argomenti local arg =... -- variabile globale -- setto i valori standard nella tabella di comunicazione col programma local ASS = {} -- const da settare al caricamento del file ASS.nMaxStory = 100 -- lunghezza massima della storia ASS.bActiveHist = false -- flag che indica se attivare il salvataggio delle operazioni ( per poter usare undo e redo) -- input ASS.nPartId = GDB_ID.NULL -- part da accoppiare ASS.nIdFirstLine = GDB_ID.NULL -- edge del part con cui eseguire l'accoppiamento ASS.nIdSecondLine = GDB_ID.NULL -- edge di destinazione dell'accoppiamento ASS.nIdAxs = GDB_ID.NULL -- asse con cui eseguire la rotazione( è una CRV_LINE) ASS.dAng = 0 -- angolo per la rotazione ASS.vtAx = V_NULL() -- asse di rotazione ASS.ptAx = ORIG() -- punto per l'asse di rotazione ASS.vtMove = V_NULL() -- vettore di traslazione ASS.vtFirstNorm = V_NULL() -- normale della superficie del part da accoppiare ASS.vtSecondNorm = V_NULL() -- normale di destinazione dell'accoppiamento ASS.nVeinCtx = GDB_ID.NULL -- indice del contesto del VeinMatch3D ASS.nOption = 0 -- intero che indica l'opzione di pairing scelta ASS.nGroup = 0 -- intero che indica il numero del gruppo da aggiornare per il part nPartToPair ASS.nPartToPair = GDB_ID.NULL -- id del part di cui si vogliono aggiornare le info di pairing ASS.sPairList = "" -- lista di accoppiamento ASS.bSaveHist = true -- flag che indica se salvare nella storia l'operazione eseguita ASS.bSaveTemp = false -- flag che indica se salvare nella storia temporanea l'operazione eseguita ASS.nTempToSave = GDB_ID.NULL -- posizione nel vettore temporaneo della trasformazione da salvare ASS.nTypeTrf = GDB_ID.NULL -- tipo della trasformazione da aggiungere alla storia ( 0: traslazione; 1: rotazione; 2: accoppiamento/disaccoppiamento; 3: import) -- output ASS.ERR = 0 -- -1 : valori non settati o sbagliati, -2 : operazione impossibile(es: fuori dall'array), -3 : manca qualcosa nel database (info, pezzi, layer..) ASS.nTransf = 0 -- numero di operazioni eseguite / numero di operazione nella tabella della storia, aggiornato dopo un Undo o un Redo ASS.sFunc = "" -- funzione in cui è stato eseguito il return a seguito di un errore ASS.bRedoPossible = false -- variabili locali local vPaired = {} local ptPair = ORIG() local GroupCounter = 1 -- ogni volta che viene usato va incrementato di 1 local nTernaId = GDB_ID.NULL local ptOrigId = ORIG() -- gestione della storia -- tbEvent = { Id, vtDir, ptAx, dAngOrId, bWPaired, lPair} -- solo move e rotate possono essere effettuati su pezzi singoli, anche se accoppiati local Time = 0 local tbStory = {} -- gestione della storia temporanea local TempTime = 0 local tbTempStory = {} -- leggo gli argomenti passati dalla chiamata del file local bAutoRun = false if arg then ASS.nVeinCtx = arg.nVeinCtx bAutoRun = arg.AutoRun end -- rendo la variabile globale _G.ASS = ASS function ResetASS() -- input ASS.nPartId = GDB_ID.NULL ASS.nIdFirstLine = GDB_ID.NULL ASS.nIdSecondLine = GDB_ID.NULL ASS.nIdAxs = GDB_ID.NULL ASS.dAng = 0 ASS.vtAx = V_NULL() ASS.ptAx = ORIG() ASS.vtMove = V_NULL() ASS.vtFirstNorm = V_NULL() ASS.vtSecondNorm = V_NULL() ASS.nVeinCtx = GDB_ID.NULL ASS.nOption = 0 ASS.nGroup = 0 ASS.nPartToPair = GDB_ID.NULL ASS.sPairList = "" ASS.nTempToSave = GDB_ID.NULL ASS.nTypeTrf = GDB_ID.NULL -- output ASS.ERR = GDB_ID.NULL ASS.nTransf = 0 end local function FromStringToINTVECTOR( sIntVectorString) local vInt = {} local vsInt = EgtSplitString(sIntVectorString,",") for sInt in vsInt do table.insert( vInt, EgtEvalNumExpr(sInt)) end return vInt end local function AddEvent( tbEvent) if not tbEvent.Id then do return end end -- se ho già raggiunto il massimo della storia salvabile allora elimino il primo elemento if Time == ASS.nMaxStory then table.remove(tbStory,1) end -- se ero avevo già fatto degli undo allora devo cancellare la storia che sto per sovrascrivere if Time < #tbStory then local nLastEvent = #tbStory for nItTime = Time, nLastEvent, 1 do table.remove(tbStory, Time + 1) end end if Time < ASS.nMaxStory then Time = Time + 1 end table.insert( tbStory, tbEvent) return true end local function AddTempEvent( tbEvent) -- se ho già raggiunto il massimo della storia salvabile allora elimino il primo elemento if TempTime == ASS.nMaxStory then table.remove(tbTempStory,1) end -- se ero avevo già fatto degli undo allora devo cancellare la storia che sto per sovrascrivere if TempTime < #tbTempStory then local nLastEvent = #tbTempStory for nItTime = TempTime, nLastEvent, 1 do table.remove(tbTempStory, TempTime + 1) end end if TempTime < ASS.nMaxStory then TempTime = TempTime + 1 end table.insert( tbTempStory, tbEvent) end function ASS.AddEvent() ASS.sFunc = "ASS.AddEvent" local tbEvent = {} local a = tbEvent.nId if ASS.nTypeTrf == 0 then -- traslazione if ASS.nPartId == GDB_ID.NULL or AreSameVectorApprox(ASS.vtMove, V_NULL()) then ASS.ERR = -1 return false end tbEvent = {Id = ASS.nPartId, vtDir = ASS.vtMove, ptAx = ORIG(), dAngOrId = 0, bWPaired = true, lPair = {}} elseif ASS.nTypeTrf == 1 then -- rotazione if ASS.nPartId == GDB_ID.NULL or AreSameVectorApprox(ASS.vtAx, V_NULL()) or ASS.dAng == nil then ASS.ERR = -1 return false end tbEvent = {Id = ASS.nPartId, vtDir = ASS.vtAx, ptAx = ASS.ptAx, dAngOrId = ASS.dAng, bWPaired = true, lPair = {}} elseif ASS.nTypeTrf == 2 then -- accoppiamento if ASS.nPartId == GDB_ID.NULL or ASS.nPartToPair == GDB_ID.NULL then ASS.ERR = -1 return false end tbEvent = {Id = ASS.nPartId, vtDir = V_NULL(), ptAx = ORIG(), dAngOrId = ASS.nPartToPair, bWPaired = true, lPair = FromStringToINTVECTOR(ASS.sPairList)} elseif ASS.nTypeTrf == 3 then -- importazione oggetto if ASS.nPartId == GDB_ID.NULL then ASS.ERR = -1 return false end tbEvent = {Id = ASS.nPartId, vtDir = V_NULL(), ptAx = ORIG(), dAngOrId = 0, bWPaired = true, lPair = {}} else do return false end end local bOk = false if AddEvent( tbEvent) then bOk = true end ASS.nTransf = Time return bOk end function ASS.AddEventFromTemp() ASS.sFunc = "AddEventFromTemp" if abs(ASS.nTempToSave) > #tbTempStory then ASS.ERR = -2 return false end if ASS.nTempToSave < 0 then ASS.nTempToSave = #tbTempStory + 1 + ASS.nTempToSave end AddEvent( tbTempStory[ASS.nTempToSave]) return true end function ASS.ResetStory() tbStory = {} Time = 0 return true end function ASS.ResetTempStory() tbTempStory = {} TempTime = 0 return true end local function ApplyTransf( tbEvent, bForward, bSave, bTemp) -- tbEvent = { nId, vtDir, ptAx, dAngOrId, bWPaired, lPair} if tbEvent == nil or bForward == nil or bSave == nil or bTemp == nil or tbEvent.Id == GDB_ID.NULL or tbEvent.Id == nil or tbEvent.vtDir == nil or tbEvent.ptAx == nil or tbEvent.dAngOrId == nil then ASS.ERR = -1 return false end ASS.bSaveHist = bSave -- se ho una traslazione o una rotazione applico la trasformazione a tutto l'accoppiato if not AreSameVectorExact(V_NULL(), tbEvent.vtDir) then -- se è un undo allora inverto il vettore if not bForward then tbEvent.vtDir = Vector3d(tbEvent.vtDir) * (-1) end if tbEvent.dAngOrId == 0 then ASS.nTypeTrf = 0 -- setto il tipo di trasformazione che sto facendo (in caso serva al chiamante) ASS.nPartId = tbEvent.Id ASS.vtMove = tbEvent.vtDir ASS.bSaveHist = bSave ASS.bSaveTemp = bTemp if tbEvent.bWPaired then ASS.Move() else ASS.MoveSingle() end elseif not AreSameVectorExact(V_NULL(), tbEvent.vtDir) then ASS.nTypeTrf = 1 -- setto il tipo di trasformazione che sto facendo (in caso serva al chiamante) ASS.nPartId = tbEvent.Id ASS.vtAx = tbEvent.vtDir ASS.ptAx = tbEvent.ptAx ASS.dAng = tbEvent.dAngOrId ASS.bSaveHist = bSave ASS.bSaveTemp = bTemp if tbEvent.bWPaired then ASS.Rotate() else ASS.RotateSingle() end end elseif tbEvent.dAngOrId == 0 then ASS.nTypeTrf = 3 -- setto il tipo di trasformazione che sto facendo (in caso serva al chiamante) -- se non sono definiti né l'asse né l'angolo/id di accoppiamento allora è un import if not bForward then -- se sto facendo un undo allora elimino il part e il SOLID importati local nChild = EgtGetInfo(tbEvent.Id, "Child", "i") EgtErase(nChild) EgtErase(tbEvent.Id) end -- se sto facendo un redo, non faccio nulla elseif bForward then ASS.nTypeTrf = 2 -- setto il tipo di trasformazione che sto facendo (in caso serva al chiamante) -- sto applicando un accoppiamento -- aggiorno le info dei due part e di tutti i loro associati ASS.nPartId = tbEvent.Id ASS.nPartToPair = tbEvent.dAngOrId if not ASS.UpdatePairInfo() then return false end else ASS.nTypeTrf = 2 -- setto il tipo di trasformazione che sto facendo (in caso serva al chiamante) -- sto applicando un disaccoppiamento if #tbEvent.lPair == 1 then ASS.nPartId = tbEvent.dAngOrId if not ASS.Unpair() then ASS.ERR = -2 return false end else -- alla lista dei paired del part selezionato per essere accoppiato tolgo tutti i part che ho aggiunto( part destinatario e suoi eventuali accoppiati) for n, nIdToUnpair in pairs(tbEvent.lPair) do -- rimuovo anche le info ASS.nPartId = tbEvent.Id ASS.nPartToPair = nIdToUnpair if not ASS.RemovePairInfo() then return false end end local sPairedNew1 = EgtGetInfo( tbEvent.Id, "Paired", "s") local lPairNew1 = EgtGetInfo(tbEvent.Id, "Paired", "vi") if lPairNew1 == nil or sPairedNew1 == nil then ASS.ERR = -3 return false end -- copio la nuova lista dei paired in tutti gli altri paired for n, nIdPaired in pairs(lPairNew1) do ASS.nPartId = nIdPaired ASS.sPairList = sPairedNew1 ASS.nGroup = -1 ASS.UpdatePairInfoSingle() end -- se il part corrente era già accoppiato con altri pezzi allora lascio a quell'accoppiato il numero del gruppo che sto spezzando -- e darò un nuovo numero al destinatario e al suo accoppiato local bCurrWasSingle = false if #lPairNew1 == 1 then bCurrWasSingle = true ASS.sPairList = sPairedNew1 ASS.nGroup = 0 ASS.UpdatePairInfoSingle() end -- alla lista del part destinatario dell'accoppiamento tolgo tutti i part che gli ho aggiunto for n, nIdPaired in pairs(lPairNew1) do ASS.nPartId = tbEvent.dAngOrId ASS.nPartToPair = nIdPaired if not ASS.RemovePairInfo() then return false end end -- assegno un nuovo numero di gruppo al gruppo che ho creato local sPairedNew2 = EgtGetInfo( tbEvent.dAngOrId, "Paired", "s") local lPairNew2 = EgtGetInfo( tbEvent.dAngOrId, "Paired", "vi") local nGroupCode = -1 -- se il curr era single allora mantengo il numero di gruppo per l'assemblato del destinatario if not bCurrWasSingle then -- il curr non era single, quindi a lui resta il numero di gruppo if #lPairNew2 > 1 then -- anche il destinatario non era single, quindi serve un nuovo numero di gruppo nGroupCode = GroupCounter GroupCounter = GroupCounter + 1 else -- il destinatario era single, quindi rimetto semplicemente a 0 il numero di gruppo nGroupCode = 0 end end -- aggiorno la lista dei part che erano già paired con il part selezionato for n, nIdPaired in pairs(lPairNew2) do ASS.nPartId = nIdPaired ASS.sPairList = sPairedNew2 ASS.nGroup = nGroupCode ASS.UpdatePairInfoSingle() end end end return true end function ASS.Undo() ASS.sFunc = "ASS.Undo" if Time == 0 then do return end end if Time > #tbStory then Time = #tbStory end ApplyTransf(tbStory[Time], false, false, false) Time = Time - 1 ASS.nTransf = Time ASS.bRedoPossible = true return true end function ASS.Redo() ASS.sFunc = "ASS.Redo" if Time >= #tbStory then ASS.bRedoPossible = false return false end if Time == ASS.nMaxStory then ASS.bRedoPossible = false return false end ApplyTransf(tbStory[Time + 1], true, false, false) Time = Time + 1 ASS.nTransf = Time if Time >= #tbStory then ASS.bRedoPossible = false end if Time == ASS.nMaxStory then ASS.bRedoPossible = false end return true end function ASS.UndoTemp() ASS.sFunc = "ASS.UndoTemp" if TempTime == 0 then do return end end if TempTime > ASS.nMaxStory then TempTime = ASS.nMaxStory end ApplyTransf(tbTempStory[TempTime], false, false, false) TempTime = TempTime - 1 end function ASS.RedoTemp() ASS.sFunc = "ASS.RedoTemp" if TempTime >= #tbTempStory then do return end end if TempTime == ASS.nMaxStory then do return end end ApplyTransf(tbTempStory[TempTime + 1], true, false, false) TempTime = TempTime + 1 end local function RetrieveSurfNorm( nPartId) -- recupero la normale della faccia principale del Part a partire dall'id del Part local nLayR = EgtGetFirstNameInGroup( nPartId, "Region") local nId = EgtGetFirstInGroup(nLayR) local nSurfId = GDB_ID.NULL while nId ~= GDB_ID.NULL do if EgtGetType( nId) == GDB_TY.SRF_FRGN then nSurfId = nId break end nId = EgtGetNext(nId) end local vtNorm = EgtSurfFrNormVersor(nSurfId, GDB_RT.GLOB) return vtNorm end local function RetrieveParent( nId) -- recupero il parent dell'oggetto nId -- se è un oggetto all'interno contenuto in un Part che si chiama SOLID allora recupero il Part nId = EgtGetParent(EgtGetParent(nId)) local sName = "" sName = EgtGetName(nId, "s") if sName == "SOLID" then nId = EgtGetInfo(nId, "Parent","i") end return nId end local function RetrievePart( nId) local sName = EgtGetName(nId) local nParent = nId if sName == "SOLID" then nParent = EgtGetInfo(nId, "Parent","i") end return nParent end local function RetrievePaired() vPaired = EgtGetInfo( RetrievePart(ASS.nPartId), "Paired", "vi") if vPaired == nil then ASS.ERR = -3 return false end return true end local function RetrieveLocAxis() -- recupero l'id della terna, se esiste nTernaId = GDB_ID.NULL nTernaId = EgtGetInfo( ASS.nPartId, "Terna", "i") if not nTernaId then return false else return true end end local function RetrieveLocOrig() -- recupero l'origine della terna if nTernaId == GDB_ID.NULL then do return end end local LayOrig = EgtGetFirstNameInGroup(nTernaId, "ORIG") ptOrigId = EgtGetFirstNameInGroup(LayOrig, "ORIG") end function ASS.Move() ASS.sFunc = "ASS.Move" if AreSameVectorApprox(ASS.vtMove, V_NULL()) then return true end if ASS.nPartId == nil or ASS.nPartId == GDB_ID.NULL or ASS.vtMove == nil then ASS.ERR = -1 return false end -- recupero la lista degli accoppiati if not RetrievePaired() then return false end if RetrieveLocAxis() then EgtMove(nTernaId, ASS.vtMove, GDB_RT.GLOB) end -- muovo il pezzo e tutti i suoi accoppiati for n, nId in pairs(vPaired) do EgtMove( nId, ASS.vtMove, GDB_RT.GLOB) local nChild = EgtGetInfo( nId, "Child", "i") EgtMove( nChild, ASS.vtMove, GDB_RT.GLOB) end -- se richiesto salvo la storia if ASS.bActiveHist then local tbEv = {Id = ASS.nPartId, vtDir = ASS.vtMove, ptAx = ORIG(), dAngOrId = 0, bWPaired = true, lPair = {}} if ASS.bSaveHist then AddEvent( tbEv) end if ASS.bSaveTemp then AddTempEvent( tbEv) end end return true end function ASS.MoveSingle() ASS.sFunc = "ASS.MoveSingle" if AreSameVectorApprox(ASS.vtMove, V_NULL()) then return true end if ASS.nPartId == nil or ASS.nPartId == GDB_ID.NULL or ASS.vtMove == nil then ASS.ERR = -1 return false end -- muovo il pezzo MA NON i suoi accoppiati EgtMove( ASS.nPartId, ASS.vtMove, GDB_RT.GLOB) local nChild = EgtGetInfo( ASS.nPartId, "Child", "i") EgtMove( nChild, ASS.vtMove, GDB_RT.GLOB) if RetrieveLocAxis() then EgtMove(nTernaId, ASS.vtMove, GDB_RT.GLOB) end -- se richiesto salvo la storia if ASS.bActiveHist then local tbEv = {Id = ASS.nPartId, vtDir = ASS.vtMove, ptAx = ORIG(), dAngOrId = 0, bWPaired = false, lPair = {}} if ASS.bSaveHist then AddEvent( tbEv) end if ASS.bSaveTemp then AddTempEvent( tbEv) end end return true end function ASS.Rotate() ASS.sFunc = "ASS.Rotate" if ASS.dAng == 0 then return true end if ASS.nPartId == nil or ASS.nPartId == GDB_ID.NULL or ASS.ptAx == nil or AreSameVectorApprox( ASS.vtAx, V_NULL()) then ASS.ERR = -1 return false end -- recupero la lista degli accoppiati if not RetrievePaired() then return false end if RetrieveLocAxis() then RetrieveLocOrig() -- muovo la terna local ptBefore = EgtSP(ptOrigId, GDB_RT.GLOB) local ptAfterId = EgtCopyGlob(ptOrigId, nTernaId) EgtRotate( ptAfterId, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB, GDB_RT.GLOB) local vtMove = Point3d(EgtSP( ptAfterId, GDB_RT.GLOB)) - Point3d(ptBefore) EgtMove( nTernaId, vtMove, GDB_RT.GLOB) EgtErase(ptAfterId) end -- ruoto il pezzo e tutti i suoi accoppiati for n, nId in pairs(vPaired) do EgtRotate( nId, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB) local nChild = EgtGetInfo( nId, "Child","i") EgtRotate( nChild, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB) end -- se richiesto salvo la storia if ASS.bActiveHist then local tbEv = {Id = ASS.nPartId, vtDir = ASS.vtAx, ptAx = ASS.ptAx, dAngOrId = ASS.dAng, bWPaired = true, lPair = {}} if ASS.bSaveHist then AddEvent( tbEv) end if ASS.bSaveTemp then AddTempEvent( tbEv) end end return true end function ASS.RotateSingle() ASS.sFunc = "ASS.RotateSingle" if ASS.dAng == 0 then return true end if RetrieveLocAxis() then RetrieveLocOrig() -- muovo la terna local ptBefore = EgtSP(ptOrigId, GDB_RT.GLOB) local ptAfterId = EgtCopy(ptOrigId, nTernaId) EgtRotate( ptAfterId, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB) local vtMove = Point3d(EgtSP( ptAfterId, GDB_RT.GLOB)) - Point3d(ptBefore) EgtMove( nTernaId, vtMove, GDB_RT.GLOB) EgtErase(ptAfterId) end -- ruoto il pezzo MA NON i suoi accoppiati EgtRotate( ASS.nPartId, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB) local nChild = EgtGetInfo( ASS.nPartId, "Child","i") EgtRotate( nChild, ASS.ptAx, ASS.vtAx, ASS.dAng, GDB_RT.GLOB) -- se richiesto salvo la storia if ASS.bActiveHist then local tbEv = {Id = ASS.nPartId, vtDir = ASS.vtMove, ptAx = ASS.ptAx, dAngOrId = ASS.dAng, bWPaired = false, lPair = {}} if ASS.bSaveHist then AddEvent( tbEv) end if ASS.bSaveTemp then AddTempEvent( tbEv) end end return true end function ASS.FlipParallel() ASS.sFunc = "ASS.FlipParallel" local vtNorm = V_NULL() -- recupero la normale della superficie originale vtNorm = RetrieveSurfNorm( RetrievePart(ASS.nPartId)) if vtNorm == nil or AreSameVectorApprox(vtNorm, V_NULL()) then ASS.ERR = -3 return false end ASS.ptAx = ptPair ASS.vtAx = vtNorm ASS.dAng = 180 if not ASS.Rotate() or not ASS.EdgePair() then return false end return true end function ASS.FlipPerpendicular() ASS.sFunc = "ASS.FlipPerpendicular" -- recupero la normale della faccia principale del part del secondo part local vtNorm = V_NULL() vtNorm = RetrieveSurfNorm( RetrieveParent(ASS.nIdSecondLine)) if vtNorm == nil or AreSameVectorApprox(vtNorm, V_NULL()) then ASS.ERR = -3 return false end local vtStartDir = EgtSV(ASS.nIdSecondLine, GDB_RT.GLOB) local vtAx = vtNorm ^ vtStartDir if vtAx == nil or AreSameVectorApprox(vtAx, V_NULL()) then ASS.ERR = -2 return false end -- recupero il punto usato per l'accoppiamento if ptPair == nil then ASS.ERR = -2 return false end ASS.ptAx = ptPair ASS.vtAx = vtAx ASS.dAng = 180 if not ASS.Rotate() or not ASS.EdgePair() then return false end return true end function ASS.FacePair() ASS.sFunc = "ASS.FacePair" -- setto e controllo EgtSetContext(ASS.nVeinCtx) if ASS.nPartId == GDB_ID.NULL then ASS.ERR = -1 return false end if ASS.nIdSecondLine == GDB_ID.NULL then ASS.ERR = -1 return false end -- recupero gli id dei Part local nIdToPair = RetrieveParent(ASS.nIdSecondLine) ASS.nPartId = RetrievePart(ASS.nPartId) local ptAx = EgtSP(ASS.nIdSecondLine, GDB_RT.GLOB) local vtAx = Vector3d(EgtSV(ASS.nIdSecondLine, GDB_RT.GLOB)) local vtNorm1 = Vector3d(ASS.vtFirstNorm):isZero() and Vector3d(RetrieveSurfNorm(ASS.nPartId)) or Vector3d(ASS.vtFirstNorm) local vtNorm2 = Vector3d(ASS.vtSecondNorm):isZero() and Vector3d(RetrieveSurfNorm( nIdToPair)) or Vector3d(ASS.vtSecondNorm) local dAng = GetAngle( vtNorm1, vtNorm2) local vtCopy = Vector3d(vtNorm1) vtCopy:rotate(vtAx, 180 - dAng) vtCopy = vtCopy * (GDB_ID.NULL) ASS.ptAx = ptAx ASS.vtAx = vtAx if AreSameVectorApprox(vtNorm2, vtCopy) then ASS.dAng = 180 - dAng if not ASS.Rotate() then return false end else ASS.dAng = -(180 - dAng) if not ASS.Rotate() then return false end end return true end function ASS.EdgePair() ASS.sFunc = "ASS.EdgePair" -- setto e faccio i controlli -- resetto il conto di operazioni fatto ASS.nTransf = 1 EgtSetContext(ASS.nVeinCtx) if ASS.nPartId == GDB_ID.NULL then ASS.ERR = -1 return false end if ASS.nIdFirstLine == GDB_ID.NULL then ASS.ERR = -1 return false end if ASS.nIdSecondLine == GDB_ID.NULL then ASS.ERR = -1 return false end -- controllo che i due part non siano già accoppiati -- recupero l'id del secondo part local nIdToPair = RetrieveParent(ASS.nIdSecondLine) if nIdToPair == GDB_ID.NULL then ASS.ERR = -1 return false end ASS.nPartId = RetrievePart(ASS.nPartId) if ASS.nPartId == GDB_ID.NULL then ASS.ERR = -1 return false end -- verifico che i due part non siano già accoppiati local nGroup1 = 0 local nGroup2 = 0 nGroup1 = EgtGetInfo( ASS.nPartId, "GroupCode","i") or 0 nGroup2 = EgtGetInfo( nIdToPair, "GroupCode","i") or 0 if nGroup1 == nGroup2 and nGroup1 ~= 0 then return true end -- se i due part non erano già associati allora procedo con l'accoppiamento -- first line local ptStartF, ptEndF, ptMidF, vtDirF ptStartF = EgtSP(ASS.nIdFirstLine, GDB_RT.GLOB) ptEndF = EgtEP(ASS.nIdFirstLine, GDB_RT.GLOB) ptMidF = EgtMP(ASS.nIdFirstLine, GDB_RT.GLOB) vtDirF = EgtSV(ASS.nIdFirstLine, GDB_RT.GLOB) -- second line local ptStartS, ptEndS, ptMidS, vtDirS ptStartS = EgtSP(ASS.nIdSecondLine, GDB_RT.GLOB) ptEndS = EgtEP(ASS.nIdSecondLine, GDB_RT.GLOB) ptMidS = EgtMP(ASS.nIdSecondLine, GDB_RT.GLOB) vtDirS = EgtSV(ASS.nIdSecondLine, GDB_RT.GLOB) local ptIni, ptFin if ASS.nOption == 0 then -- Start-Start ptIni = ptStartF ptFin = ptStartS elseif ASS.nOption == 1 then -- Start-End ptIni = ptStartF ptFin = ptEndS elseif ASS.nOption == 2 then -- End-Start ptIni = ptEndF ptFin = ptStartS elseif ASS.nOption == 3 then -- End-End ptIni = ptEndF ptFin = ptEndS elseif ASS.nOption == 4 then -- Mid-Mid ptIni = ptMidF ptFin = ptMidS end ptPair = ptFin -- calcolo il vettore movimento e sposto solid e part ASS.vtMove = ptFin - ptIni local dAng = GetAngle(vtDirF, vtDirS) if not ASS.Move() then return false end local dTol = 0.001 if dAng < dTol or abs(dAng - 180) < dTol or abs(dAng - 360) < dTol then --EgtDraw() return true end ASS.nTransf = 2 -- ruoto il solid che sto spostando local vtAx = Vector3d( vtDirF ^ vtDirS) ASS.dAng = dAng ASS.ptAx = ptFin ASS.vtAx = vtAx if not ASS.Rotate() then return false end --EgtDraw() return true end function ASS.Unpair() ASS.sFunc = "ASS.Unpair" if ASS.nPartId == nil or ASS.nPartId == GDB_ID.NULL then ASS.ERR = -1 return false end -- rimuovo le info dal PartCurr e da tutti i suoi Pair ASS.nPartToPair = ASS.nPartId if not ASS.RemovePairInfo() then return false end local nPartCurr = ASS.nPartId if not RetrievePaired() then return false end local sPaired = EgtGetInfo(ASS.nPartId, "Paired") if sPaired == nil then ASS.ERR = -3 return false end for n, nId in pairs(vPaired) do ASS.nPartId = nId ASS.sPairList = sPaired ASS.nGroup = #vPaired > 1 and GDB_ID.NULL or 0 if not ASS.UpdatePairInfoSingle() then return false end end -- resetto le info di pairing del part corrente ASS.nPartId = nPartCurr ASS.sPairList = EgtNumToString(nPartCurr) ASS.nGroup = 0 if not ASS.UpdatePairInfoSingle() then return false end return true end function ASS.RemovePairInfo() --nId As Integer, nIdToUnpair As Integer -- al part nId tolgo l'accoppiamento con nIdToUnpair ASS.sFunc = "ASS.RemovePairInfo" --aggiorno le info local sPair = EgtGetInfo(ASS.nPartId, "Paired", sPair) local vsPaired = EgtSplitString(sPair, ",") local sIdToUnpair = EgtNumToString(ASS.nPartToPair) if sIdToUnpair == nil or sIdToUnpair == "" or vsPaired == nil or sPair == nil then ASS.ERR = -3 return false end -- ricostruisco l'informazione paired senza l'Id che ho disaccoppiato local sNewPaired = "" for s, sIdPaired in pairs(vsPaired) do if sIdPaired ~= sIdToUnpair then if sNewPaired ~= "" then sNewPaired = sNewPaired .. "," .. sIdPaired else sNewPaired = sIdPaired end end end -- aggiorno le info local nGroup = #vsPaired > 2 and GDB_ID.NULL or 0 ASS.sPairList = sNewPaired ASS.nGroup = nGroup if not ASS.UpdatePairInfoSingle() then return false end return true end function ASS.UpdatePairInfoSingle() ASS.sFunc = "ASS.UpdatePairInfoSingle" if ASS.sPairList == nil or ASS.sPairList == "" or ASS.nGroup == nil then ASS.ERR = -1 return false end EgtSetInfo(ASS.nPartId, "Paired", ASS.sPairList) if ASS.nGroup ~= GDB_ID.NULL then EgtSetInfo(ASS.nPartId, "GroupCode", ASS.nGroup) end return true end function ASS.UpdatePairInfo() ASS.sFunc = "ASS.UpdatePairInfo" local nId1 = RetrievePart(ASS.nPartId) if nId1 == nil or nId1 == GDB_ID.NULL then ASS.ERR = -1 return false end ASS.nPartId = nId1 -- il secondo id lo recupero dal parent del secondo edge, se presente, altrimenti da nPartToPair local nId2 = GDB_ID.NULL if ASS.nIdSecondLine ~= GDB_ID.NULL then nId2 = RetrieveParent(ASS.nIdSecondLine) else nId2 = RetrievePart(ASS.nPartToPair) end if nId1 == nil or nId1 == GDB_ID.NULL then ASS.ERR = -1 return false end ASS.nPartToPair = nId2 -- salvo la lista degli attuali accoppiati del part destinatario dell'accoppiamento local lPairList = EgtGetInfo( ASS.nPartToPair,"Paired", "vi") if lPairList == nil then ASS.ERR = -3 return false end -- verifico se uno o entrambi dei due part sono già in un gruppo local sPaired1 = "" sPaired1 = EgtGetInfo(nId1, "Paired") if sPaired1 == nil then ASS.ERR = -3 return false end local sPaired2 = "" sPaired2 = EgtGetInfo(nId2, "Paired") if sPaired2 == nil then ASS.ERR = -3 return false end local nGroup = 0 -- se nessuno dei due era in un gruppo creo un nuovo gruppo con questi due part if sPaired1 == EgtNumToString(nId1) and sPaired2 == EgtNumToString(nId2) then sPaired1 = sPaired1 .. "," .. sPaired2 nGroup = EgtGetInfo(nId1, "GroupCode","i") -- se solo il secondo era in un gruppo, al secondo copio gli id del gruppo elseif sPaired1 == EgtNumToString(nId1) and sPaired2 ~= EgtNumToString(nId2) then sPaired2 = sPaired2 .. "," .. EgtNumToString(nId1) sPaired1 = sPaired2 nGroup = EgtGetInfo(nId2, "GroupCode","i") -- se solo il primo era in un gruppo, al secondo copio gli id del gruppo elseif sPaired1 ~= EgtNumToString(nId1) and sPaired2 == EgtNumToString(nId2) then sPaired1 = sPaired1 .. "," .. EgtNumToString(nId2) nGroup = EgtGetInfo(nId1, "GroupCode","i") -- se entrambi erano in un gruppo faccio il merge elseif sPaired1 ~= EgtNumToString(nId1) and sPaired2 ~= EgtNumToString(nId2) then sPaired1 = sPaired1 .. "," .. sPaired2 local nGroup1 = EgtGetInfo(nId1, "GroupCode","i") local nGroup2 = EgtGetInfo(nId2, "GroupCode","i") nGroup = nGroup1 < nGroup2 and nGroup1 or nGroup2 end if nGroup == 0 or nGroup == nil then nGroup = GroupCounter GroupCounter = GroupCounter + 1 end -- scorro tutti i part associati e aggiorno le loro info local vPaired_s = EgtSplitString(sPaired1) -- qua devo fare uno split sulle virgole ASS.sPairList = sPaired1 ASS.nGroup = nGroup local nPartCurr = ASS.nPartId for n, sId in pairs(vPaired_s) do local nId = EgtEvalNumExpr(sId) ASS.nPartId = nId if not ASS.UpdatePairInfoSingle() then return false end end if ASS.bActiveHist then ASS.nPartId = nPartCurr local tbEv = {Id = ASS.nPartId, vtDir = V_NULL(), ptAx = ORIG(), dAngOrId = ASS.nPartToPair, bWPaired = true, lPair = lPairList} if ASS.bSaveHist then AddEvent( tbEv) end if ASS.bSaveTemp then AddTempEvent( tbEv) end end return true end function ASS.PairAll() ASS.sFunc = "ASS.PairAll" local nTrasfTot = 0 EgtSetContext(ASS.nVeinCtx) local nPart = EgtGetFirstPart() if nPart == nil or nPart == GDB_ID.NULL then ASS.ERR = -3 return false end while nPart do local sLineToPair = EgtGetInfo(nPart, "PairToRef") local sMyLineToPairName = EgtGetInfo( nPart, "PairMyRef") if sLineToPair then -- recupero l'id del lato da accoppiare local sLayName = "Ref" local nLayRef = EgtGetFirstNameInGroup(nPart, sLayName) local nMyLineToPair = EgtGetFirstNameInGroup(nLayRef, sMyLineToPairName) if nMyLineToPair == nil or nMyLineToPair == GDB_ID.NULL then ASS.ERR = -3 return false end -- spezzo l'informazione per risalire al lato di destionazione dell'accoppiamento local vToInfo = EgtSplitString(sLineToPair, "_") local sLineToPairName = vToInfo[3] local sPartName = vToInfo[1].."_"..vToInfo[2] local nPartToPair = EgtGetFirstNameInGroup(GDB_ID.ROOT, sPartName) local nLay = EgtGetFirstNameInGroup(nPartToPair, sLayName) local nLineToPair = EgtGetFirstNameInGroup(nLay, sLineToPairName) if nLineToPair == nil or nLineToPair == GDB_ID.NULL then ASS.ERR = -3 return false end local nSpin = EgtGetInfo(nPart, "PairSpin", "i") ASS.nPartId = nPart ASS.nIdFirstLine = nMyLineToPair ASS.nIdSecondLine = nLineToPair -- controllo se è settata la modalità di accoppiamento sennò lascio il default middle-middle local nOption = EgtGetInfo(nPart, "PairMode", "i") ASS.nOption = nOption and nOption or 4 if not ASS.EdgePair() then return false end nTrasfTot = ASS.nTransf -- verifico che lo spin sia rispettato local vtEdge1 = EgtSV( ASS.nIdFirstLine, GDB_RT.GLOB) local vtEdge2 = EgtSV( ASS.nIdSecondLine, GDB_RT.GLOB) if AreSameVectorApprox( vtEdge1, vtEdge2) and nSpin == -1 then if not ASS.FlipParallel() then return false end end -- recupero l'angolo che deve esserci tra le due facce dei part alla fine dell'accoppiamento local nAngGoal = EgtGetInfo(nPart, "PairAng", "i") -- calcolo l'angolo attuale tra le due normali e quindi la rotazione che devo applicare per differenza local vtSurf1 = RetrieveSurfNorm(nPart) local vtSurf2 = RetrieveSurfNorm(RetrieveParent(ASS.nIdSecondLine)) if vtSurf1 == nil or AreSameVectorApprox( vtSurf1, V_NULL()) or vtSurf2 == nil or AreSameVectorApprox( vtSurf2, V_NULL()) then ASS.ERR = -3 return false end ASS.vtAx = EgtSV(ASS.nIdSecondLine, GDB_RT.GLOB) if ASS.vtAx == nil or AreSameVectorApprox(ASS.vtAx, V_NULL()) then ASS.ERR = -1 return false end local dAngCurr = GetRotation(vtSurf1, vtSurf2, ASS.vtAx) ASS.dAng = dAngCurr - nAngGoal ASS.ptAx = EgtSP(ASS.nIdSecondLine, GDB_RT.GLOB) if not ASS.Rotate() then return false end nTrasfTot = nTrasfTot + 1 -- aggiorno le info di accoppiamento ASS.nPartToPair = nPartToPair if not ASS.UpdatePairInfo() then return false end nTrasfTot = nTrasfTot + 1 end nPart = EgtGetNext(nPart) end ASS.nTransf = nTrasfTot return true end ------ per funzionare con il require --return ASS ------ per funzionare con il require ------ per funzionare nel CAM5 -- ASS.nVeinCtx = 1 -- ASS.PairAll() -- EgtDraw() ------ per funzionare nel CAM5 --- if bAutoRun then ASS.PairAll() end