Files
EgtMachKernel/SawFinishing.cpp
T
Dario Sassi 2c8c8457a2 EgtMachKernel 1.6o4 :
- aggiunte lavorazioni di sgrossatura e finitura con lama di cornici lineari
- al caricamento, se gruppo macchinata errato, lo sposto in un gruppo di errore anzichè cancellarlo
- aggiunta GetRawGlobBox.
2016-04-06 06:30:52 +00:00

1138 lines
38 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2016
//----------------------------------------------------------------------------
// File : SawFinishing.cpp Data : 05.04.16 Versione : 1.6o4
// Contenuto : Implementazione gestione finitura superficie con lama.
//
// Note : Questa lavorazione è sempre espressa nel riferimento globale.
//
// Modifiche : 05.04.16 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "MachMgr.h"
#include "DllMain.h"
#include "SawFinishing.h"
#include "CamData.h"
#include "/EgtDev/Include/EXeCmdLogOff.h"
#include "/EgtDev/Include/EXeConst.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EgkOffsetCurve.h"
#include "/EgtDev/Include/EgkOffsetCurveOnX.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
// per far dimenticare macro di WinUser.h
#undef GetClassName
using namespace std ;
//----------------------------------------------------------------------------
typedef PtrOwner<ICurve> POWNCURVE ;
typedef std::vector<POWNCURVE> POCRVVECTOR ;
//----------------------------------------------------------------------------
const std::string MCH_SECTION = "Sect" ;
const std::string MCH_GUIDE = "Guide" ;
//----------------------------------------------------------------------------
USEROBJ_REGISTER( "EMkSawFinishing", SawFinishing) ;
//----------------------------------------------------------------------------
const string&
SawFinishing::GetClassName( void) const
{
return USEROBJ_GETNAME( SawFinishing) ;
}
//----------------------------------------------------------------------------
SawFinishing*
SawFinishing::Clone( void) const
{
// alloco oggetto
SawFinishing* pSaw = new(nothrow) SawFinishing ;
// eseguo copia dei dati
if ( pSaw != nullptr) {
try {
pSaw->m_Params = m_Params ;
pSaw->m_TParams = m_TParams ;
}
catch( ...) {
delete pSaw ;
return nullptr ;
}
}
// ritorno l'oggetto
return pSaw ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
sOut += GetClassName() + "[mm]" + szNewLine ;
sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ;
sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ;
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
sOut += m_Params.ToString( i) + szNewLine ;
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
sOut += m_TParams.ToString( i) + szNewLine ;
sOut += KEY_NUM + EQUAL + ToString( m_nCuts) + szNewLine ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Save( STRVECTOR& vString) const
{
try {
int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 2 ;
vString.insert( vString.begin(), nSize, "") ;
int k = - 1 ;
if ( ! SetVal( KEY_IDS, m_vId, vString[++k]))
return false ;
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
vString[++k] = m_Params.ToString( i) ;
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
vString[++k] = m_TParams.ToString( i) ;
if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k]))
return false ;
if ( ! SetVal( KEY_NUM, m_nCuts, vString[++k]))
return false ;
}
catch( ...) {
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Load( const STRVECTOR& vString)
{
int nSize = int( vString.size()) ;
// lista identificativi geometrie da lavorare
int k = - 1 ;
if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId))
return false ;
// parametri lavorazione
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) {
int nKey ;
if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) {
if ( m_Params.IsOptional( i))
-- k ;
else
return false ;
}
}
// parametri utensile
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) {
int nKey ;
if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i)
return false ;
}
// parametri di stato
while ( k < nSize - 1) {
// separo chiave da valore
string sKey, sVal ;
SplitFirst( vString[++k], "=", sKey, sVal) ;
// leggo
if ( sKey == KEY_PHASE){
if ( ! FromString( sVal, m_nPhase))
return false ;
}
else if ( sKey == KEY_NUM) {
if ( ! FromString( sVal, m_nCuts))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
SawFinishing::SawFinishing( void)
{
m_Params.m_sName = "*" ;
m_Params.m_sToolName = "*" ;
m_TParams.m_sName = "*" ;
m_TParams.m_sHead = "*" ;
m_nCuts = 0 ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Prepare( const string& sSawName)
{
// verifico il gestore lavorazioni
if ( m_pMchMgr == nullptr)
return false ;
// recupero il gestore DB utensili della macchina corrente
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
if ( pTMgr == nullptr)
return false ;
// recupero il gestore DB lavorazioni della macchina corrente
MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ;
if ( pMMgr == nullptr)
return false ;
// ricerca della lavorazione di libreria con il nome indicato
const SawFinishingData* pDdata = GetSawFinishingData( pMMgr->GetMachining( sSawName)) ;
if ( pDdata == nullptr)
return false ;
m_Params = *pDdata ;
// ricerca dell'utensile usato dalla lavorazione
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
if ( pTdata == nullptr)
return false ;
m_TParams = *pTdata ;
m_Params.m_sToolName = m_TParams.m_sName ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::SetParam( int nType, bool bVal)
{
//switch ( nType) {
//}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::SetParam( int nType, int nVal)
{
switch ( nType) {
case MPA_HEADSIDE :
if ( ! m_Params.VerifyHeadSide( nVal))
return false ;
m_Params.m_nHeadSide = nVal ;
return true ;
case MPA_STEPTYPE :
if ( ! m_Params.VerifyStepType( nVal))
return false ;
m_Params.m_nStepType = nVal ;
return true ;
case MPA_LEADLINKTYPE :
if ( ! m_Params.VerifyLeadLinkType( nVal))
return false ;
m_Params.m_nLeadLinkType = nVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::SetParam( int nType, double dVal)
{
switch ( nType) {
case MPA_SPEED :
if ( ! m_TParams.VerifySpeed( dVal))
return false ;
if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR)
m_Params.m_dSpeed = 0 ;
else
m_Params.m_dSpeed = dVal ;
return true ;
case MPA_FEED :
if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR)
m_Params.m_dFeed = 0 ;
else
m_Params.m_dFeed = dVal ;
return true ;
case MPA_STARTFEED :
if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR)
m_Params.m_dStartFeed = 0 ;
else
m_Params.m_dStartFeed = dVal ;
return true ;
case MPA_ENDFEED :
if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR)
m_Params.m_dEndFeed = 0 ;
else
m_Params.m_dEndFeed = dVal ;
return true ;
case MPA_TIPFEED :
if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR)
m_Params.m_dTipFeed = 0 ;
else
m_Params.m_dTipFeed = dVal ;
return true ;
case MPA_OFFSR :
if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR)
m_Params.m_dOffsR = UNKNOWN_PAR ;
else
m_Params.m_dOffsR = dVal ;
return true ;
case MPA_DEPTH :
m_Params.m_sDepth = ToString( dVal) ;
return true ;
case MPA_STARTPOS :
m_Params.m_dStartPos = dVal ;
return true ;
case MPA_SIDESTEP :
m_Params.m_dSideStep = dVal ;
return true ;
case MPA_APPROX :
m_Params.m_dApprox = dVal ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::SetParam( int nType, const string& sVal)
{
switch ( nType) {
case MPA_TOOL : {
const ToolData* pTdata ;
if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata))
return false ;
m_Params.m_sToolName = sVal ;
m_Params.m_ToolUuid = pTdata->m_Uuid ;
m_TParams = *pTdata ;
} return true ;
case MPA_DEPTH_STR :
m_Params.m_sDepth = sVal ;
return true ;
case MPA_SYSNOTES :
m_Params.m_sSysNotes = sVal ;
break ;
case MPA_USERNOTES :
m_Params.m_sUserNotes = sVal ;
break ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::SetGeometry( const SELVECTOR& vIds)
{
// verifico validità gestore DB geometrico
if ( m_pGeomDB == nullptr)
return false ;
// reset della geometria corrente
m_vId.clear() ;
// verifico che gli identificativi rappresentino delle entità ammissibili
for ( const auto& Id : vIds) {
// test sull'entità
int nSubs ;
if ( ! VerifyGeometry( Id, nSubs)) {
string sOut = "Entity " + ToString( Id) + " skipped by Sawing" ;
LOG_INFO( GetEMkLogger(), sOut.c_str()) ;
continue ;
}
// posso aggiungere alla lista
m_vId.emplace_back( Id) ;
}
return ( ! m_vId.empty()) ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Preview( bool bRecalc)
{
// non esiste preview, si fa apply
return Apply( bRecalc) ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Apply( bool bRecalc)
{
// reset numero tagli nella lavorazione
m_nCuts = 0 ;
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// recupero gruppo per geometria ausiliaria
int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ;
// se non c'è, lo aggiungo
if ( nAuxId == GDB_ID_NULL) {
nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nAuxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nAuxId, MCH_AUX) ;
m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ;
bRecalc = true ;
}
// altrimenti, se chiesto ricalcolo, lo svuoto
else if ( bRecalc) {
m_pGeomDB->EmptyGroup( nAuxId) ;
}
// se necessario, preparo geometria e la inserisco sotto la geometria ausiliaria
if ( bRecalc && ! AdjustGeometry( nAuxId))
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ;
// se non c'è, lo aggiungo
if ( nClId == GDB_ID_NULL) {
nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
if ( nClId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nClId, MCH_CL) ;
}
// altrimenti lo svuoto
else
m_pGeomDB->EmptyGroup( nClId) ;
// calcolo le passate
if ( ! CalculateToolPath( nAuxId, nClId))
return false ;
m_nCuts = 1 ;
// se lavorazione vuota, esco
if ( m_nCuts == 0)
return true ;
// calcolo gli assi macchina
if ( ! CalculateAxesValues())
return false ;
// gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione
if ( ! AdjustStartEndMovements())
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetParam( int nType, bool& bVal) const
{
//switch ( nType) {
//}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetParam( int nType, int& nVal) const
{
switch ( nType) {
case MPA_TYPE :
nVal = MT_SAWFINISHING ;
return true ;
case MPA_HEADSIDE :
nVal = m_Params.m_nHeadSide ;
return true ;
case MPA_STEPTYPE :
nVal = m_Params.m_nStepType ;
return true ;
case MPA_LEADLINKTYPE :
nVal = m_Params.m_nLeadLinkType ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetParam( int nType, double& dVal) const
{
switch ( nType) {
case MPA_SPEED :
dVal = GetSpeed() ;
return true ;
case MPA_FEED :
dVal = GetFeed() ;
return true ;
case MPA_STARTFEED :
dVal = GetStartFeed() ;
return true ;
case MPA_ENDFEED :
dVal = GetEndFeed() ;
return true ;
case MPA_TIPFEED :
dVal = GetTipFeed() ;
return true ;
case MPA_OFFSR :
dVal =GetOffsR() ;
return true ;
case MPA_STARTPOS :
dVal = m_Params.m_dStartPos ;
return true ;
case MPA_SIDESTEP :
dVal = m_Params.m_dSideStep ;
return true ;
case MPA_APPROX :
dVal = m_Params.m_dApprox ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetParam( int nType, string& sVal) const
{
switch ( nType) {
case MPA_NAME :
sVal = m_Params.m_sName ;
return true ;
case MPA_TOOL :
sVal = m_Params.m_sToolName ;
return true ;
case MPA_DEPTH_STR :
sVal = m_Params.m_sDepth ;
return true ;
case MPA_TUUID :
sVal = ToString( m_Params.m_ToolUuid) ;
return true ;
case MPA_UUID :
sVal = ToString( m_Params.m_Uuid) ;
return true ;
case MPA_SYSNOTES :
sVal = m_Params.m_sSysNotes ;
return true ;
case MPA_USERNOTES :
sVal = m_Params.m_sUserNotes ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
const ToolData&
SawFinishing::GetToolData( void) const
{
return m_TParams ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetGeometry( SELVECTOR& vIds) const
{
// restituisco l'elenco delle entità
vIds = m_vId ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP)
{
// compenso il raggio dell'utensile
ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::VerifyGeometry( SelData Id, int& nSubs)
{
// ammessi : curve o superfici
// per ora accetto solo curve
const ICurve* pCurve = nullptr ;
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ;
// se direttamente la curva
if ( Id.nSub == SEL_SUB_ALL) {
pCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ;
if ( pCurve != nullptr) {
if ( pCurve->GetType() == CRV_COMPO)
nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ;
else
nSubs = 0 ;
}
}
// altrimenti sottocurva di composita
else {
const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ;
if ( pCompo != nullptr)
pCurve = pCompo->GetCurve( Id.nSub) ;
nSubs = 0 ;
}
return ( pCurve != nullptr) ;
}
//----------------------------------------------------------------------------
ICurve*
SawFinishing::GetCurve( SelData Id)
{
// ammessi : curve o facce di polymesh
// nel caso di facce si deve recuperare la linea di base
// per ora accetto solo curve
PtrOwner<ICurve> pCurve ;
// se direttamente curva
if ( Id.nSub == SEL_SUB_ALL) {
// recupero e duplico la curva
const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ;
if ( pOriCurve != nullptr)
pCurve.Set( pOriCurve->Clone()) ;
}
// altrimenti sottocurva di composita
else {
// recupero la composita
const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ;
if ( pCompo != nullptr) {
// duplico la curva semplice
const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ;
if ( pOriCurve != nullptr) {
pCurve.Set( pOriCurve->Clone()) ;
// recupero estrusione e spessore
Vector3d vtExtr ;
if ( pCompo->GetExtrusion( vtExtr))
pCurve->SetExtrusion( vtExtr) ;
double dThick ;
if ( pCompo->GetThickness( dThick))
pCurve->SetThickness( dThick) ;
}
}
}
if ( IsNull( pCurve))
return nullptr ;
// ne recupero il riferimento globale
Frame3d frGlob ;
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
return nullptr ;
// la porto in globale
pCurve->ToGlob( frGlob) ;
// la restituisco
return Release( pCurve) ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::AdjustGeometry( int nAuxId)
{
// sgrossatura di cornici diritte : due o più curve (sezioni e guida rettilinea)
size_t nCrvCount = m_vId.size() ;
if ( nCrvCount >= 2) {
// le sezioni devono essere chiuse, piane e giacere in uno stesso piano verticale
POCRVVECTOR vpSects ;
vpSects.reserve( nCrvCount - 1) ;
Vector3d vtN ;
for ( size_t i = 0 ; i < nCrvCount - 1 ; ++ i) {
vpSects.emplace_back( GetCurve( m_vId[i])) ;
if ( IsNull( vpSects.back()))
return false ;
if ( ! vpSects.back()->IsClosed())
return false ;
Plane3d plPlane ;
if ( ! vpSects.back()->IsFlat( plPlane, 10 * EPS_SMALL) || abs( plPlane.vtN.z) > EPS_SMALL)
return false ;
if ( i == 0)
vtN = plPlane.vtN ;
else {
if ( ! AreSameOrOppositeVectorApprox( plPlane.vtN, vtN))
return false ;
}
}
// l'ultima curva deve essere una linea, iniziare in comune con la prima sezione ed essere perp. al piano
PtrOwner<ICurve> pGuide( GetCurve( m_vId[nCrvCount-1])) ;
if ( IsNull( pGuide) || pGuide->GetType() != CRV_LINE)
return false ;
Point3d ptStStart, ptGdStart ;
if ( ! vpSects[0]->GetStartPoint( ptStStart) ||
! pGuide->GetStartPoint( ptGdStart) ||
! AreSamePointApprox( ptStStart, ptGdStart))
return false ;
Vector3d vtGdDir ;
if ( ! pGuide->GetStartDir( vtGdDir) || ! AreSameOrOppositeVectorApprox( vtN, vtGdDir))
return false ;
// creo sottogruppo di ausiliario per le sezioni con riferimento avente
// l'origine nel punto di inizio della prima sezione e la Z opposta alla direzione della guida
Frame3d frSect ;
if ( ! frSect.Set( ptStStart, - vtGdDir))
return false ;
int nGrpSectId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, frSect) ;
if ( nGrpSectId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nGrpSectId, MCH_SECTION) ;
for ( auto& pSect : vpSects) {
pSect->ToLoc( frSect) ;
if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpSectId, ::Release( pSect)) == GDB_ID_NULL)
return false ;
}
// creo sottogruppo per la guida
// inserisco la guida nel gruppo ausiliario
int nGrpGuideId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, Frame3d()) ;
if ( nGrpGuideId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nGrpGuideId, MCH_GUIDE) ;
if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpGuideId, ::Release( pGuide)) == GDB_ID_NULL)
return false ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateToolPath( int nAuxId, int nClId)
{
// recupero il riferimento globale delle sezioni
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
Frame3d frSect ;
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
// recupero le sezioni e il loro ingombro in globale
ICURVEPVECTOR vpSects ;
BBox3d b3Sect ;
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
while ( nSectId != GDB_ID_NULL) {
// recupero il puntatore alla curva
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
if ( vpSects.back() == nullptr)
return false ;
// recupero l'ingombro della sezione corrente in globale
BBox3d b3Temp ;
vpSects.back()->GetBBox( frSect, b3Temp) ;
b3Sect.Add( b3Temp) ;
// passo alla successiva
nSectId = m_pGeomDB->GetNext( nSectId) ;
}
// recupero la linea guida
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ;
if ( pGuide == nullptr)
return false ;
// recupero gli estremi della linea guida
Point3d ptGdStart, ptGdEnd ;
pGuide->GetStartPoint( ptGdStart) ;
pGuide->GetEndPoint( ptGdEnd) ;
// recupero la direzione della linea guida
Vector3d vtGdDir ;
pGuide->GetStartDir( vtGdDir) ;
// per ora ammesse solo linee guida rettilinee dirette lungo X o Y
if ( ! AreSameOrOppositeVectorApprox( vtGdDir, X_AX) &&
! AreSameOrOppositeVectorApprox( vtGdDir, Y_AX)) {
LOG_INFO( GetEMkLogger(), "Error in SawFinishing : Guide Line not along X or Y") ;
return false ;
}
// recupero il box del grezzo
BBox3d b3Raw ;
if ( ! GetRawGlobBox( m_nPhase, nGuideId, b3Raw) || b3Raw.IsEmpty()) {
LOG_INFO( GetEMkLogger(), "Error in SawFinishing : Empty RawBox") ;
return false ;
}
// aggiusto la linea guida al bordo del box
if ( AreSameVectorApprox( vtGdDir, X_AX)) {
ptGdStart.x = b3Raw.GetMin().x ;
ptGdEnd.x = b3Raw.GetMax().x ;
}
else if ( AreOppositeVectorApprox( vtGdDir, X_AX)) {
ptGdStart.x = b3Raw.GetMax().x ;
ptGdEnd.x = b3Raw.GetMin().x ;
}
else if ( AreSameVectorApprox( vtGdDir, Y_AX)) {
ptGdStart.y = b3Raw.GetMin().y ;
ptGdEnd.y = b3Raw.GetMax().y ;
}
else {
ptGdStart.y = b3Raw.GetMax().y ;
ptGdEnd.y = b3Raw.GetMin().y ;
}
// offset radiale delle sezioni per il sovramateriale
double dOffsR = GetOffsR() ;
POCRVVECTOR vpOvrCrvs ;
vpOvrCrvs.reserve( vpSects.size()) ;
for ( const auto& pSect : vpSects) {
OffsetCurve OffsCrv ;
OffsCrv.Make( pSect, dOffsR, ICurve::OFF_FILLET) ;
vpOvrCrvs.emplace_back( OffsCrv.GetLongerCurve()) ;
}
// ricavo dalla sezione la curva per centro in basso della lama
double dOffsX = 0.5 * m_TParams.m_dThick ;
POCRVVECTOR vpCrvs ;
vpCrvs.reserve( vpOvrCrvs.size()) ;
for ( auto& pOvrCrv : vpOvrCrvs) {
OffsetCurveOnX OffsCrvX ;
OffsCrvX.Make( Get( pOvrCrv), dOffsX) ;
vpCrvs.emplace_back( OffsCrvX.GetLongerCurve()) ;
}
//int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, m_pGeomDB->GetParentId( nSectId), ::Release( pCrv)) ;
//m_pGeomDB->Save( nCrvId, "C:\\EgtData\\Varie\\Test\\aaa.nge", GDB_SV_TXT) ;
//pCrv.Set( ::GetCurve( m_pGeomDB->RemoveGeoObjAndErase( nCrvId))) ;
// determino l'ingombro delle sezioni in locale
BBox3d b3Crv ;
for ( auto& pCrv : vpCrvs) {
BBox3d b3Temp ;
pCrv->GetLocalBBox( b3Temp) ;
b3Crv.Add( b3Temp) ;
}
// valuto l'espressione dell'affondamento
ExeLuaSetGlobNumVar( "TH", 0) ;
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
double dDepth ;
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
LOG_INFO( GetEMkLogger(), "Error in SawFinishing : Depth not computable") ;
return false ;
}
// creo gruppo per geometria di lavorazione
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
if ( nPxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
// Determino versori fresa e correzione
Vector3d vtTool, vtCorr ;
if ( ! CalculateToolAndCorrVersors( vtGdDir, m_Params.m_nHeadSide, vtTool, vtCorr)) {
LOG_INFO( GetEMkLogger(), "Error in SawFinishing : CalculateToolAndCorrVersors") ;
return false ;
}
// Imposto dati comuni
SetPathId( nPxId) ;
SetToolDir( vtTool) ;
SetCorrDir( vtCorr) ;
// Ciclo sulle passate
double dLargh = b3Crv.GetMax().x - b3Crv.GetMin().x ;
double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ;
int nStep = static_cast<int>( ceil( dLargh / dStep)) ;
dStep = dLargh / nStep ;
double dSectYMin = b3Crv.GetMin().y ;
double dSectYMax = b3Crv.GetMax().y ;
int nCount = 0 ;
for ( int i = 0 ; i <= nStep ; ++ i) {
// flag per primo e ultimo taglio
bool bFirst = ( i == 0) ;
bool bLast = ( i == nStep) ;
// determino l'ascissa della prima intersezione
double dX = b3Crv.GetMax().x - i * dStep ;
// determino l'ordinata della prima intersezione
double dY ;
double dYmin = dSectYMin ;
for ( auto& pCrv : vpCrvs) {
if ( ! GetHeightOnSection( Get( pCrv), dX, dYmin, dSectYMax, dY))
return false ;
dYmin = dY ;
}
// estremi del taglio
Vector3d vtMove = dX * frSect.VersX() + dY * frSect.VersY() - 0.5 * m_TParams.m_dThick * vtTool ;
Point3d ptStart = ptGdStart + vtMove ;
Point3d ptEnd = ptGdEnd + vtMove ;
// determino l'elevazione del taglio
Vector3d vtThick = vtTool * m_TParams.m_dThick ;
double dElev, dElev2 ;
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev) ||
! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev2) ) {
LOG_INFO( GetEMkLogger(), "Error in SawFinishinging : GetElevation") ;
return false ;
}
dElev = max( dElev, dElev2) ;
// la confronto con il massimo affondamento e con la massima lavorazione della lama
double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ;
if ( dElev > dMaxDepth) {
ptStart += Vector3d( 0, 0, dElev - dMaxDepth) ;
ptEnd += Vector3d( 0, 0, dElev - dMaxDepth) ;
dElev = dMaxDepth ;
}
// esecuzione del taglio
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
if ( ! CalculateOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bFirst, bLast))
return false ;
}
else {
if ( ! CalculateZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bFirst, bLast, nCount))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bFirst, bool bLast)
{
// recupero distanza di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// se attacco/uscita/collegamento esterno allungo inizio
Point3d ptNewStart = ptStart ;
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
ptNewStart = ptStart - vtDir * dAppr ;
}
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
// distanza XY tra centro e bordo taglio
double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ;
// modifico inizio
ptNewStart = ptStart - vtDir * ( dDeltaT + dAppr) ;
}
// Sempre una sola passata
{
// 1 -> approccio
if ( ! AddApproach( ptNewStart, vtCorr, bFirst, dSafeZ, dElev, dAppr))
return false ;
// 2 -> movimento in affondo al punto iniziale
SetFlag( 0) ;
if ( m_Params.m_nLeadLinkType != SAWFIN_LL_OUT)
SetFeed( GetTipFeed()) ;
else
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
return false ;
// 3 -> movimento di lato al punto finale
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptEnd) == GDB_ID_NULL)
return false ;
// 4 -> retrazione
if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateZigZagCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bFirst, bool bLast,
int& nCount)
{
// recupero distanza di sicurezza
double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// aggiorno inizio, fine e direzione movimento
Point3d ptOriStart = ptStart ;
Point3d ptOriEnd = ptEnd ;
Point3d ptNewStart = ptStart ;
Point3d ptNewEnd = ptEnd ;
Vector3d vtNewDir = vtDir ;
// se attacco/uscita/collegamento standard allungo inizio e fine dell'approccio
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
// modifico inizio
ptNewStart = ptStart - vtDir * dAppr ;
// modifico fine
ptNewEnd = ptEnd + vtDir * dAppr ;
}
// se attacco/uscita/collegamento esterno allungo inizio e fine a fuori grezzo
else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
// distanza XY tra centro e bordo taglio
double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ;
// modifico inizio
ptNewStart = ptStart - vtDir * ( dDeltaT + dAppr) ;
// modifico fine
ptNewEnd = ptEnd + vtDir * ( dDeltaT + dAppr) ;
}
// le passate dispari sono al contrario
if ( ( nCount % 2) != 0) {
swap( ptOriStart, ptOriEnd) ;
swap( ptNewStart, ptNewEnd) ;
vtNewDir.Invert() ;
}
// Sempre una sola passata
{
// 1 -> approccio
if ( bFirst || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
if ( ! AddApproach( ptNewStart, vtCorr, bFirst, dSafeZ, dElev, dAppr))
return false ;
}
// 2 -> movimento in affondo al punto iniziale
SetFlag( 0) ;
// con attacco centrato sono sul materiale e devo usare feed di testa
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
SetFeed( GetTipFeed()) ;
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
return false ;
}
// con attacco fuori sono in aria
else {
if ( bFirst) {
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
return false ;
}
else {
Point3d ptLast ;
GetCurrPos( ptLast) ;
double dDiff = ( ptNewStart - ptLast) * vtNewDir ;
// se precedente e corrente sono fuori allo stesso modo
if ( abs( dDiff) < 10 * EPS_SMALL) {
// inizio nuova passata
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
return false ;
}
// se il precedente è più fuori
else if ( dDiff > 0) {
// allungo nuova passata
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewStart - dDiff * vtNewDir) == GDB_ID_NULL)
return false ;
}
// se il corrente è più fuori
else {
// allungo passata precedente
if ( AddLinearMove( ptLast + dDiff * vtNewDir) == GDB_ID_NULL)
return false ;
// inizio nuova passata
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewStart) == GDB_ID_NULL)
return false ;
}
}
}
// 3 -> movimento di lato al punto finale
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptNewEnd) == GDB_ID_NULL)
return false ;
}
else {
SetFeed( GetFeed()) ;
if ( AddLinearMove( ptOriEnd) == GDB_ID_NULL)
return false ;
SetFeed( GetEndFeed()) ;
if ( AddLinearMove( ptNewEnd) == GDB_ID_NULL)
return false ;
}
// 4 -> retrazione
if ( bLast || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) {
if ( ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dElev, dAppr))
return false ;
}
// incremento contatore passate
++ nCount ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtCorr, bool bFirst,
double dSafeZ, double dElev, double dAppr)
{
// se distanza di sicurezza minore di distanza di inizio
if ( dSafeZ < m_Params.m_dStartPos + 10 * EPS_SMALL) {
// 1 -> punto sopra inizio
Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ;
if ( bFirst) {
SetFlag( 1) ;
if ( AddRapidStart( ptP1) == GDB_ID_NULL)
return false ;
}
else {
SetFlag( 0) ;
if ( AddRapidMove( ptP1) == GDB_ID_NULL)
return false ;
}
}
else {
// 1a -> punto sopra inizio
Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ;
Point3d ptP1a = ptP1b + Z_AX * ( dSafeZ - m_Params.m_dStartPos) ;
if ( bFirst) {
SetFlag( 1) ;
if ( AddRapidStart( ptP1a) == GDB_ID_NULL)
return false ;
}
else {
SetFlag( 0) ;
if ( AddRapidMove( ptP1a) == GDB_ID_NULL)
return false ;
}
// 1b -> punto appena sopra inizio
SetFlag( 0) ;
if ( AddRapidMove( ptP1b) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::AddRetract( const Point3d& ptP, const Vector3d& vtCorr, double dSafeZ, double dElev, double dAppr)
{
if ( dSafeZ < m_Params.m_dStartPos + 10 * EPS_SMALL) {
// 4 -> movimento di risalita sopra il punto finale
SetFeed( GetEndFeed()) ;
Point3d ptP4 = ptP + vtCorr * ( dElev + dAppr) ;
if ( AddLinearMove( ptP4) == GDB_ID_NULL)
return false ;
}
else {
// 4a -> movimento di risalita appena sopra il punto finale
SetFeed( GetEndFeed()) ;
Point3d ptP4a = ptP + vtCorr * ( dElev + dAppr) ;
if ( AddLinearMove( ptP4a) == GDB_ID_NULL)
return false ;
// 4b -> movimento di risalita sopra il punto finale
Point3d ptP4b = ptP4a + Z_AX * ( dSafeZ - m_Params.m_dStartPos) ;
if ( AddRapidMove( ptP4b) == GDB_ID_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateToolAndCorrVersors( const Vector3d& vtTang, int nHeadSide,
Vector3d& vtTool, Vector3d& vtCorr)
{
// Versore fresa : annullo la componente in Z e normalizzo
vtTool = vtTang ;
vtTool.z = 0 ;
if ( ! vtTool.Normalize())
return false ;
// ruoto attorno a Zglob+ a seconda del lato mandrino
if ( nHeadSide == SAW_HS_LEFT)
vtTool.Rotate( Z_AX, 90) ;
else
vtTool.Rotate( Z_AX, -90) ;
// Versore correzione
vtCorr = Z_AX ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::GetHeightOnSection( const ICurve* pSect, double dX, double dYmin, double dYmax, double& dY)
{
// creo raggio per intersezione con direzione Y+
PtrOwner<ICurveLine>pRay( CreateCurveLine()) ;
if ( IsNull( pRay) ||
! pRay->Set( Point3d( dX, dYmin - EPS_SMALL, 0), Point3d( dX, dYmax + EPS_SMALL, 0)))
return false ;
// eseguo intersezione (considero l'ultima, ovvero quella con Y maggiore)
IntersCurveCurve intCC( *Get( pRay), *pSect) ;
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo)) {
// nel caso di sovrapposizione devo prendere la Y in basso del tratto
dY = aInfo.IciA[0].ptI.y ;
return true ;
}
// se non c'è intersezione assegno il minimo
dY = dYmin ;
return true ;
}