diff --git a/ChainCurves.cpp b/ChainCurves.cpp index 2fd1499..1b702d5 100644 --- a/ChainCurves.cpp +++ b/ChainCurves.cpp @@ -52,10 +52,6 @@ ChainCurves::AddCurve( int nId, const Point3d& ptStart, const Vector3d& vtStart, // li inserisco nel PointGrid3d m_PointGrid.InsertPoint( ptStart, nV) ; m_PointGrid.InsertPoint( ptEnd, - nV) ; - // verifico il valore di tolleranza rispetto alla distanza tra gli estremi dell'entità (ignoro curve chiuse) - double dDist = Dist( ptStart, ptEnd) ; - if ( dDist > EPS_SMALL && m_dToler > dDist / 2) - m_dToler = max( dDist / 2, EPS_SMALL) ; return true ; } diff --git a/DistPointTria.cpp b/DistPointTria.cpp new file mode 100644 index 0000000..34e8a09 --- /dev/null +++ b/DistPointTria.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : DistPointTria.cpp Data : 19.10.17 Versione : 1.8j4 +// Contenuto : Implementazione della classe distanza punto da triangolo. +// +// +// +// Modifiche : 19.10.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ProjPlane.h" +#include "DistPointLine.h" +#include "/EgtDev/Include/EGkDistPointTria.h" + + +//---------------------------------------------------------------------------- +DistPointTriangle::DistPointTriangle( const Point3d& ptP, const Triangle3d& Tria) +{ + if ( &Tria == nullptr || ! Tria.IsValid()) { + // distanza non calcolabile + m_dSqDist = - 1 ; + return ; + } + + // eseguo calcoli e determino il quadrato della distanza + Calculate( ptP, Tria) ; + + // dichiaro distanza non ancora calcolata + m_dDist = - 1 ; +} + +//---------------------------------------------------------------------------- +void +DistPointTriangle::Calculate( const Point3d& ptP, const Triangle3d& Tria) +{ + // Proiezione del punto sul piano del triangolo + Point3d ptQ = ptP - (( ptP - Tria.GetP( 0)) * Tria.GetN()) * Tria.GetN() ; + + // Verifico se il punto proiettato sta nel triangolo + if ( PointInTria( ptQ, Tria) != PTT_OUT) { + m_dSqDist = SqDist( ptP, ptQ) ; + m_ptMinDist = ptQ ; + return ; + } + + // Determino la minima distanza dai tre lati + for ( int i = 0 ; i < 3 ; ++ i) { + DistPointLine dstPL( ptQ, Tria.GetP( i), Tria.GetP( ( i + 1) % 3)) ; + double dSqDist ; + if ( dstPL.GetSqDist( dSqDist) && ( m_dSqDist < 0 || dSqDist < m_dSqDist)) { + m_dSqDist = dSqDist ; + dstPL.GetMinDistPoint( m_ptMinDist) ; + } + } +} + +//---------------------------------------------------------------------------- +bool +DistPointTriangle::GetSqDist( double& dSqDist) +{ + if ( m_dSqDist < 0) + return false ; + + dSqDist = m_dSqDist ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointTriangle::GetDist( double& dDist) +{ + if ( m_dSqDist < 0) + return false ; + + if ( m_dDist < 0) + m_dDist = sqrt( m_dSqDist) ; + dDist = m_dDist ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointTriangle::GetMinDistPoint( Point3d& ptMinDist) +{ + if ( m_dSqDist < 0) + return false ; + + ptMinDist = m_ptMinDist ; + return true ; +} diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index df3a9af..03332ff 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -267,7 +267,10 @@ copy $(TargetPath) \EgtProg\Dll64 + + + @@ -388,6 +391,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -408,6 +412,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 0f1ed74..a6f8f4a 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -363,6 +363,15 @@ File di origine\GeoInters + + File di origine\GeoInters + + + File di origine\GeoInters + + + File di origine\GeoDist + @@ -791,6 +800,12 @@ File di intestazione\Include + + File di intestazione\Include + + + File di intestazione\Include + diff --git a/IntersCrvCompoCrvCompo.cpp b/IntersCrvCompoCrvCompo.cpp index dac0154..cce1610 100644 --- a/IntersCrvCompoCrvCompo.cpp +++ b/IntersCrvCompoCrvCompo.cpp @@ -170,213 +170,249 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA, } } - // sistemazione di intersezioni coincidenti + // sistemazione di intersezioni coincidenti con ordinamento su prima curva A for ( int i = 0 ; i < m_nNumInters ; ++ i) { - for ( int j = 0 ; j < m_nNumInters ; ++ j) { - // se i due indici coincidono, passo oltre - if ( i == j) - continue ; - // calcolo sottoindici - int ki = 0 ; // del successivo si prende sempre il primo - int kj = ( m_Info[j].bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap - // verifico se precedente e corrente si riferiscono alla stessa intersezione (10 * EPS_SMALL) - if ( AreSamePointXYEpsilon( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI, 10 * EPS_SMALL) && - AreSamePointXYEpsilon( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI, 10 * EPS_SMALL) && - CompatibleParamA( m_Info[j], m_Info[i], bCrvAClosed, dCrvASpan) && - CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan)) { - // caso DET-NULL -> NULL-DET per prima curva - if ( m_Info[j].IciA[kj].nPrevTy != ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL && - m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy != ICCT_NULL) { - // per la prima curva tengo i determinati - m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ; - m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; - // se overlap equiverso - if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { - // per la seconda curva ogni sottotipo è il duale di quello della prima - m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; - m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { - // per la seconda curva ogni sottotipo è come quello della prima ma in posizione invertita - m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; - m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; - } - // se overlap equiverso - if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { - m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; - m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { - m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; - m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; - } - // medio parametri e punti separatamente per le due curve - MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; - MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; - // se entrambi overlap non cancello - if ( m_Info[j].bOverlap && m_Info[i].bOverlap) - continue ; - // cancello un singolo - if ( m_Info[i].bOverlap) { - EraseOtherInfo( i, j) ; - } - else { - EraseCurrentInfo( i, j) ; - break ; - } + // precedente + int j = i - 1 ; + if ( j < 0) { + if ( bCrvAClosed && m_nNumInters > 1) + j = m_nNumInters - 1 ; + else + continue ; + } + // calcolo sottoindici + int ki = 0 ; // del successivo si prende sempre il primo + int kj = ( m_Info[j].bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap + // verifico se precedente e corrente si riferiscono alla stessa intersezione (10 * EPS_SMALL) + if ( AreSamePointXYEpsilon( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI, 10 * EPS_SMALL) && + AreSamePointXYEpsilon( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI, 10 * EPS_SMALL) && + CompatibleParamA( m_Info[j], m_Info[i], bCrvAClosed, dCrvASpan) && + CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan)) { + // caso DET-NULL -> NULL-DET per prima curva + if ( m_Info[j].IciA[kj].nPrevTy != ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL && + m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy != ICCT_NULL) { + // per la prima curva tengo i determinati + m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ; + m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; + // se overlap equiverso + if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { + // per la seconda curva ogni sottotipo è il duale di quello della prima + m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; + m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } - // caso NULL-DET -> DET-NULL per prima curva (possibile su inizio/fine di curva chiusa) - else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy != ICCT_NULL && - m_Info[i].IciA[ki].nPrevTy != ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { - // per la prima curva tengo i determinati - m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[kj].nNextTy ; - m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ; - // se overlap equiverso - if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { - // per la seconda curva ogni sottotipo è il duale di quello della prima - m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; - m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { - // per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata - m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; - m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; - } - // se overlap equiverso - if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { - // per la seconda curva ogni sottotipo è il duale di quello della prima - m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; - m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { - // per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata - m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; - m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; - } - // medio parametri e punti separatamente per le due curve - MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; - MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; - // se entrambi overlap non cancello - if ( m_Info[j].bOverlap && m_Info[i].bOverlap) - continue ; - // cancello un singolo - if ( m_Info[i].bOverlap) { - EraseOtherInfo( i, j) ; - } - else { - EraseCurrentInfo( i, j) ; - break ; - } + // se altrimenti overlap controverso + else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { + // per la seconda curva ogni sottotipo è come quello della prima ma in posizione invertita + m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; + m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } - // caso DET-NULL -> NULL-DET per seconda curva - else if ( m_Info[j].IciB[kj].nPrevTy != ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL && - m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy != ICCT_NULL) { - // per la seconda curva tengo i determinati - m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ; - m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; - // se overlap equiverso - if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { - // per la prima curva ogni sottotipo è il duale di quello della seconda - m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; - m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { - // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata - m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; - m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; - } - // se overlap equiverso - if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { - // per la prima curva ogni sottotipo è il duale di quello della seconda - m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; - m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { - // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata - m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; - m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; - } - // medio parametri e punti separatamente per le due curve - MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; - MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; - // se entrambi overlap non cancello - if ( m_Info[j].bOverlap && m_Info[i].bOverlap) - continue ; - // cancello un singolo - if ( m_Info[i].bOverlap) { - EraseOtherInfo( i, j) ; - } - else { - EraseCurrentInfo( i, j) ; - break ; - } + // se overlap equiverso + if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { + m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; + m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } - // caso NULL-DET -> DET-NULL per seconda curva (possibile su inizio/fine di curva chiusa) - else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy != ICCT_NULL && - m_Info[i].IciB[ki].nPrevTy != ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) { - // per la seconda curva tengo i determinati - m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ; - m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ; - // se overlap equiverso - if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { - // per la prima curva ogni sottotipo è il duale di quello della seconda - m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; - m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { - // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata - m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; - m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; - } - // se overlap equiverso - if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { - // per la prima curva ogni sottotipo è il duale di quello della seconda - m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; - m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; - } - // se altrimenti overlap controverso - else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { - // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata - m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; - m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; - } - // medio parametri e punti separatamente per le due curve - MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; - MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; - // se entrambi overlap non cancello - if ( m_Info[j].bOverlap && m_Info[i].bOverlap) - continue ; - // cancello un singolo - if ( m_Info[i].bOverlap) { - EraseOtherInfo( i, j) ; - } - else { - EraseCurrentInfo( i, j) ; - break ; - } + // se altrimenti overlap controverso + else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { + m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; + m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } - // caso NULL-NULL per corrente di prima curva - else if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { - // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) - EraseCurrentInfo( i, j) ; - break ; - } - // caso NULL-NULL per precedente di prima curva - else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL) { - // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) + // medio parametri e punti separatamente per le due curve + MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; + MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; + // se entrambi overlap non cancello + if ( m_Info[j].bOverlap && m_Info[i].bOverlap) + continue ; + // cancello un singolo + if ( m_Info[i].bOverlap) { EraseOtherInfo( i, j) ; } + else { + EraseCurrentInfo( i, j) ; + } + } + // caso NULL-DET -> DET-NULL per prima curva (possibile su inizio/fine di curva chiusa) + else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy != ICCT_NULL && + m_Info[i].IciA[ki].nPrevTy != ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { + // per la prima curva tengo i determinati + m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[kj].nNextTy ; + m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ; + // se overlap equiverso + if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { + // per la seconda curva ogni sottotipo è il duale di quello della prima + m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; + m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { + // per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata + m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; + m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; + } + // se overlap equiverso + if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { + // per la seconda curva ogni sottotipo è il duale di quello della prima + m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; + m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { + // per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata + m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; + m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; + } + // medio parametri e punti separatamente per le due curve + MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; + MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; + // se entrambi overlap non cancello + if ( m_Info[j].bOverlap && m_Info[i].bOverlap) + continue ; + // cancello un singolo + if ( m_Info[i].bOverlap) { + EraseOtherInfo( i, j) ; + } + else { + EraseCurrentInfo( i, j) ; + } + } + // caso NULL-NULL per corrente di prima curva + else if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { + m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; + // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) + EraseCurrentInfo( i, j) ; + } + // caso NULL-NULL per precedente di prima curva + else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL) { + m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ; + // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) + EraseOtherInfo( i, j) ; } } } + // sistemazione di intersezioni coincidenti con ordinamento su seconda curva B + stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ; + for ( int i = 0 ; i < m_nNumInters ; ++ i) { + // precedente + int j = i - 1 ; + if ( j < 0) { + if ( bCrvAClosed && m_nNumInters > 1) + j = m_nNumInters - 1 ; + else + continue ; + } + // calcolo sottoindici + int ki = 0 ; // del successivo si prende sempre il primo + int kj = ( m_Info[j].bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap + // verifico se precedente e corrente si riferiscono alla stessa intersezione (10 * EPS_SMALL) + if ( AreSamePointXYEpsilon( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI, 10 * EPS_SMALL) && + AreSamePointXYEpsilon( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI, 10 * EPS_SMALL) && + CompatibleParamA( m_Info[j], m_Info[i], bCrvAClosed, dCrvASpan) && + CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan)) { + // caso DET-NULL -> NULL-DET per seconda curva + if ( m_Info[j].IciB[kj].nPrevTy != ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL && + m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy != ICCT_NULL) { + // per la seconda curva tengo i determinati + m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ; + m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; + // se overlap equiverso + if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { + // per la prima curva ogni sottotipo è il duale di quello della seconda + m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; + m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { + // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata + m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; + m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; + } + // se overlap equiverso + if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { + // per la prima curva ogni sottotipo è il duale di quello della seconda + m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; + m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { + // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata + m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; + m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; + } + // medio parametri e punti separatamente per le due curve + MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; + MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; + // se entrambi overlap non cancello + if ( m_Info[j].bOverlap && m_Info[i].bOverlap) + continue ; + // cancello un singolo + if ( m_Info[i].bOverlap) { + EraseOtherInfo( i, j) ; + } + else { + EraseCurrentInfo( i, j) ; + } + } + // caso NULL-DET -> DET-NULL per seconda curva (possibile su inizio/fine di curva chiusa) + else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy != ICCT_NULL && + m_Info[i].IciB[ki].nPrevTy != ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) { + // per la seconda curva tengo i determinati + m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ; + m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ; + // se overlap equiverso + if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { + // per la prima curva ogni sottotipo è il duale di quello della seconda + m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; + m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { + // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata + m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; + m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; + } + // se overlap equiverso + if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { + // per la prima curva ogni sottotipo è il duale di quello della seconda + m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; + m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; + } + // se altrimenti overlap controverso + else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { + // per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata + m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; + m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; + } + // medio parametri e punti separatamente per le due curve + MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; + MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; + // se entrambi overlap non cancello + if ( m_Info[j].bOverlap && m_Info[i].bOverlap) + continue ; + // cancello un singolo + if ( m_Info[i].bOverlap) { + EraseOtherInfo( i, j) ; + } + else { + EraseCurrentInfo( i, j) ; + } + } + // caso NULL-NULL per corrente di seconda curva + else if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) { + m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; + // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) + EraseCurrentInfo( i, j) ; + } + // caso NULL-NULL per precedente di seconda curva + else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL) { + m_Info[i].IciB[0].nPrevTy = m_Info[j].IciB[0].nPrevTy ; + // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) + EraseOtherInfo( i, j) ; + } + } + } + // ripristino ordinamento su prima curva + stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ; + // verifico se sono rimaste delle intersezioni di tipo non definito sulla curva A e cerco di risolverle per continuità for ( int i = 0 ; i < m_nNumInters ; ++ i) { // se il tipo di accostamento per la curva A non è definito diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index b7437b6..de58ef5 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -162,17 +162,17 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li m_Info.IciB[0].dU = CrossXY( ( ptS2 - ptS1), vtDir1) / dCrossXY ; // verifica posizione intersezione su prima linea int nPos1 = ICurve::PP_NULL ; // fuori - if ( ( m_Info.IciA[0].dU * vtDir1).IsSmall()) + if ( abs( m_Info.IciA[0].dU * dLen1XY) < EPS_SMALL) nPos1 = ICurve::PP_START ; // vicino a inizio - else if ( (( 1 - m_Info.IciA[0].dU) * vtDir1).IsSmall()) + else if ( abs(( 1 - m_Info.IciA[0].dU) * dLen1XY) < EPS_SMALL) nPos1 = ICurve::PP_END ; // vicino a fine else if ( m_Info.IciA[0].dU > 0 && m_Info.IciA[0].dU < 1) nPos1 = ICurve::PP_MID ; // nell'interno // verifica posizione intersezione su seconda linea int nPos2 = ICurve::PP_NULL ; // fuori - if ( ( m_Info.IciB[0].dU * vtDir2).IsSmall()) + if ( abs( m_Info.IciB[0].dU * dLen2XY) < EPS_SMALL) nPos2 = ICurve::PP_START ; // vicino a inizio - else if ( (( 1 - m_Info.IciB[0].dU) * vtDir2).IsSmall()) + else if ( abs(( 1 - m_Info.IciB[0].dU) * dLen2XY) < EPS_SMALL) nPos2 = ICurve::PP_END ; // vicino a fine else if ( m_Info.IciB[0].dU > 0 && m_Info.IciB[0].dU < 1) nPos2 = ICurve::PP_MID ; // nell'interno diff --git a/IntersLineTria.cpp b/IntersLineTria.cpp index 6fa89ab..100565b 100644 --- a/IntersLineTria.cpp +++ b/IntersLineTria.cpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------- -// EgalTech 2015-2015 +// EgalTech 2015-2017 //---------------------------------------------------------------------------- -// File : IntersLinePlane.cpp Data : 18.02.15 Versione : 1.6b7 +// File : IntersLineTria.cpp Data : 16.10.17 Versione : 1.8j4 // Contenuto : Implementazione della intersezione linea/triangolo. // // @@ -16,19 +16,17 @@ #include "ProjPlane.h" #include "CurveLine.h" #include "IntersLineLine.h" +#include "IntersLineTria.h" #include "/EgtDev/Include/EGkFrame3d.h" -#include "/EgtDev/Include/EGkIntersLineTria.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" +#include - -//---------------------------------------------------------------------------- -static int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, - Point3d& ptInt, Point3d& ptInt2) ; +using namespace std ; //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTria, - Point3d& ptInt, Point3d& ptInt2) + Point3d& ptInt, Point3d& ptInt2, bool bFinite) { Vector3d vtL = ptL2 - ptL1 ; double dLen = vtL.Len() ; @@ -36,19 +34,19 @@ IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTr vtL /= dLen ; else vtL = V_NULL ; - return IntersLineTria( ptL1, vtL, dLen, trTria, ptInt, ptInt2) ; + return IntersLineTria( ptL1, vtL, dLen, trTria, ptInt, ptInt2, bFinite) ; } //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, - Point3d& ptInt, Point3d& ptInt2) + Point3d& ptInt, Point3d& ptInt2, bool bFinite) { // determino il piano del triangolo Plane3d plPlane ; plPlane.Set( trTria.GetP( 0), trTria.GetN()) ; // calcolo l'intersezione tra il segmento di linea e il piano del triangolo - int nRes = IntersLinePlane( ptL, vtL, dLen, plPlane, ptInt) ; + int nRes = IntersLinePlane( ptL, vtL, dLen, plPlane, ptInt, bFinite) ; // se non c'è intersezione if ( nRes == ILPT_NO) return ILTT_NO ; @@ -68,134 +66,253 @@ IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Tria } // se la linea giace nel piano del triangolo else { - return IntersCoplanarLineTria( ptL, vtL, dLen, trTria, ptInt, ptInt2) ; + return IntersCoplanarLineTria( ptL, vtL, dLen, trTria, ptInt, ptInt2, bFinite) ; } } //---------------------------------------------------------------------------- int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, - Point3d& ptInt, Point3d& ptInt2) + Point3d& ptInt, Point3d& ptInt2, bool bFinite) { - // verifico se il segmento è completamente contenuto nel triangolo - ptInt = ptL ; - ptInt2 = ptL + vtL * dLen ; - int nPTT = PointInTria( ptInt, trTria) ; - int nPTT2 = PointInTria( ptInt2, trTria) ; - if ( ( nPTT == PTT_IN && nPTT2 != PTT_OUT) || ( nPTT != PTT_OUT && nPTT2 == PTT_IN)) - return ILTT_SEGM ; - if ( nPTT == PTT_VERT && nPTT2 == PTT_VERT) - return ILTT_SEGM_ON_EDGE ; - if ( ( nPTT == PTT_VERT || nPTT == PTT_EDGE) && ( nPTT2 == PTT_VERT || nPTT2 == PTT_EDGE)) { - Point3d ptMed = Media( ptInt, ptInt2, 0.5) ; - if ( PointInTria( ptMed, trTria) == PTT_IN) - return ILTT_SEGM ; - else + // Normale alla linea giacente nel piano + Vector3d vtN = vtL ^ trTria.GetN() ; + vtN.Normalize() ; + // calcolo le distanze dei vertici del triangolo dalla retta + array< double, 3> vDist ; + for ( int i = 0 ; i < 3 ; ++i) + vDist[i] = ( trTria.GetP( i) - ptL) * vtN ; + // verifico posizione del triangolo rispetto alla retta + array vPos = { 0, 0, 0} ; + int nVertPos = 0 ; int nVertNeg = 0 ; + for ( int i = 0 ; i < 3 ; ++i) { + if ( vDist[i] > EPS_SMALL) { + vPos[i] = 1 ; + ++ nVertPos ; + } + else if ( vDist[i] < -EPS_SMALL) { + vPos[i] = -1 ; + ++ nVertNeg ; + } + } + // Se il triangolo giace tutto da una parte della retta, nessuna intersezione + if ( nVertPos == 3 || nVertNeg == 3) { + return ILTT_NO ; + } + // Se altrimenti il triangolo giace sulla retta (triangolo schiacciato), sovrapposizione + else if ( nVertPos == 0 && nVertNeg == 0) { + // Determino i vertici estremi sulla retta + double dUmin = ( trTria.GetP( 0) - ptL) * vtL ; + double dUmax = ( trTria.GetP( 1) - ptL) * vtL ; + ptInt = trTria.GetP( 0) ; + ptInt2 = trTria.GetP( 1) ; + if ( dUmin > dUmax) { + swap( dUmin, dUmax) ; + swap( ptInt, ptInt2) ; + } + double dU2 = ( trTria.GetP( 2) - ptL) * vtL ; + if ( dU2 < dUmin) + ptInt = trTria.GetP( 2) ; + else if ( dU2 > dUmax) + ptInt2 = trTria.GetP( 2) ; + // Se linea infinita + if ( ! bFinite) { return ILTT_SEGM_ON_EDGE ; - } - // se segmento nullo, basta verificare la posizione del punto iniziale - if ( dLen < EPS_SMALL || vtL.IsSmall()) { - switch ( nPTT) { - case PTT_OUT : - return ILTT_NO ; - case PTT_VERT : - return ILTT_VERT ; - case PTT_EDGE : - return ILTT_EDGE ; - default : - return ILTT_IN ; } - } - // definisco un riferimento coincidente con il piano del triangolo - Frame3d frRef ; - if ( ! frRef.Set( trTria.GetP( 0), trTria.GetN(), ( trTria.GetP( 1) - trTria.GetP( 0)))) - return ILTT_NO ; - // esprimo il triangolo e il segmento in questo riferimento - Triangle3d trTriaL = trTria ; - trTriaL.ToLoc( frRef) ; - Point3d ptLL = ptL ; - ptLL.ToLoc( frRef) ; - Vector3d vtLL = vtL ; - vtLL.ToLoc( frRef) ; - // calcolo le intersezioni tra i lati del triangolo e il segmento - CurveLine LineLL ; - LineLL.Set( ptLL, ptLL + vtLL * dLen) ; - int nNumInt = 0 ; - IntCrvCrvInfo IntCCI[3] ; - for ( int i = 0 ; i < 3 ; ++ i) { - CurveLine LineTL ; - LineTL.Set( trTriaL.GetP( i), trTriaL.GetP( ( i + 1) % 3)) ; - IntersLineLine IntLL( LineLL, LineTL) ; - if ( IntLL.GetIntCrvCrvInfo( IntCCI[nNumInt])) - ++ nNumInt ; - } - // se nessuna intersezione - if ( nNumInt == 0) - return ILTT_NO ; - // se una sola intersezione - else if ( nNumInt == 1) { - // punto di intersezione - Point3d ptIntL = IntCCI[0].IciA[0].ptI ; - ptInt = ptIntL ; - ptInt.ToGlob( frRef) ; - // se è l'inizio del segmento ( e il resto del segmento deve essere per forza esterno) - if ( AreSamePointApprox( ptIntL, LineLL.GetStart())) - return ( ( nPTT == PTT_VERT) ? ILTT_VERT : ILTT_EDGE) ; - // se è la fine del segmento ( e il resto del segmento deve essere per forza esterno) - else if ( AreSamePointApprox( ptIntL, LineLL.GetEnd())) - return ( ( nPTT2 == PTT_VERT) ? ILTT_VERT : ILTT_EDGE) ; - // altrimenti è un punto intermedio + // Altrimenti linea finita else { - // se l'inizio è nel triangolo - if ( nPTT == PTT_IN) { - ptInt = ptL ; - ptInt2 = ptInt ; - return ILTT_SEGM ; - } - // se altrimenti è la fine nel triangolo - else if ( nPTT2 == PTT_IN) { - ptInt2 = ptL + vtL * dLen ; - return ILTT_SEGM ; - } - // altrimenti entrambi esterni, è un vertice - else + // se massimo coincide con inizio segmento di retta + if ( abs( dUmax) < EPS_SMALL) { + ptInt = ptInt2 ; return ILTT_VERT ; - } - } - // se 2 intersezioni - else if ( nNumInt == 2) { - // punti di intersezione - Point3d ptIntL = IntCCI[0].IciA[0].ptI ; - ptInt = ptIntL ; - ptInt.ToGlob( frRef) ; - Point3d ptInt2L = IntCCI[1].IciA[0].ptI ; - ptInt2 = ptInt2L ; - ptInt2.ToGlob( frRef) ; - // se coincidono, deve essere un vertice - if ( AreSamePointApprox( ptIntL, ptInt2L)) - return ILTT_VERT ; - // altrimenti è un tratto - else { - // le ordino secondo il verso positivo della linea - if ( ( ptInt - ptL) * vtL > ( ptInt2 - ptL) * vtL) - std::swap( ptInt, ptInt2) ; - return ILTT_SEGM ; - } - } - // altrimenti 3 intersezioni, una deve coincidere con un lato le altre due sono i suoi vertici - else { - for ( int i = 0 ; i < 3 ; ++ i) { - if ( IntCCI[i].bOverlap) { - // punti di intersezione - Point3d ptIntL = IntCCI[i].IciA[0].ptI ; - ptInt = ptIntL ; - ptInt.ToGlob( frRef) ; - Point3d ptInt2L = IntCCI[i].IciA[1].ptI ; - ptInt2 = ptInt2L ; - ptInt2.ToGlob( frRef) ; + } + // se minimo coincide con fine segmento di retta + else if ( abs ( dUmin - dLen) < EPS_SMALL) { + return ILTT_VERT ; + } + // se segmento non si sovrappone + else if ( dUmax < 0 || dUmin > dLen) { + return ILTT_NO ; + } + // altrimenti sovrapposizione parziale + else { + if ( dUmin < 0) + ptInt = ptL ; + if ( dUmax > dLen) + ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM_ON_EDGE ; } } } - return ILTT_NO ; -} \ No newline at end of file + // se altrimenti due vertici del triangolo giacciono sulla linea + else if ( nVertPos + nVertNeg == 1) { + // Determino i vertici sulla linea + int nCount = 0 ; + for ( int i = 0 ; i < 3 ; ++i) { + if ( vPos[i] == 0) { + if ( nCount == 0) + ptInt = trTria.GetP( i) ; + else + ptInt2 = trTria.GetP( i) ; + nCount ++ ; + } + } + // Ordino i vertici sulla linea + double dUmin = ( ptInt - ptL) * vtL ; + double dUmax = ( ptInt2 - ptL) * vtL ; + if ( dUmin > dUmax) { + swap( dUmin, dUmax) ; + swap( ptInt, ptInt2) ; + } + // Se linea infinita + if ( ! bFinite) { + return ILTT_SEGM_ON_EDGE ; + } + // Altrimenti linea finita + else { + // se massimo coincide con inizio segmento di retta + if ( abs( dUmax) < EPS_SMALL) { + ptInt = ptInt2 ; + return ILTT_VERT ; + } + // se minimo coincide con fine segmento di retta + else if ( abs ( dUmin - dLen) < EPS_SMALL) { + return ILTT_VERT ; + } + // se segmento non si sovrappone + else if ( dUmax < 0 || dUmin > dLen) { + return ILTT_NO ; + } + // altrimenti sovrapposizione parziale + else { + if ( dUmin < 0) + ptInt = ptL ; + if ( dUmax > dLen) + ptInt2 = ptL + vtL * dLen ; + return ILTT_SEGM_ON_EDGE ; + } + } + } + // se altrimenti un vertice del triangolo giace sulla retta e gli altri due sono dalla stessa parte + else if ( ( nVertPos == 2 && nVertNeg == 0) || ( nVertPos == 0 && nVertNeg == 2)) { + // Determino quale è il vertice sulla linea + for ( int i = 0 ; i < 3 ; ++i) { + if ( vPos[i] == 0) { + ptInt = trTria.GetP( i) ; + break ; + } + } + // Se linea infinita + if ( ! bFinite) { + return ILTT_VERT ; + } + // Altrimenti linea finita + else { + // devo verificare che il vertice stia sul segmento + double dU = ( ptInt - ptL) * vtL ; + if ( dU < -EPS_SMALL || dU > dLen + EPS_SMALL) + return ILTT_NO ; + else + return ILTT_VERT ; + } + } + // se altrimenti un vertice del triangolo giace sulla retta e gli altri due sono da parti opposte + else if ( nVertPos == 1 && nVertNeg == 1) { + // Determino il vertice sulla linea e gli altri due da interpolare + int nP, nM ; + for ( int i = 0 ; i < 3 ; ++i) { + if ( vPos[i] == 0) + ptInt = trTria.GetP( i) ; + else if ( vPos[i] > 0) + nP = i ; + else + nM = i ; + } + // Calcolo l'intersezione con la linea + double dCoeff = abs( vDist[nP]) / ( abs( vDist[nP]) + abs( vDist[nM])) ; + ptInt2 = Media( trTria.GetP( nP), trTria.GetP( nM), dCoeff) ; + // Ordino i vertici sulla linea + double dUmin = ( ptInt - ptL) * vtL ; + double dUmax = ( ptInt2 - ptL) * vtL ; + if ( dUmin > dUmax) { + swap( dUmin, dUmax) ; + swap( ptInt, ptInt2) ; + } + // Se linea infinita + if ( ! bFinite) { + return ILTT_SEGM ; + } + // Altrimenti linea finita + else { + // se massimo coincide con inizio segmento di retta + if ( abs( dUmax) < EPS_SMALL) { + ptInt = ptInt2 ; + return ILTT_EDGE ; + } + // se minimo coincide con fine segmento di retta + else if ( abs ( dUmin - dLen) < EPS_SMALL) { + return ILTT_EDGE ; + } + // se segmento non si sovrappone + else if ( dUmax < 0 || dUmin > dLen) { + return ILTT_NO ; + } + // altrimenti sovrapposizione parziale + else { + if ( dUmin < 0) + ptInt = ptL ; + if ( dUmax > dLen) + ptInt2 = ptL + vtL * dLen ; + return ILTT_SEGM ; + } + } + } + // altrimenti due vertici giaccio da una parte e uno da quella opposta + else { + // Determino le intersezioni + int nCount = 0 ; + for ( int i = 0 ; i < 3 ; ++ i) { + int j = ( i + 1) % 3 ; + if ( vPos[i] != vPos[j]) { + double dCoeff = abs( vDist[i]) / ( abs( vDist[i]) + abs( vDist[j])) ; + ( nCount == 0 ? ptInt : ptInt2) = Media( trTria.GetP( i), trTria.GetP( j), dCoeff) ; + ++ nCount ; + } + } + // Ordino i vertici sulla linea + double dUmin = ( ptInt - ptL) * vtL ; + double dUmax = ( ptInt2 - ptL) * vtL ; + if ( dUmin > dUmax) { + swap( dUmin, dUmax) ; + swap( ptInt, ptInt2) ; + } + // Se linea infinita + if ( ! bFinite) { + return ILTT_SEGM ; + } + // Altrimenti linea finita + else { + // se massimo coincide con inizio segmento di retta + if ( abs( dUmax) < EPS_SMALL) { + ptInt = ptInt2 ; + return ILTT_EDGE ; + } + // se minimo coincide con fine segmento di retta + else if ( abs ( dUmin - dLen) < EPS_SMALL) { + return ILTT_EDGE ; + } + // se segmento non si sovrappone + else if ( dUmax < 0 || dUmin > dLen) { + return ILTT_NO ; + } + // altrimenti sovrapposizione parziale + else { + if ( dUmin < 0) + ptInt = ptL ; + if ( dUmax > dLen) + ptInt2 = ptL + vtL * dLen ; + return ILTT_SEGM ; + } + } + } +} diff --git a/IntersLineTria.h b/IntersLineTria.h new file mode 100644 index 0000000..2c598dc --- /dev/null +++ b/IntersLineTria.h @@ -0,0 +1,21 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : IntersLineTria.cpp Data : 16.10.17 Versione : 1.8j4 +// Contenuto : Dichiarazione di funzioni intersezione linea/triangolo. +// +// +// +// Modifiche : 16.10.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkIntersLineTria.h" + +//---------------------------------------------------------------------------- +int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, + Point3d& ptInt, Point3d& ptInt2, bool bFinite = true) ; + diff --git a/IntersPlanePlane.cpp b/IntersPlanePlane.cpp index 48e5539..1791d82 100644 --- a/IntersPlanePlane.cpp +++ b/IntersPlanePlane.cpp @@ -6,15 +6,15 @@ // // // -// Modifiche : 15.12.17 DS Creazione modulo. +// Modifiche : 15.10.17 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkIntersPlanePlane.h" +#include "/EgtDev/Include/EGkIntersLinePlane.h" //---------------------------------------------------------------------------- int diff --git a/IntersPlaneSurfTm.cpp b/IntersPlaneSurfTm.cpp new file mode 100644 index 0000000..08ddebc --- /dev/null +++ b/IntersPlaneSurfTm.cpp @@ -0,0 +1,206 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : IntersPlaneSurfTm.cpp Data : 16.10.17 Versione : 1.8j4 +// Contenuto : Implementazione della intersezione piano/superficie trimesh. +// +// +// +// Modifiche : 16.10.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ProjPlane.h" +#include "IntersLineSurfTm.h" +#include "CurveLine.h" +#include "DistPointLine.h" +#include "HashGrids3d.h" +#include "/EgtDev/Include/EGkIntersPlaneSurfTm.h" +#include "/EgtDev/Include/EGkIntersPlaneTria.h" +#include "/EgtDev/Include/EGkPointGrid3d.h" +#include "/EgtDev/Include/EGkDistPointTria.h" +#include + +using namespace std ; + +//---------------------------------------------------------------------------- +// Intersezione di un piano con una superficie TriMesh +//---------------------------------------------------------------------------- +bool +IntersPlaneSurfTm( const Plane3d& plPlane, const ISurfTriMesh& Stm, + PNTVECTOR& vPnt, BIPNTVECTOR& vBpt, TRIA3DVECTOR& vTria) +{ + // verifico piano + if ( &plPlane == nullptr || plPlane.GetVersN().IsSmall()) + return false ; + // verifico superficie + if ( &Stm == nullptr || ! Stm.IsValid()) + return false ; + // verifico parametri di ritorno + if ( &vPnt == nullptr || &vBpt == nullptr || &vTria == nullptr) + return false ; + vPnt.clear() ; + vBpt.clear() ; + vTria.clear() ; + + // per ricerca veloce di punti ripetuti + PointGrid3d PtGrid ; + PtGrid.Init( 100) ; + + // per ricerca veloce di linee ripetute + HashGrids3d LnGrid ; + LnGrid.SetActivationGrid( true) ; + + // per ricerca veloce di triangoli ripetuti + HashGrids3d TrGrid ; + TrGrid.SetActivationGrid( true) ; + + // cerco i triangoli intersecati dal piano + Triangle3d Tria ; + int nT = Stm.GetFirstTriangle( Tria) ; + while ( nT != SVT_NULL) { + // intersezione tra il piano e il triangolo + Point3d ptInt, ptInt2 ; + int nRes = IntersPlaneTria( plPlane, Tria, ptInt, ptInt2) ; + // se vertice + if ( nRes == IPTT_VERT) { + // verifico se punto già inserito + int nId ; + if ( ! PtGrid.Find( ptInt, 10 * EPS_SMALL, nId)) { + vPnt.emplace_back( ptInt) ; + PtGrid.InsertPoint( ptInt, int( vPnt.size()) - 1) ; + } + } + // se altrimenti segmento + else if ( nRes == IPTT_EDGE || nRes == IPTT_YES) { + // se abbastanza lungo + if ( ! AreSamePointApprox( ptInt, ptInt2)) { + // verifico se già inserito + bool bFound = false ; + BBox3d b3Line( ptInt, ptInt2) ; + INTVECTOR vnIds ; + if ( LnGrid.Find( b3Line, vnIds)) { + for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) { + int nA = vnIds[i] ; + const Point3d& ptOth = vBpt[nA].first ; + const Point3d& ptOth2 = vBpt[nA].second ; + if ( ( AreSamePointEpsilon( ptInt, ptOth, 10 * EPS_SMALL) && + AreSamePointEpsilon( ptInt2, ptOth2, 10 * EPS_SMALL)) || + ( AreSamePointEpsilon( ptInt, ptOth2, 10 * EPS_SMALL) && + AreSamePointEpsilon( ptInt2, ptOth, 10 * EPS_SMALL))) { + bFound = true ; + break ; + } + } + } + // se non inserito, procedo + if ( ! bFound) { + vBpt.emplace_back( ptInt, ptInt2) ; + LnGrid.Add( int( vBpt.size()) - 1, b3Line) ; + LnGrid.Update() ; + } + } + } + // se altrimenti l'intero triangolo + else if ( nRes == IPTT_OVERLAPS) { + // verifico se triangolo già inserito + bool bFound = false ; + BBox3d b3Tria( Tria.GetP( 0), Tria.GetP( 1)) ; + b3Tria.Add( Tria.GetP( 2)) ; + INTVECTOR vnIds ; + if ( TrGrid.Find( b3Tria, vnIds)) { + for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) { + int nA = vnIds[i] ; + const Triangle3d& trOth = vTria[nA] ; + array< bool, 3> bOth = { false, false, false} ; + for ( int j = 0 ; j < 3 ; ++ j) { + for ( int k = 0 ; k < 3 ; ++ k) { + if ( ! bOth[k]) + bOth[k] = AreSamePointEpsilon( Tria.GetP( j), trOth.GetP( k), 10 * EPS_SMALL) ; + } + } + if ( bOth[0] && bOth[1] && bOth[2]) { + bFound = true ; + break ; + } + } + } + // se non inserito, procedo + if ( ! bFound) { + vTria.emplace_back( Tria) ; + TrGrid.Add( int( vTria.size()) - 1, b3Tria) ; + TrGrid.Update() ; + } + } + // passo al prossimo triangolo + nT = Stm.GetNextTriangle( nT, Tria) ; + } + + // rimuovo i punti che stanno sui segmenti + for ( int i = int( vPnt.size()) - 1 ; i >= 0 ; -- i) { + bool bFound = false ; + BBox3d b3Pnt( vPnt[i]) ; + b3Pnt.Expand( 10 * EPS_SMALL) ; + INTVECTOR vnIds ; + if ( LnGrid.Find( b3Pnt, vnIds)) { + for ( int j = 0 ; j < int( vnIds.size()) ; ++ j) { + int nA = vnIds[j] ; + double dSqDist ; + if ( DistPointLine( vPnt[i], vBpt[nA].first, vBpt[nA].second).GetSqDist( dSqDist) && dSqDist < 100 * SQ_EPS_SMALL) { + bFound = true ; + break ; + } + } + } + if ( bFound) + vPnt.erase( vPnt.begin() + i) ; + } + + // rimuovo i punti che stanno sui triangoli + for ( int i = int( vPnt.size()) - 1 ; i >= 0 ; -- i) { + bool bFound = false ; + BBox3d b3Pnt( vPnt[i]) ; + b3Pnt.Expand( 10 * EPS_SMALL) ; + INTVECTOR vnIds ; + if ( TrGrid.Find( b3Pnt, vnIds)) { + for ( int j = 0 ; j < int( vnIds.size()) ; ++ j) { + int nA = vnIds[j] ; + const Triangle3d& trOth = vTria[nA] ; + double dSqDist ; + if ( DistPointTriangle( vPnt[i], trOth).GetSqDist( dSqDist) && dSqDist < 100 * SQ_EPS_SMALL) { + bFound = true ; + break ; + } + } + } + if ( bFound) + vPnt.erase( vPnt.begin() + i) ; + } + + // rimuovo i segmenti che stanno sui triangoli + for ( int i = int( vBpt.size()) - 1 ; i >= 0 ; -- i) { + bool bFound = false ; + Point3d ptStart = vBpt[i].first ; + Point3d ptEnd = vBpt[i].second ; + BBox3d b3Line( ptStart, ptEnd) ; + INTVECTOR vnIds ; + if ( TrGrid.Find( b3Line, vnIds)) { + for ( int j = 0 ; j < int( vnIds.size()) ; ++ j) { + int nA = vnIds[j] ; + const Triangle3d& trOth = vTria[nA] ; + Point3d ptInt, ptInt2 ; + if ( IntersLineTria( ptStart, ptEnd, trOth, ptInt, ptInt2) == ILTT_SEGM_ON_EDGE) { + bFound = true ; + break ; + } + } + } + if ( bFound) + vBpt.erase( vBpt.begin() + i) ; + } + + return true ; +} diff --git a/IntersPlaneTria.cpp b/IntersPlaneTria.cpp new file mode 100644 index 0000000..52a4cab --- /dev/null +++ b/IntersPlaneTria.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : IntersPlaneTria.cpp Data : 16.10.17 Versione : 1.8j3 +// Contenuto : Implementazione della intersezione piano/triangolo. +// +// +// +// Modifiche : 16.10.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "IntersLineTria.h" +#include "/EgtDev/Include/EGkIntersPlaneTria.h" +#include "/EgtDev/Include/EGkIntersPlanePlane.h" +#include + +using namespace std ; + +//---------------------------------------------------------------------------- +int +IntersPlaneTria( const Plane3d& plPlane, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2) +{ + // calcolo le distanze dei vertici del triangolo dal piano + array< double, 3> vDist ; + for ( int i = 0 ; i < 3 ; ++i) + vDist[i] = ( ( trTria.GetP( i) - ORIG) * plPlane.GetVersN() - plPlane.GetDist()) ; + // verifico posizione del triangolo rispetto al piano + int nVertPos = 0 ; int nVertNeg = 0 ; + for ( auto& dDist : vDist) { + if ( dDist > EPS_SMALL) + ++ nVertPos ; + else if ( dDist < -EPS_SMALL) + ++ nVertNeg ; + } + // se il triangolo giace nel piano, sovrapposizione + if ( nVertPos == 0 && nVertNeg == 0) + return IPTT_OVERLAPS ; + // se altrimenti il triangolo giace tutto da una parte del piano, nessuna intersezione + else if ( nVertPos == 3 || nVertNeg == 3) + return IPTT_NO ; + + // intersezione tra il piano e il piano del triangolo + Plane3d plTria ; + plTria.Set( trTria.GetP( 0), trTria.GetN()) ; + Point3d ptL ; Vector3d vtL ; + if ( IntersPlanePlane( plPlane, plTria, ptL, vtL) != IPPT_YES) + return IPTT_NO ; + + // interseco la linea con il triangolo (giace nel suo piano) + int nRes = IntersCoplanarLineTria( ptL, vtL, 100.0, trTria, ptInt, ptInt2, false) ; + switch( nRes) { + case ILTT_NO : return IPTT_NO ; + case ILTT_SEGM : return IPTT_YES ; + case ILTT_SEGM_ON_EDGE : return IPTT_EDGE ; + case ILTT_VERT : return IPTT_VERT ; + case ILTT_EDGE : return IPTT_NO ; + default : return IPTT_NO ; + } +} diff --git a/MC_Tables.h b/MC_Tables.h index 27803ec..7106ee3 100644 --- a/MC_Tables.h +++ b/MC_Tables.h @@ -1747,7 +1747,7 @@ static int nIndexVsIndex10[6][2] = { { 60 , 5 }, static int Cases10Plus[6][2][12] = { -/* 195: 0, 1, 6, 7, */ {{ 7, 5, 9, 9, 8, 7, 1, 0, 11, 11, 3, 1 },// 0 +/* 195: 0, 1, 6, 7, */ {{ 7, 5, 9, 9, 8, 7, 1, 10, 11, 11, 3, 1 },// 0 { 2, 4, 4, 7, 5, 9, 8, 1, 10, 11, 3, -1}}, /* 85: 0, 2, 4, 6, */ {{ 0, 4, 1, 4, 5, 1, 3, 2, 6, 3, 6, 7 },// 1 diff --git a/PolyLine.cpp b/PolyLine.cpp index 5d155c0..f94795c 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -845,17 +845,18 @@ PolyLine::MyApproxOnSide( const Vector3d& vtN, bool bLeftSide, double dToler) ( ! bLeftSide && dCrossXY > 0 && dCros2XY > 0)) { // calcolo del punto di intersezione tra i segmenti precP-currP e nextP-next2P, allungati al centro CurveLine Line1, Line2 ; - if ( Line1.Set( precP->first, currP->first) && Line1.ExtendEndByLen( 1000) && - Line2.Set( nextP->first, nex2P->first) && Line2.ExtendStartByLen( 1000)) { + if ( Line1.Set( precP->first, currP->first) && + Line2.Set( nextP->first, nex2P->first)) { // se la normale non coincide con l'asse Z, devo portare le linee nel riferimento OCS di questa Frame3d frNorm ; if ( ! vtN.IsZplus() && ! vtN.IsZminus()) frNorm.Set( ORIG, vtN) ; Line1.ToLoc( frNorm) ; Line2.ToLoc( frNorm) ; - IntersLineLine IntLL( Line1, Line2) ; + IntersLineLine IntLL( Line1, Line2, false) ; IntCrvCrvInfo IntInfo ; - if ( IntLL.GetIntCrvCrvInfo( IntInfo) && ! IntInfo.bOverlap) { + if ( IntLL.GetIntCrvCrvInfo( IntInfo) && + ! IntInfo.bOverlap && IntInfo.IciA[0].dU > 1 && IntInfo.IciB[0].dU < 0) { Point3d ptInt = 0.5 * ( IntInfo.IciA[0].ptI + IntInfo.IciB[0].ptI) ; ptInt.ToGlob( frNorm) ; // verifico che distanza dell'intersezione dal segmento currP-nextP sia inferiore a tolleranza corrente diff --git a/SurfFlatRegionBooleans.cpp b/SurfFlatRegionBooleans.cpp index 868d208..af13c4c 100644 --- a/SurfFlatRegionBooleans.cpp +++ b/SurfFlatRegionBooleans.cpp @@ -319,8 +319,9 @@ bool SurfFlatRegion::MyChainCurves( PCRV_DEQUE& vpCurve, PCRV_DEQUE& vpLoop) { // concateno le curve + double dToler = 5 * EPS_SMALL ; ChainCurves chainC ; - chainC.Init( false, 5 * EPS_SMALL, int( vpCurve.size())) ; + chainC.Init( false, dToler, int( vpCurve.size())) ; for ( int i = 0 ; i < int( vpCurve.size()) ; ++i) { // recupero i dati della curva necessari al concatenamento e li assegno Point3d ptStart, ptEnd ; @@ -342,13 +343,26 @@ SurfFlatRegion::MyChainCurves( PCRV_DEQUE& vpCurve, PCRV_DEQUE& vpLoop) // recupero le curve e le inserisco nella nuova curva composita for ( auto i : vIds) { // la aggiungo alla curva composta - if ( ! pCrvCompo->AddCurve( vpCurve[i-1], true, 5 * EPS_SMALL)) + if ( ! pCrvCompo->AddCurve( vpCurve[i-1], true, dToler)) return false ; vpCurve[i-1] = nullptr ; } // aggiorno il nuovo punto vicino if ( pCrvCompo->GetCurveCount() > 0) pCrvCompo->GetEndPoint( ptNearStart) ; + // se lunghezza curva inferiore a 2 volte la tolleranza, la salto + double dCrvLen ; + if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 2. * dToler) + continue ; + // se curva chiusa entro 2 volte la tolleranza ma considerata aperta, la chiudo bene + Point3d ptStart, ptEnd ; + if ( pCrvCompo->GetStartPoint( ptStart) && + pCrvCompo->GetEndPoint( ptEnd) && + AreSamePointEpsilon( ptStart, ptEnd, 2. * dToler) && + ! AreSamePointApprox( ptStart, ptEnd)) { + // porto il punto finale a coincidere esattamente con l'inizio + pCrvCompo->ModifyEnd( ptStart) ; + } // compatto la nuova curva pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; // inserisco la curva composita nel gruppo destinazione