diff --git a/Angle.cpp b/Angle.cpp new file mode 100644 index 0000000..fbfa46e --- /dev/null +++ b/Angle.cpp @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : Angle.cpp Data : 14.07.14 Versione : 1.5g2 +// Contenuto : Implementazione funzioni per gestione angoli. +// +// +// +// Modifiche : 14.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "/EgtDev/Include/EGkAngle.h" +#include "/EgtDev/Include/EGkGeoConst.h" + + +//---------------------------------------------------------------------------- +double +AngleNearAngle( double dAngDeg, double dAngRefDeg) +{ + // devo portare l'angolo entro +/- un angolo piatto dal riferimento + while ( dAngDeg > dAngRefDeg + ANG_STRAIGHT + EPS_ANG_ZERO) + dAngDeg -= ANG_FULL ; + while ( dAngDeg < dAngRefDeg - ANG_STRAIGHT - EPS_ANG_ZERO) + dAngDeg += ANG_FULL ; + return dAngDeg ; +} + +//---------------------------------------------------------------------------- +double +DiffAngle( double dAng1Deg, double dAng2Deg) +{ + double dAng1Near2Deg = AngleNearAngle( dAng1Deg, dAng2Deg) ; + + return ( dAng1Near2Deg - dAng2Deg) ; +} + +//---------------------------------------------------------------------------- +double +MediaAngle( double dAng1Deg, double dAng2Deg, double dCoeff) +{ + double dAng1Near2Deg = AngleNearAngle( dAng1Deg, dAng2Deg) ; + + return ( dAng1Near2Deg * ( 1 - dCoeff) + dAng2Deg * dCoeff) ; +} diff --git a/CurveArc.cpp b/CurveArc.cpp index b2791c8..aed804a 100644 --- a/CurveArc.cpp +++ b/CurveArc.cpp @@ -20,6 +20,7 @@ #include "GeoObjFactory.h" #include "NgeWriter.h" #include "NgeReader.h" +#include "/EgtDev/Include/EGkAngle.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include @@ -1255,6 +1256,53 @@ CurveArc::InvertN( void) return true ; } +//---------------------------------------------------------------------------- +bool +CurveArc::CalcPointAngle( const Point3d& ptP, double& dAngDeg) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // posizione angolare del punto rispetto al centro a partire dalla direzione start + bool bDet ; + if ( ! m_VtS.GetRotation( ( ptP - m_PtCen), m_VtN, dAngDeg, bDet) || ! bDet) + return false ; + if ( m_dAngCenDeg > 0 && dAngDeg < - EPS_ANG_ZERO) + dAngDeg += ANG_FULL ; + else if ( m_dAngCenDeg < 0 && dAngDeg > EPS_ANG_ZERO) + dAngDeg -= ANG_FULL ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveArc::CalcPointParamPosiz( const Point3d& ptP, double& dU, int& nPos) const +{ + // calcolo la posizione angolare + double dAngDeg ; + if ( ! CalcPointAngle( ptP, dAngDeg)) + return false ; + // calcolo parametro + dU = dAngDeg / m_dAngCenDeg ; + // verifica posizione punto su arco + nPos = PP_NULL ; // fuori + if ( fabs( DiffAngle( dAngDeg, 0) * DEGTORAD * m_dRad) < EPS_SMALL) { + nPos = PP_START ; // vicino a inizio + dU = AngleNearAngle( dAngDeg, 0) / m_dAngCenDeg ; + dU = max( dU, 0.) ; + } + else if ( fabs( DiffAngle( dAngDeg, m_dAngCenDeg) * DEGTORAD * m_dRad) < EPS_SMALL) { + nPos = PP_END ; // vicino a fine + dU = AngleNearAngle( dAngDeg, m_dAngCenDeg) / m_dAngCenDeg ; + dU = min( dU, 1.) ; + } + else if ( dU > 0 && dU < 1) + nPos = PP_MID ; // nell'interno + return true ; +} + //---------------------------------------------------------------------------- bool CurveArc::ChangeRadius( double dNewRadius) diff --git a/CurveArc.h b/CurveArc.h index 1c3ca0a..38bbe01 100644 --- a/CurveArc.h +++ b/CurveArc.h @@ -124,6 +124,8 @@ class CurveArc : public ICurveArc, public IGeoObjRW { return m_dAngCenDeg ; } virtual double GetDeltaN( void) const { return m_dDeltaN ; } + virtual bool CalcPointAngle( const Point3d& ptP, double& dAngDeg) const ; + virtual bool CalcPointParamPosiz( const Point3d& ptP, double& dU, int& nPos) const ; virtual bool InvertN( void) ; virtual bool ChangeRadius( double dNewRadius) ; virtual bool ChangeDeltaN( double dNewDeltaN) ; diff --git a/CurveLine.cpp b/CurveLine.cpp index 314d1c9..ffeda3a 100644 --- a/CurveLine.cpp +++ b/CurveLine.cpp @@ -726,3 +726,30 @@ CurveLine::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) return ( m_PtStart.ToGlob( frOri) && m_PtStart.ToLoc( frDest) && m_PtEnd.ToGlob( frOri) && m_PtEnd.ToLoc( frDest)) ; } + +//---------------------------------------------------------------------------- +bool +CurveLine::CalcPointParamPosiz( const Point3d& ptP, bool bOnXY, double& dU, int& nPos) const +{ + // vettore linea nel piano XY + Vector3d vtDir = m_PtEnd - m_PtStart ; + if ( bOnXY) + vtDir.z = 0 ; + if ( vtDir.IsSmall()) + return false ; + // calcolo parametro + dU = ( ptP - m_PtStart) * vtDir / vtDir.SqLen() ; + // verifica posizione intersezione su linea + nPos = ICurve::PP_NULL ; // fuori + if ( ( dU * vtDir).IsSmall()) { + nPos = ICurve::PP_START ; // vicino a inizio + dU = max( dU, 0.) ; + } + else if ( (( 1 - dU) * vtDir).IsSmall()) { + nPos = ICurve::PP_END ; // vicino a fine + dU = min( dU, 1.) ; + } + else if ( dU > 0 && dU < 1) + nPos = ICurve::PP_MID ; // nell'interno + return true ; +} diff --git a/CurveLine.h b/CurveLine.h index bb65be0..08ba074 100644 --- a/CurveLine.h +++ b/CurveLine.h @@ -103,6 +103,7 @@ class CurveLine : public ICurveLine, public IGeoObjRW { return m_PtStart ; } virtual const Point3d& GetEnd( void) const { return m_PtEnd ; } + virtual bool CalcPointParamPosiz( const Point3d& ptP, bool bOnXY, double& dU, int& nPos) const ; public : // IGeoObjRW virtual int GetNgeId( void) const ; diff --git a/DistPointArc.cpp b/DistPointArc.cpp index d1bc149..00c786d 100644 --- a/DistPointArc.cpp +++ b/DistPointArc.cpp @@ -44,44 +44,28 @@ DistPointArc::DistPointArc( const Point3d& ptP, const ICurveArc& arArc) void DistPointArc::DistPointCircle( const Point3d& ptP, const ICurveArc& arArc) { - // vettori ausiliari - Vector3d vtDiff = ptP - arArc.GetCenter() ; - double dDistN = vtDiff * arArc.GetNormVersor() ; - Vector3d vtDiffPlane = vtDiff - dDistN * arArc.GetNormVersor() ; - double dDistPlane = fabs( vtDiffPlane.Len() - arArc.GetRadius()) ; - // calcolo della distanza - if ( fabs( dDistPlane) > EPS_ZERO && fabs( dDistN) > EPS_ZERO) - m_dDist = sqrt( dDistPlane * dDistPlane + dDistN * dDistN) ; - else if ( fabs( dDistPlane) > EPS_ZERO) - m_dDist = dDistPlane ; - else if ( fabs( dDistN) > EPS_ZERO) - m_dDist = fabs( dDistN) ; - else - m_dDist = 0 ; - // calcolo del parametro del punto a minima distanza - if ( vtDiffPlane.Normalize()) { - bool bDet ; - double dAngDeg ; - double dParam ; - Point3d ptMinDist ; - arArc.GetStartVersor().GetRotation( vtDiffPlane, arArc.GetNormVersor(), dAngDeg, bDet) ; - if ( arArc.GetAngCenter() > 0 && dAngDeg < 0) - dAngDeg += 360 ; - else if ( arArc.GetAngCenter() < 0 && dAngDeg > 0) - dAngDeg -= 360 ; - dParam = dAngDeg / arArc.GetAngCenter() ; + // se il punto non sta sul centro dell'arco, posso calcolarne la posizione angolare + double dAngDeg ; + if ( arArc.CalcPointAngle( ptP, dAngDeg)) { + double dParam = dAngDeg / arArc.GetAngCenter() ; if ( dParam < 0) dParam = 0 ; else if ( dParam > 1) dParam = 1 ; // calcolo del punto di minima distanza + Point3d ptMinDist ; arArc.GetPointD1D2( dParam, ICurve::FROM_MINUS, ptMinDist) ; + // calcolo del valore di minima distanza + m_dDist = Dist( ptP, ptMinDist) ; // salvo i dati m_Info.push_back( MinDistPCInfo( MDPCI_NORMAL, dParam, ptMinDist)) ; } + // altrimenti tutti i punti della circonferenza sono a minima distanza else { + // calcolo del valore di minima distanza + m_dDist = sqrt( SqDist( ptP, arArc.GetCenter()) + arArc.GetRadius() * arArc.GetRadius()) ; + // salvo iniziale e finale, come estremi del range Point3d ptMinDist ; - // tutti i punti della circonferenza sono a minima distanza salvo iniziale e finale arArc.GetStartPoint( ptMinDist) ; m_Info.push_back( MinDistPCInfo( MDPCI_START_CONT, 0, ptMinDist)) ; arArc.GetEndPoint( ptMinDist) ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 7440484..8c590d7 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 37b4b46..2acca5f 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -227,6 +227,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -258,8 +259,10 @@ copy $(TargetPath) \EgtProg\Dll64 + + @@ -287,6 +290,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -363,7 +367,9 @@ copy $(TargetPath) \EgtProg\Dll64 + + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 9fe9e08..6d1c200 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -198,6 +198,15 @@ File di origine\GeoInters + + File di origine\GeoInters + + + File di origine\GeoInters + + + File di origine\Base + @@ -485,6 +494,15 @@ File di intestazione + + File di intestazione + + + File di intestazione + + + File di intestazione + diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index a21b916..aabc7bf 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -1831,8 +1831,8 @@ GdbExecutor::CurveCompoAddCurve( const STRVECTOR& vsParams, bool bEndOrStart) bool GdbExecutor::CurveCompoExtractCurve( const STRVECTOR& vsParams, bool bEndOrStart) { - // 3 parametri : IdSou, IdDest, IdParent - if ( vsParams.size() != 3) + // 1 o 3 parametri : IdSou[, IdDest, IdParent] + if ( vsParams.size() != 1 && vsParams.size() != 3) return false ; // recupero la curva composita e il suo riferimento int nIdCCompo = GetIdParam( vsParams[0]) ; @@ -1843,7 +1843,10 @@ GdbExecutor::CurveCompoExtractCurve( const STRVECTOR& vsParams, bool bEndOrStart if ( ! m_pGDB->GetGlobFrame( nIdCCompo, frSou)) return false ; // estraggo la opportuna entità - ICurve* pCrv = pCrvCompo->RemoveFirstOrLastCurve( bEndOrStart) ; + PtrOwner pCrv( pCrvCompo->RemoveFirstOrLastCurve( bEndOrStart)) ; + // se 1 solo parametro -> cancellazione + if ( vsParams.size() == 1) + return true ; // recupero il riferimento del gruppo destinazione Frame3d frDest ; if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[2]), frDest)) @@ -1852,7 +1855,7 @@ GdbExecutor::CurveCompoExtractCurve( const STRVECTOR& vsParams, bool bEndOrStart if ( ! AreSameFrame( frSou, frDest)) pCrv->LocToLoc( frSou, frDest) ; // inserisco la curva estratta nel DB - return AddGeoObj( vsParams[1], vsParams[2], pCrv) ; + return AddGeoObj( vsParams[1], vsParams[2], ::Release( pCrv)) ; } //---------------------------------------------------------------------------- @@ -3162,6 +3165,13 @@ GdbExecutor::GetPointWParam( const string& sParam, const Frame3d& frPnt, Point3d FromString( vsParams[2], ptP.z) && FromString( vsParams[3], dW)) ; } + // se 3 parti, sono 2 coordinate e un peso + else if ( vsParams.size() == 3) { + ptP.z = 0 ; + return ( FromString( vsParams[0], ptP.x) && + FromString( vsParams[1], ptP.y) && + FromString( vsParams[2], dW)) ; + } // se 2 parti, nome di punto predefinito, punto notevole o già nel DB e un peso else if ( vsParams.size() == 2) { // recupero il punto @@ -4594,12 +4604,12 @@ GdbExecutor::SplitCurveByClass( const STRVECTOR& vsParams) if ( nIdGrp[nGrp] < GDB_ID_ROOT) continue ; // se curva praticamente nulla, vado oltre - if ( fabs( ccClass[i].dParS - ccClass[i].dParE) < 10 * EPS_PARAM) + if ( fabs( ccClass[i].dParE - ccClass[i].dParS) < 10 * EPS_PARAM) continue ; // copio la parte di curva che interessa e la porto nel riferimento del gruppo PtrOwner pSplit( pCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ; if ( ! ::IsValid( pSplit)) - return false ; + continue ; pSplit->LocToLoc( frCrv, frGrp[nGrp]) ; // la inserisco nel gruppo if ( m_pGDB->AddGeoObj( GDB_ID_NULL, nIdGrp[nGrp], ::Release( pSplit)) == GDB_ID_NULL) diff --git a/IntersArcArc.cpp b/IntersArcArc.cpp new file mode 100644 index 0000000..229be2b --- /dev/null +++ b/IntersArcArc.cpp @@ -0,0 +1,534 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : IntersArcArc.cpp Data : 10.07.14 Versione : 1.5g2 +// Contenuto : Implementazione della classe intersezione arco/arco. +// +// +// +// Modifiche : 10.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "IntersArcArc.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +IntersArcArc::IntersArcArc( const ICurveArc& Arc1, const ICurveArc& Arc2) +{ + // Le intersezioni sono calcolate nel piano XY locale. + + // nessuna intersezione trovata + m_bOverlaps = false ; + m_nNumInters = 0 ; + + // verifico validità archi + if ( ! Arc1.IsValid() || ! Arc2.IsValid()) + return ; + // verifico che l'angolo al centro non superi il giro + if ( fabs( Arc1.GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO || + fabs( Arc2.GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) + return ; + // ne faccio una copia + m_Arc1.CopyFrom( &Arc1) ; + m_Arc2.CopyFrom( &Arc2) ; + // gli archi devono avere il piano coincidente con XY + if ( ! m_Arc1.GetNormVersor().IsZplus() && ! m_Arc1.GetNormVersor().IsZminus()) + return ; + if ( ! m_Arc2.GetNormVersor().IsZplus() && ! m_Arc2.GetNormVersor().IsZminus()) + return ; + // !!! Gestire gli archi proiettati come ellissi + + // verifico sovrapposizione box + BBox3d boxArc1 ; + if ( ! m_Arc1.GetLocalBBox( boxArc1)) + return ; + BBox3d boxArc2 ; + if ( ! m_Arc2.GetLocalBBox( boxArc2)) + return ; + if ( ! boxArc1.OverlapsXY( boxArc2)) + return ; + + // versore e distanza tra i centri + Vector3d vtDir = ( m_Arc2.GetCenter() - m_Arc1.GetCenter()) ; + vtDir.z = 0 ; + double dDist = vtDir.LenXY() ; + vtDir /= dDist ; + + // cerchi esterni -> nessuna intersezione + if ( dDist > m_Arc1.GetRadius() + m_Arc2.GetRadius() + EPS_SMALL) + return ; + + // cerchi interni -> nessuna intersezione + if ( dDist < fabs( m_Arc1.GetRadius() - m_Arc2.GetRadius()) - EPS_SMALL) + return ; + + // cerchi coincidenti -> sovrapposizioni e/o intersezioni agli estremi + if ( dDist < EPS_SMALL && fabs( m_Arc1.GetRadius() - m_Arc2.GetRadius()) < EPS_SMALL) { + // coefficiente da parametro dell'arco 1 a lunghezza + double dU2L = fabs( m_Arc1.GetAngCenter()) * DEGTORAD * m_Arc1.GetRadius() ; + // determino se sono equiversi o controversi + bool bEqVers = (( m_Arc1.GetAngCenter() * m_Arc1.GetNormVersor().z * + m_Arc2.GetAngCenter() * m_Arc2.GetNormVersor().z) > 0) ; + // calcolo degli estremi degli archi + Point3d ptS1, ptE1 ; + if ( ! m_Arc1.GetStartPoint( ptS1) || ! m_Arc1.GetEndPoint( ptE1)) + return ; + Point3d ptS2, ptE2 ; + if ( ! m_Arc2.GetStartPoint( ptS2) || ! m_Arc2.GetEndPoint( ptE2)) + return ; + // calcolo del parametro di inizio dell'arco 2 nel riferimento dell'arco 1 + double dUS2 ; + int nPosS2 ; + if ( ! m_Arc1.CalcPointParamPosiz( ptS2, dUS2, nPosS2)) + return ; + // calcolo dell'ampiezza parametrica dell'arco 2 nel riferimento dell'arco 1 + double dDeltaU2 = fabs( m_Arc2.GetAngCenter() / m_Arc1.GetAngCenter()) * ( bEqVers ? 1 : -1) ; + // calcolo dell'ampiezza parametrica di un giro nel riferimento dell'arco 1 + double dTurnU = fabs( ANG_FULL / m_Arc1.GetAngCenter()) ; + // determinazione del minimo e massimo parametro dell'arco 2 nel riferimento dell'arco 1 + double dU2min = dUS2 ; + double dU2max = dUS2 + dDeltaU2 ; + if ( dU2min > dU2max) + swap( dU2min, dU2max) ; + // se il minimo è negativo, aggiungo un giro + if ( dU2min * dU2L < - EPS_SMALL) { + dU2min += dTurnU ; + dU2max += dTurnU ; + } + // se il minimo di 2 coincide con il massimo di 1 nel primo giro -> un punto estremo + if ( fabs( 1 - dU2min) * dU2L < EPS_SMALL) { + m_Info[0].IciA[0].dU = 1 ; + m_Info[0].IciB[0].dU = ( bEqVers ? 0 : 1) ; + m_Info[0].IciA[0].ptI = ptE1 ; + m_Info[0].IciB[0].ptI = ( bEqVers ? ptS2 : ptE2) ; + m_Info[0].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciA[0].nNextTy = ICCT_NULL ; + m_Info[0].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciB[0].nNextTy = ICCT_NULL ; + m_Info[0].bOverlap = false ; + m_nNumInters = 1 ; + } + // se invece è minore -> una sovrapposizione + else if ( dU2min < 1) { + // inizio dell'intervallo + m_Info[0].IciA[0].dU = dU2min ; + m_Info[0].IciB[0].dU = ( bEqVers ? 0 : 1) ; + m_Arc1.GetPointD1D2( m_Info[0].IciA[0].dU, ICurve::FROM_MINUS, m_Info[0].IciA[0].ptI) ; + m_Info[0].IciB[0].ptI = ( bEqVers ? ptS2 : ptE2) ; + m_Info[0].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciA[0].nNextTy = ICCT_ON ; + if ( bEqVers) { + m_Info[0].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciB[0].nNextTy = ICCT_ON ; + } + else { + m_Info[0].IciB[0].nPrevTy = ICCT_ON ; + m_Info[0].IciB[0].nNextTy = ICCT_NULL ; + } + // fine dell'intervallo + if ( dU2max < 1) { + m_Info[0].IciA[1].dU = dU2max ; + m_Info[0].IciB[1].dU = ( bEqVers ? 1 : 0) ; + } + else { + m_Info[0].IciA[1].dU = 1 ; + int nPos ; + m_Arc2.CalcPointParamPosiz( ptE1, m_Info[0].IciB[1].dU, nPos) ; + } + m_Arc1.GetPointD1D2( m_Info[0].IciA[1].dU, ICurve::FROM_MINUS, m_Info[0].IciA[1].ptI) ; + m_Arc2.GetPointD1D2( m_Info[0].IciB[1].dU, ICurve::FROM_MINUS, m_Info[0].IciB[1].ptI) ; + m_Info[0].IciA[1].nPrevTy = ICCT_ON ; + m_Info[0].IciA[1].nNextTy = ICCT_NULL ; + if ( bEqVers) { + m_Info[0].IciB[1].nPrevTy = ICCT_ON ; + m_Info[0].IciB[1].nNextTy = ICCT_NULL ; + } + else { + m_Info[0].IciB[1].nPrevTy = ICCT_NULL ; + m_Info[0].IciB[1].nNextTy = ICCT_ON ; + } + // dati generali + m_Info[0].bOverlap = true ; + m_Info[0].bCBOverEq = bEqVers ; + m_bOverlaps = true ; + m_nNumInters = 1 ; + } + // se il massimo di 2 coincide con il minimo di 1 nel secondo giro e 1 non completo -> un punto estremo + if ( fabs( dTurnU - dU2max) * dU2L < EPS_SMALL && dTurnU < 1 - EPS_PARAM) { + m_Info[m_nNumInters].IciA[0].dU = 0 ; + m_Info[m_nNumInters].IciB[0].dU = ( bEqVers ? 1 : 0) ; + m_Info[m_nNumInters].IciA[0].ptI = ptS1 ; + m_Info[m_nNumInters].IciB[0].ptI = ( bEqVers ? ptE2 : ptS2) ; + m_Info[m_nNumInters].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[m_nNumInters].IciA[0].nNextTy = ICCT_NULL ; + m_Info[m_nNumInters].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[m_nNumInters].IciB[0].nNextTy = ICCT_NULL ; + m_Info[m_nNumInters].bOverlap = false ; + ++ m_nNumInters ; + } + // se invece è maggiore -> una sovrapposizione + else if ( dU2max > dTurnU) { + // inizio dell'intervallo + m_Info[m_nNumInters].IciA[0].dU = 0 ; + int nPos ; + m_Arc2.CalcPointParamPosiz( ptS1, m_Info[m_nNumInters].IciB[0].dU, nPos) ; + m_Info[m_nNumInters].IciA[0].ptI = ptS1 ; + m_Arc2.GetPointD1D2( m_Info[m_nNumInters].IciB[0].dU, ICurve::FROM_MINUS, m_Info[m_nNumInters].IciB[0].ptI) ; + m_Info[m_nNumInters].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[m_nNumInters].IciA[0].nNextTy = ICCT_ON ; + if ( bEqVers) { + m_Info[m_nNumInters].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[m_nNumInters].IciB[0].nNextTy = ICCT_ON ; + } + else { + m_Info[m_nNumInters].IciB[0].nPrevTy = ICCT_ON ; + m_Info[m_nNumInters].IciB[0].nNextTy = ICCT_NULL ; + } + // fine dell'intervallo + if ( dU2max - dTurnU < 1) { + m_Info[m_nNumInters].IciA[1].dU = dU2max - dTurnU ; + m_Info[m_nNumInters].IciB[1].dU = ( bEqVers ? 1 : 0) ; + } + else { + m_Info[m_nNumInters].IciA[1].dU = 1 ; + int nPos ; + m_Arc2.CalcPointParamPosiz( ptE1, m_Info[m_nNumInters].IciB[1].dU, nPos) ; + } + m_Arc1.GetPointD1D2( m_Info[m_nNumInters].IciA[1].dU, ICurve::FROM_MINUS, m_Info[m_nNumInters].IciA[1].ptI) ; + m_Arc2.GetPointD1D2( m_Info[m_nNumInters].IciB[1].dU, ICurve::FROM_MINUS, m_Info[m_nNumInters].IciB[1].ptI) ; + m_Info[m_nNumInters].IciA[1].nPrevTy = ICCT_ON ; + m_Info[m_nNumInters].IciA[1].nNextTy = ICCT_NULL ; + if ( bEqVers) { + m_Info[m_nNumInters].IciB[1].nPrevTy = ICCT_ON ; + m_Info[m_nNumInters].IciB[1].nNextTy = ICCT_NULL ; + } + else { + m_Info[m_nNumInters].IciB[1].nPrevTy = ICCT_NULL ; + m_Info[m_nNumInters].IciB[1].nNextTy = ICCT_ON ; + } + // dati generali + m_Info[m_nNumInters].bOverlap = true ; + m_Info[m_nNumInters].bCBOverEq = bEqVers ; + m_bOverlaps = true ; + ++ m_nNumInters ; + } + // se due intersezioni, le ordino in senso crescente del parametro U della prima curva + if ( m_nNumInters == 2) { + if ( m_Info[0].IciA[0].dU > m_Info[1].IciA[0].dU) + swap( m_Info[0], m_Info[1]) ; + } + return ; + } + + // cerchi tangenti esterni -> una intersezione + if ( fabs( dDist - ( m_Arc1.GetRadius() + m_Arc2.GetRadius())) < EPS_SMALL) { + // calcolo il punto di intersezione + Point3d ptInt = m_Arc1.GetCenter() + vtDir * m_Arc1.GetRadius() ; + // posizione parametrica dell'intersezione sul primo arco + int nPos1 ; + if ( ! m_Arc1.CalcPointParamPosiz( ptInt, m_Info[0].IciA[0].dU, nPos1)) + return ; + // posizione parametrica dell'intersezione sul secondo arco + int nPos2 ; + if ( ! m_Arc2.CalcPointParamPosiz( ptInt, m_Info[0].IciB[0].dU, nPos2)) + return ; + // se soluzione non accettata, esco + if ( nPos1 == ICurve::PP_NULL || nPos2 == ICurve::PP_NULL) + return ; + // calcolo i punti sui due archi (possono differire in Z) + m_Arc1.GetPointD1D2( m_Info[0].IciA[0].dU, ICurve::FROM_MINUS, m_Info[0].IciA[0].ptI) ; + m_Arc2.GetPointD1D2( m_Info[0].IciB[0].dU, ICurve::FROM_MINUS, m_Info[0].IciB[0].ptI) ; + // calcolo dati ausiliari + bool bCCW1 = (( m_Arc1.GetAngCenter() > 0 && m_Arc1.GetNormVersor().IsZplus()) || + ( m_Arc1.GetAngCenter() < 0 && m_Arc1.GetNormVersor().IsZminus())) ; + bool bCCW2 = (( m_Arc2.GetAngCenter() > 0 && m_Arc2.GetNormVersor().IsZplus()) || + ( m_Arc2.GetAngCenter() < 0 && m_Arc2.GetNormVersor().IsZminus())) ; + // calcolo tipo di intersezione + m_Info[0].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciA[0].nNextTy = ICCT_NULL ; + m_Info[0].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciB[0].nNextTy = ICCT_NULL ; + // si incontrano alle estremità, non si può dire alcunché + if ( ( nPos1 == ICurve::PP_START || nPos1 == ICurve::PP_END) && + ( nPos2 == ICurve::PP_START || nPos2 == ICurve::PP_END)) { + ; // rimangono tutti NULL + } + // l'inizio di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_START) { + if ( bCCW2) + m_Info[0].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[0].IciA[0].nNextTy = ICCT_IN ; // NULL + IN + // curva 2 NULL + NULL + } + // la fine di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_END) { + if ( bCCW2) + m_Info[0].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[0].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL + // curva 2 NULL + NULL + } + // l'inizio di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_START) { + // curva 1 NULL + NULL + if ( bCCW1) + m_Info[0].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[0].IciB[0].nNextTy = ICCT_IN ; // NULL + IN + } + // la fine di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_END) { + // curva 1 NULL + NULL + if ( bCCW1) + m_Info[0].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[0].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL + } + // si intersecano nel mezzo + else { + if ( bCCW2) { + m_Info[0].IciA[0].nPrevTy = ICCT_OUT ; // OUT + OUT + m_Info[0].IciA[0].nNextTy = ICCT_OUT ; + } + else { + m_Info[0].IciA[0].nPrevTy = ICCT_IN ; // IN + IN + m_Info[0].IciA[0].nNextTy = ICCT_IN ; + } + if ( bCCW1) { + m_Info[0].IciB[0].nPrevTy = ICCT_OUT ; // OUT + OUT + m_Info[0].IciB[0].nNextTy = ICCT_OUT ; + } + else { + m_Info[0].IciB[0].nPrevTy = ICCT_IN ; // IN + IN + m_Info[0].IciB[0].nNextTy = ICCT_IN ; + } + } + // aggiorno dati generali di intersezione + m_Info[0].bOverlap = false ; + m_nNumInters = 1 ; + return ; + } + + // cerchi tangenti interni -> una intersezione + if ( fabs( dDist - fabs( m_Arc1.GetRadius() - m_Arc2.GetRadius())) < EPS_SMALL) { + // determino quale dei due contiene l'altro + bool bBiggest1 = ( m_Arc1.GetRadius() > m_Arc2.GetRadius()) ; + // calcolo il punto di intersezione + Point3d ptInt = m_Arc1.GetCenter() + ( bBiggest1 ? vtDir : - vtDir) * m_Arc1.GetRadius() ; + // posizione parametrica dell'intersezione sul primo arco + int nPos1 ; + if ( ! m_Arc1.CalcPointParamPosiz( ptInt, m_Info[0].IciA[0].dU, nPos1)) + return ; + // posizione parametrica dell'intersezione sul secondo arco + int nPos2 ; + if ( ! m_Arc2.CalcPointParamPosiz( ptInt, m_Info[0].IciB[0].dU, nPos2)) + return ; + // se soluzione non accettata, esco + if ( nPos1 == ICurve::PP_NULL || nPos2 == ICurve::PP_NULL) + return ; + // calcolo i punti sui due archi (possono differire in Z) + m_Arc1.GetPointD1D2( m_Info[0].IciA[0].dU, ICurve::FROM_MINUS, m_Info[0].IciA[0].ptI) ; + m_Arc2.GetPointD1D2( m_Info[0].IciB[0].dU, ICurve::FROM_MINUS, m_Info[0].IciB[0].ptI) ; + // calcolo dati ausiliari + bool bCCW1 = (( m_Arc1.GetAngCenter() > 0 && m_Arc1.GetNormVersor().IsZplus()) || + ( m_Arc1.GetAngCenter() < 0 && m_Arc1.GetNormVersor().IsZminus())) ; + bool bCCW2 = (( m_Arc2.GetAngCenter() > 0 && m_Arc2.GetNormVersor().IsZplus()) || + ( m_Arc2.GetAngCenter() < 0 && m_Arc2.GetNormVersor().IsZminus())) ; + // calcolo tipo di intersezione + m_Info[0].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciA[0].nNextTy = ICCT_NULL ; + m_Info[0].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[0].IciB[0].nNextTy = ICCT_NULL ; + // si incontrano alle estremità, non si può dire alcunché + if ( ( nPos1 == ICurve::PP_START || nPos1 == ICurve::PP_END) && + ( nPos2 == ICurve::PP_START || nPos2 == ICurve::PP_END)) { + ; // rimangono tutti NULL + } + // l'inizio di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_START) { + if ( ( bBiggest1 && bCCW2) || ( ! bBiggest1 && ! bCCW2)) + m_Info[0].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[0].IciA[0].nNextTy = ICCT_IN ; // NULL + IN + // curva 2 NULL + NULL + } + // la fine di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_END) { + if ( ( bBiggest1 && bCCW2) || ( ! bBiggest1 && ! bCCW2)) + m_Info[0].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[0].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL + // curva 2 NULL + NULL + } + // l'inizio di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_START) { + // curva 1 NULL + NULL + if ( ( bBiggest1 && ! bCCW1) || ( ! bBiggest1 && bCCW1)) + m_Info[0].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[0].IciB[0].nNextTy = ICCT_IN ; // NULL + IN + } + // la fine di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_END) { + // curva 1 NULL + NULL + if ( ( bBiggest1 && ! bCCW1) || ( ! bBiggest1 && bCCW1)) + m_Info[0].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[0].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL + } + // si intersecano nel mezzo + else { + if ( ( bBiggest1 && bCCW2) || ( ! bBiggest1 && ! bCCW2)) { + m_Info[0].IciA[0].nPrevTy = ICCT_OUT ; // OUT + OUT + m_Info[0].IciA[0].nNextTy = ICCT_OUT ; + } + else { + m_Info[0].IciA[0].nPrevTy = ICCT_IN ; // IN + IN + m_Info[0].IciA[0].nNextTy = ICCT_IN ; + } + if ( ( bBiggest1 && ! bCCW1) || ( ! bBiggest1 && bCCW1)) { + m_Info[0].IciB[0].nPrevTy = ICCT_OUT ; // OUT + OUT + m_Info[0].IciB[0].nNextTy = ICCT_OUT ; + } + else { + m_Info[0].IciB[0].nPrevTy = ICCT_IN ; // IN + IN + m_Info[0].IciB[0].nNextTy = ICCT_IN ; + } + } + // aggiorno dati generali di intersezione + m_Info[0].bOverlap = false ; + m_nNumInters = 1 ; + return ; + } + + // due intersezioni + double dA = ( m_Arc1.GetRadius() * m_Arc1.GetRadius() - m_Arc2.GetRadius() * m_Arc2.GetRadius() + + dDist * dDist) / ( 2 * dDist) ; + double dH = sqrt( m_Arc1.GetRadius() * m_Arc1.GetRadius() - dA * dA) ; + Point3d ptRef = m_Arc1.GetCenter() + dA * vtDir ; + Vector3d vtDelta = dH * vtDir ; + vtDelta.Rotate( Z_AX, 0, 1) ; + int nPos1, nPos2 ; + // ---> prima intersezione + // determinazione geometrica e topologica dell'intersezione tra le due curve + if ( CalcSecIntersGeomData( 0, ptRef + vtDelta, nPos1, nPos2) && + CalcSecIntersTopolData( 0, nPos1, nPos2)) { + // aggiorno dati generali di intersezione + m_Info[0].bOverlap = false ; + ++ m_nNumInters ; + } + // ---> seconda intersezione + // determinazione geometrica e topologica dell'intersezione tra le due curve + if ( CalcSecIntersGeomData( m_nNumInters, ptRef - vtDelta, nPos1, nPos2) && + CalcSecIntersTopolData( m_nNumInters, nPos1, nPos2)) { + // aggiorno dati generali di intersezione + m_Info[m_nNumInters].bOverlap = false ; + ++ m_nNumInters ; + } + // se due intersezioni, le ordino in senso crescente del parametro U della prima curva + if ( m_nNumInters == 2) { + if ( m_Info[0].IciA[0].dU > m_Info[1].IciA[0].dU) + swap( m_Info[0], m_Info[1]) ; + } +} + +//---------------------------------------------------------------------------- +bool +IntersArcArc::CalcSecIntersGeomData( int nInt, const Point3d& ptInt, int& nPos1, int& nPos2) +{ + // posizione parametrica dell'intersezione sul primo arco + if ( ! m_Arc1.CalcPointParamPosiz( ptInt, m_Info[nInt].IciA[0].dU, nPos1)) + return false ; + // posizione parametrica dell'intersezione sul secondo arco + if ( ! m_Arc2.CalcPointParamPosiz( ptInt, m_Info[nInt].IciB[0].dU, nPos2)) + return false ; + // se soluzione non accettata, esco + if ( nPos1 == ICurve::PP_NULL || nPos2 == ICurve::PP_NULL) + return false ; + // calcolo i punti sulle due curve (possono differire in Z) + m_Arc1.GetPointD1D2( m_Info[nInt].IciA[0].dU, ICurve::FROM_MINUS, m_Info[nInt].IciA[0].ptI) ; + m_Arc2.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, m_Info[nInt].IciB[0].ptI) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +IntersArcArc::CalcSecIntersTopolData( int nInt, int nPos1, int nPos2) +{ + // calcolo dati ausiliari + Point3d ptInt1, ptInt2 ; + Vector3d vtDir1, vtDir2 ; + m_Arc1.GetPointD1D2( m_Info[nInt].IciA[0].dU, ICurve::FROM_MINUS, ptInt1, &vtDir1) ; + m_Arc2.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, ptInt2, &vtDir2) ; + double dCrossXY = CrossXY( vtDir1, vtDir2) ; + // calcolo tipo di intersezione + m_Info[nInt].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciA[0].nNextTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nNextTy = ICCT_NULL ; + // si incontrano alle estremità, non si può dire alcunché + if ( ( nPos1 == ICurve::PP_START || nPos1 == ICurve::PP_END) && + ( nPos2 == ICurve::PP_START || nPos2 == ICurve::PP_END)) { + ; // rimangono tutti NULL + } + // l'inizio di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_START) { + if ( dCrossXY > 0) + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; // NULL + IN + // curva 2 NULL + NULL + } + // la fine di 1 interseca il mezzo di 2 + else if ( nPos1 == ICurve::PP_END) { + if ( dCrossXY < 0) + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL + // curva 2 NULL + NULL + } + // l'inizio di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_START) { + // curva 1 NULL + NULL + if ( - dCrossXY > 0) + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; // NULL + IN + } + // la fine di 2 interseca il mezzo di 1 + else if ( nPos2 == ICurve::PP_END) { + // curva 1 NULL + NULL + if ( - dCrossXY < 0) + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL + } + // si intersecano nel mezzo + else { + if ( CrossXY( ( ( ptInt1 - vtDir1) - ( ptInt2 - vtDir2)), vtDir2) > 0) { + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; + } + else { + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; + } + if ( CrossXY( ( ( ptInt2 - vtDir2) - ( ptInt1 - vtDir1)), vtDir1) > 0) { + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; + } + else { + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; + } + } + + return true ; +} diff --git a/IntersArcArc.h b/IntersArcArc.h new file mode 100644 index 0000000..4a1d731 --- /dev/null +++ b/IntersArcArc.h @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : IntersArcArc.h Data : 10.07.14 Versione : 1.5g2 +// Contenuto : Dichiarazione della classe intersezione arco/arco. +// +// +// +// Modifiche : 10.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkIntersCurveCurve.h" +#include "CurveArc.h" + + +//----------------------------------------------------------------------------- +class IntersArcArc +{ + friend class IntersCurveCurve ; + + public : + IntersArcArc( const ICurveArc& Arc1, const ICurveArc& Arc2) ; + + public : + bool GetOverlaps( void) + { return false ; } + int GetNumInters( void) + { return m_nNumInters ; } + bool GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) + { if ( nInd < 0 || nInd >= m_nNumInters) + return false ; + aInfo = m_Info[nInd] ; + return true ; } + + private : + IntersArcArc( void) ; + bool CalcSecIntersGeomData( int nInt, const Point3d& ptInt, int& nPos1, int& nPos2) ; + bool CalcSecIntersTopolData( int nInt, int nPos1, int nPos2) ; + bool CalcOverlapData( int nInt, bool bEqVers, const Point3d& ptS1, const Point3d& ptE1, + int dUS1, int dUE1, const Point3d& ptS2, const Point3d& ptE2) ; + + private : + static const int MAX_INTERS = 2 ; + + private : + CurveArc m_Arc1 ; + CurveArc m_Arc2 ; + bool m_bOverlaps ; + int m_nNumInters ; + IntCrvCrvInfo m_Info[MAX_INTERS] ; +} ; + diff --git a/IntersCrvCompoCrvCompo.cpp b/IntersCrvCompoCrvCompo.cpp index 53daf9c..54f0367 100644 --- a/IntersCrvCompoCrvCompo.cpp +++ b/IntersCrvCompoCrvCompo.cpp @@ -30,6 +30,7 @@ static bool CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nS const ICurve& CurveB, double dUB, int& nType) ; static bool CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB1, double dUB2, int& nType) ; +static bool MoveParamToAvoidTg( double& dU, ICurve::Side nSide, const ICurve& Curve) ; //---------------------------------------------------------------------------- IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA, @@ -645,23 +646,27 @@ CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB, int& nType) { // devo studiare un intorno dell'intersezione + // spostandomi leggermente per evitare eventuali problemi di tangenza Point3d ptP ; // direzione di arrivo (FROM_MINUS) o partenza (FROM_PLUS) curva A Vector3d vtADir ; - if ( ! CurveA.IsValidParam( dUA, nSideA) || - ! CurveA.GetPointTang( dUA, nSideA, ptP, vtADir)) + double dUAm = dUA ; + if ( ! MoveParamToAvoidTg( dUAm, nSideA, CurveA) || + ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) vtADir *= - 1 ; // direzioni di arrivo (prev) e partenza (next) curva B Vector3d vtBpDir ; - if ( ! CurveB.IsValidParam( dUB, ICurve::FROM_MINUS) || - ! CurveB.GetPointTang( dUB, ICurve::FROM_MINUS, ptP, vtBpDir)) + double dUBp = dUB ; + if ( ! MoveParamToAvoidTg( dUBp, ICurve::FROM_MINUS, CurveB) || + ! CurveB.GetPointTang( dUBp, ICurve::FROM_MINUS, ptP, vtBpDir)) return false ; vtBpDir *= - 1 ; Vector3d vtBnDir ; - if ( ! CurveB.IsValidParam( dUB, ICurve::FROM_PLUS) || - ! CurveB.GetPointTang( dUB, ICurve::FROM_PLUS, ptP, vtBnDir)) + double dUBn = dUB ; + if ( ! MoveParamToAvoidTg( dUBn, ICurve::FROM_PLUS, CurveB) || + ! CurveB.GetPointTang( dUBn, ICurve::FROM_PLUS, ptP, vtBnDir)) return false ; // angolo del versore DirA rispetto a DirBn double dAngADeg ; @@ -692,30 +697,35 @@ CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, Point3d ptP ; // direzione di arrivo (FROM_MINUS) o partenza (FROM_PLUS) curva A Vector3d vtADir ; - if ( ! CurveA.IsValidParam( dUA, nSideA) || - ! CurveA.GetPointTang( dUA, nSideA, ptP, vtADir)) + double dUAm = dUA ; + if ( ! MoveParamToAvoidTg( dUAm, nSideA, CurveA) || + ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) vtADir *= - 1 ; // direzioni di arrivo (prev) e partenza (next) curva B (P1) Vector3d vtB1pDir ; - if ( ! CurveB.IsValidParam( dUB1, ICurve::FROM_MINUS) || - ! CurveB.GetPointTang( dUB1, ICurve::FROM_MINUS, ptP, vtB1pDir)) + double dUB1p = dUB1 ; + if ( ! MoveParamToAvoidTg( dUB1p, ICurve::FROM_MINUS, CurveB) || + ! CurveB.GetPointTang( dUB1p, ICurve::FROM_MINUS, ptP, vtB1pDir)) return false ; vtB1pDir *= - 1 ; Vector3d vtB1nDir ; - if ( ! CurveB.IsValidParam( dUB1, ICurve::FROM_PLUS) || - ! CurveB.GetPointTang( dUB1, ICurve::FROM_PLUS, ptP, vtB1nDir)) + double dUB1n = dUB1 ; + if ( ! MoveParamToAvoidTg( dUB1n, ICurve::FROM_PLUS, CurveB) || + ! CurveB.GetPointTang( dUB1n, ICurve::FROM_PLUS, ptP, vtB1nDir)) return false ; // direzioni di arrivo (prev) e partenza (next) curva B (P2) Vector3d vtB2pDir ; - if ( ! CurveB.IsValidParam( dUB2, ICurve::FROM_MINUS) || - ! CurveB.GetPointTang( dUB2, ICurve::FROM_MINUS, ptP, vtB2pDir)) + double dUB2p = dUB2 ; + if ( ! MoveParamToAvoidTg( dUB2p, ICurve::FROM_MINUS, CurveB) || + ! CurveB.GetPointTang( dUB2p, ICurve::FROM_MINUS, ptP, vtB2pDir)) return false ; vtB2pDir *= - 1 ; Vector3d vtB2nDir ; - if ( ! CurveB.IsValidParam( dUB2, ICurve::FROM_PLUS) || - ! CurveB.GetPointTang( dUB2, ICurve::FROM_PLUS, ptP, vtB2nDir)) + double dUB2n = dUB2 ; + if ( ! MoveParamToAvoidTg( dUB2n, ICurve::FROM_PLUS, CurveB) || + ! CurveB.GetPointTang( dUB2n, ICurve::FROM_PLUS, ptP, vtB2nDir)) return false ; // angolo del versore DirA rispetto a DirB1n double dAngADeg ; @@ -751,3 +761,52 @@ CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, nType = ICCT_OUT ; return true ; } + +//---------------------------------------------------------------------------- +static bool +MoveParamToAvoidTg( double& dU, ICurve::Side nSide, const ICurve& Curve) +{ + // verifico che il parametro sia accettabile + if ( ! Curve.IsValidParam( dU, nSide)) + return false ; + + // determino un incremento piccolo ma valido del parametro U + double dDeltaU = 1000 * EPS_PARAM ; + Point3d ptPos ; + Vector3d vtDer1 ; + if ( Curve.GetPointD1D2( dU, nSide, ptPos, &vtDer1)) { + double dDer1 = vtDer1.LenXY() ; + if ( dDer1 > EPS_ZERO) + dDeltaU = 10 * EPS_SMALL / dDer1 ; + } + + // cerco di spostarmi per evitare eventuali problemi di tangenza + if ( nSide == ICurve::FROM_MINUS) { + double dUm = dU - dDeltaU ; + if ( ! Curve.IsValidParam( dUm, nSide)) { + if ( Curve.IsClosed()) { + double dStart, dEnd ; + Curve.GetDomain( dStart, dEnd) ; + dUm = ( dEnd - dStart) - dDeltaU ; + } + else + dUm = dU ; + } + dU = dUm ; + return true ; + } + else { // nSide == ICurve::FROM_PLUS + double dUm = dU + dDeltaU ; + if ( ! Curve.IsValidParam( dUm, nSide)) { + if ( Curve.IsClosed()) { + double dStart, dEnd ; + Curve.GetDomain( dStart, dEnd) ; + dUm = dStart + dDeltaU ; + } + else + dUm = dU ; + } + dU = dUm ; + return true ; + } +} diff --git a/IntersCurveCurve.cpp b/IntersCurveCurve.cpp index dc061fa..d4da256 100644 --- a/IntersCurveCurve.cpp +++ b/IntersCurveCurve.cpp @@ -13,12 +13,16 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" +#include "GeoConst.h" #include "IntersLineLine.h" +#include "IntersLineArc.h" +#include "IntersArcArc.h" #include "IntersCrvCompoCrvCompo.h" #include "CurveLine.h" #include "CurveComposite.h" #include "/EgtDev/Include/EGkIntersCurveCurve.h" #include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkPlane3d.h" #include "/EgtDev/Include/EGtPointerOwner.h" #include @@ -30,11 +34,11 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, // Le intersezioni sono calcolate nel piano XY locale. // Il flag bAreSegments vale solo per intersezione tra due linee e riguarda entrambe. - // reset + // inizializzazioni m_bOverlaps = false ; m_nNumInters = 0 ; - m_pCurve[0] = nullptr ; - m_pCurve[1] = nullptr ; + m_pCurve[0] = &CurveA ; + m_pCurve[1] = &CurveB ; // chiamo calcolatore opportuno switch ( CurveA.GetType()) { @@ -44,6 +48,7 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, LineLineCalculate( CurveA, CurveB, bAreSegments) ; break ; case CRV_ARC : + LineArcCalculate( CurveA, CurveB) ; break ; case CRV_BEZ : break ; @@ -53,6 +58,19 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, } break ; case CRV_ARC : + switch ( CurveB.GetType()) { + case CRV_LINE : + ArcLineCalculate( CurveA, CurveB) ; + break ; + case CRV_ARC : + ArcArcCalculate( CurveA, CurveB) ; + break ; + case CRV_BEZ : + break ; + case CRV_COMPO : + ArcCrvCompoCalculate( CurveA, CurveB) ; + break ; + } break ; case CRV_BEZ : break ; @@ -62,6 +80,7 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, CrvCompoLineCalculate( CurveA, CurveB) ; break ; case CRV_ARC : + CrvCompoArcCalculate( CurveA, CurveB) ; break ; case CRV_BEZ : break ; @@ -71,10 +90,6 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, } break ; } - - // salvo i puntatori alle curve - m_pCurve[0] = &CurveA ; - m_pCurve[1] = &CurveB ; } //---------------------------------------------------------------------------- @@ -86,11 +101,25 @@ IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, if ( intLnLn.m_nNumInters > 0) { m_bOverlaps = intLnLn.m_bOverlaps ; m_nNumInters = intLnLn.m_nNumInters ; - for ( int i = 0 ; i < m_nNumInters ; ++ i) + if ( m_nNumInters == 1) m_Info.push_back( intLnLn.m_Info) ; } } +//---------------------------------------------------------------------------- +void +IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB) +{ + IntersLineArc intLnAr( *GetCurveLine( &CurveA), *GetCurveArc( &CurveB)) ; + + if ( intLnAr.m_nNumInters > 0) { + m_bOverlaps = false ; + m_nNumInters = intLnAr.m_nNumInters ; + for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_Info.push_back( intLnAr.m_Info[i]) ; + } +} + //---------------------------------------------------------------------------- void IntersCurveCurve::LineCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) @@ -102,6 +131,47 @@ IntersCurveCurve::LineCrvCompoCalculate( const ICurve& CurveA, const ICurve& Cur CrvCompoCrvCompoCalculate( crvCompo, CurveB) ; } +//---------------------------------------------------------------------------- +void +IntersCurveCurve::ArcLineCalculate( const ICurve& CurveA, const ICurve& CurveB) +{ + IntersLineArc intLnAr( *GetCurveLine( &CurveB), *GetCurveArc( &CurveA)) ; + + if ( intLnAr.m_nNumInters > 0) { + m_bOverlaps = false ; + m_nNumInters = intLnAr.m_nNumInters ; + for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_Info.push_back( intLnAr.m_Info[i]) ; + // devo scambiare opportunamente le info di intersezione tra A e B + SwapInfoAB( m_Info, 0) ; + } +} + +//---------------------------------------------------------------------------- +void +IntersCurveCurve::ArcArcCalculate( const ICurve& CurveA, const ICurve& CurveB) +{ + IntersArcArc intArAr( *GetCurveArc( &CurveA), *GetCurveArc( &CurveB)) ; + + if ( intArAr.m_nNumInters > 0) { + m_bOverlaps = intArAr.m_bOverlaps ; + m_nNumInters = intArAr.m_nNumInters ; + for ( int i = 0 ; i < m_nNumInters ; ++ i) + m_Info.push_back( intArAr.m_Info[i]) ; + } +} + +//---------------------------------------------------------------------------- +void +IntersCurveCurve::ArcCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) +{ + // trasformo l'arco in curva composita + CurveComposite crvCompo ; + crvCompo.CopyFrom( &CurveA) ; + // eseguo l'intersezione tra curve composite + CrvCompoCrvCompoCalculate( crvCompo, CurveB) ; +} + //---------------------------------------------------------------------------- void IntersCurveCurve::CrvCompoLineCalculate( const ICurve& CurveA, const ICurve& CurveB) @@ -113,6 +183,17 @@ IntersCurveCurve::CrvCompoLineCalculate( const ICurve& CurveA, const ICurve& Cur CrvCompoCrvCompoCalculate( CurveA, crvCompo) ; } +//---------------------------------------------------------------------------- +void +IntersCurveCurve::CrvCompoArcCalculate( const ICurve& CurveA, const ICurve& CurveB) +{ + // trasformo l'arco in curva composita + CurveComposite crvCompo ; + crvCompo.CopyFrom( &CurveB) ; + // eseguo l'intersezione tra curve composite + CrvCompoCrvCompoCalculate( CurveA, crvCompo) ; +} + //---------------------------------------------------------------------------- void IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) @@ -239,21 +320,8 @@ IntersCurveCurve::GetCurveClassification( int nCrv, CRVCVECTOR& ccClass) // devo scambiare opportunamente le info di intersezione tra A e B // copia temporanea delle info di intersezione ICCIVECTOR InfoTmp = m_Info ; - // eseguo lo scambio - for ( int i = 0 ; i < m_nNumInters ; ++ i) { - // scambio le informazioni tra A e B - swap( InfoTmp[i].IciA[0], InfoTmp[i].IciB[0]) ; - swap( InfoTmp[i].IciA[1], InfoTmp[i].IciB[1]) ; - // riordino eventuali sovrapposizioni controverse - if ( InfoTmp[i].bOverlap && ! InfoTmp[i].bCBOverEq) { - swap( InfoTmp[i].IciA[0], InfoTmp[i].IciA[1]) ; - swap( InfoTmp[i].IciB[0], InfoTmp[i].IciB[1]) ; - } - } - // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva - stable_sort( InfoTmp.begin(), InfoTmp.end(), SortGreater) ; - // verifiche su intersezioni in zone non-manifold - OrderNonManifoldInters( InfoTmp, *(m_pCurve[1]), *(m_pCurve[0])) ; + // esecuzione scambio e controlli + SwapInfoAB( InfoTmp, 1) ; // se esiste almeno una intersezione if ( m_nNumInters >= 1) return CalcCurveClassification( m_pCurve[1], InfoTmp, ccClass) ; @@ -266,6 +334,31 @@ IntersCurveCurve::GetCurveClassification( int nCrv, CRVCVECTOR& ccClass) return false ; } +//---------------------------------------------------------------------------- +bool +IntersCurveCurve::SwapInfoAB( ICCIVECTOR& Info, int IndCrvOrd) +{ + if ( IndCrvOrd < 0 || IndCrvOrd > 1) + return false ; + + // eseguo lo scambio + for ( int i = 0 ; i < m_nNumInters ; ++ i) { + // scambio le informazioni tra A e B + swap( Info[i].IciA[0], Info[i].IciB[0]) ; + swap( Info[i].IciA[1], Info[i].IciB[1]) ; + // riordino eventuali sovrapposizioni controverse + if ( Info[i].bOverlap && ! Info[i].bCBOverEq) { + swap( Info[i].IciA[0], Info[i].IciA[1]) ; + swap( Info[i].IciB[0], Info[i].IciB[1]) ; + } + } + // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva + stable_sort( Info.begin(), Info.end(), SortGreater) ; + // verifiche su intersezioni in zone non-manifold + OrderNonManifoldInters( Info, *(m_pCurve[IndCrvOrd]), *(m_pCurve[1-IndCrvOrd])) ; + return true ; +} + //---------------------------------------------------------------------------- bool IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTOR& Info, CRVCVECTOR& ccClass) @@ -352,17 +445,21 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB double dStartPar, dEndPar ; if ( ! pCurveA->GetDomain( dStartPar, dEndPar)) return false ; - // se i box delle due curve non interferiscono è sicuramente esterna + // se i box delle due curve non interferiscono è sicuramente default BBox3d boxCrvA, boxCrvB ; if ( ! pCurveA->GetLocalBBox( boxCrvA) || ! pCurveB->GetLocalBBox( boxCrvB)) return false ; if ( ! boxCrvA.OverlapsXY( boxCrvB)) { + // determino il tipo di esterno + int nClass ; + if ( ! GetCurveOutClass( pCurveB, nClass)) + return false ; // assegno i dati CrvClass segClass ; segClass.dParS = dStartPar ; segClass.dParE = dEndPar ; - segClass.nClass = CRVC_OUT ; + segClass.nClass = nClass ; ccClass.push_back( segClass) ; return true ; } @@ -377,7 +474,7 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB return false ; // calcolo l'intersezione IntersCurveCurve iCC( clLine, *pCurveB) ; - // dichiaro la curva esterna per default + // dichiaro la classe della curva per default int nClass = CRVC_OUT ; // se c'è almeno una intersezione if ( iCC.GetNumInters() > 0) { @@ -387,6 +484,12 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB if ( aInfo.IciA[0].nPrevTy == ICCT_IN) nClass = CRVC_IN ; } + // altrimenti sono esterni tra loro + else { + // determino il tipo di esterno + if ( ! GetCurveOutClass( pCurveB, nClass)) + return false ; + } // assegno i dati CrvClass segClass ; segClass.dParS = dStartPar ; @@ -395,3 +498,17 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB ccClass.push_back( segClass) ; return true ; } + +//---------------------------------------------------------------------------- +bool +IntersCurveCurve::GetCurveOutClass( const ICurve* pCurve, int& nClass) +{ + PolyLine PL ; + if ( ! pCurve->ApproxWithLines( LIN_TOL_APPROX, ANG_TOL_APPROX_DEG, PL)) + return false ; + double dArea ; + if ( ! PL.GetAreaXY( dArea)) + return false ; + nClass = (( dArea > 0) ? CRVC_OUT : CRVC_IN) ; + return true ; +} \ No newline at end of file diff --git a/IntersLineArc.cpp b/IntersLineArc.cpp new file mode 100644 index 0000000..527fdd1 --- /dev/null +++ b/IntersLineArc.cpp @@ -0,0 +1,273 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : IntersLineArc.cpp Data : 07.07.14 Versione : 1.5g2 +// Contenuto : Implementazione della classe intersezione linea/arco. +// +// +// +// Modifiche : 07.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "IntersLineArc.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +IntersLineArc::IntersLineArc( const ICurveLine& Line, const ICurveArc& Arc) +{ + // Le intersezioni sono calcolate nel piano XY locale. + + // nessuna intersezione trovata + m_nNumInters = 0 ; + + // verifico validità linea e arco + if ( ! Line.IsValid() || ! Arc.IsValid()) + return ; + // l'arco deve avere il piano coincidente con XY + if ( ! Arc.GetNormVersor().IsZplus() && ! Arc.GetNormVersor().IsZminus()) + return ; + // verifico che l'angolo al centro non superi il giro + if ( fabs( Arc.GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) + return ; + // !!! Gestire l'arco proiettato come ellisse + + // verifico sovrapposizione box + BBox3d boxLine ; + if ( ! Line.GetLocalBBox( boxLine)) + return ; + BBox3d boxArc ; + if ( ! Arc.GetLocalBBox( boxArc)) + return ; + if ( ! boxLine.OverlapsXY( boxArc)) + return ; + + // linea : copia e Direzione + m_Line.CopyFrom( &Line) ; + m_vtDirL = m_Line.GetEnd() - m_Line.GetStart() ; + if ( m_vtDirL.SqLenXY() < EPS_SMALL * EPS_SMALL) + return ; + + // arco : copia + m_Arc.CopyFrom( &Arc) ; + + // punto proiezione del centro arco sulla linea + double dU = (( m_Arc.GetCenter() - m_Line.GetStart()) * m_vtDirL) / m_vtDirL.SqLenXY() ; + Point3d ptPrjCen = m_Line.GetStart() + m_vtDirL * dU ; + // quadrato della distanza tra centro e punto proiezione + double dSqDist = ( ptPrjCen - m_Arc.GetCenter()).SqLenXY() ; + // differenza tra quadrato del raggio e quadrato della distanza + double dSqDelta = m_Arc.GetRadius() * m_Arc.GetRadius() - dSqDist ; + + // se distanza maggiore del raggio -> nessuna intersezione + if ( dSqDelta < - 2 * m_Arc.GetRadius() * EPS_SMALL) + return ; + + // se distanza uguale al raggio -> una intersezione tangente (è la proiezione) + if ( dSqDelta < 2 * m_Arc.GetRadius() * EPS_SMALL) { + // determinazione geometrica dell'intersezione tra le due curve + int nPosL, nPosA ; + if ( ! CalcIntersGeomData( 0, ptPrjCen, nPosL, nPosA)) + return ; + // determinazione topologica dell'intersezione tra le due curve + if ( ! CalcTgIntersTopolData( 0, nPosL, nPosA)) + return ; + // aggiorno dati generali di intersezione + m_Info[0].bOverlap = false ; + m_nNumInters = 1 ; + return ; + } + + // distanza minore del raggio -> due intersezioni + double dDelta = sqrt( dSqDelta) ; + Vector3d vtDelta = m_vtDirL * dDelta / m_vtDirL.LenXY() ; + int nPosL, nPosA ; + // ---> prima intersezione + // determinazione geometrica e topologica dell'intersezione tra le due curve + if ( CalcIntersGeomData( 0, ptPrjCen - vtDelta, nPosL, nPosA) && + CalcSecIntersTopolData( 0, nPosL, nPosA)) { + // aggiorno dati generali di intersezione + m_Info[0].bOverlap = false ; + ++ m_nNumInters ; + } + // ---> seconda intersezione + // determinazione geometrica e topologica dell'intersezione tra le due curve + if ( CalcIntersGeomData( m_nNumInters, ptPrjCen + vtDelta, nPosL, nPosA) && + CalcSecIntersTopolData( m_nNumInters, nPosL, nPosA)) { + // aggiorno dati generali di intersezione + m_Info[m_nNumInters].bOverlap = false ; + ++ m_nNumInters ; + } +} + +//---------------------------------------------------------------------------- +bool +IntersLineArc::CalcIntersGeomData( int nInt, const Point3d& ptInt, int& nPosL, int& nPosA) +{ + // posizione parametrica dell'intersezione sulla linea + if ( ! m_Line.CalcPointParamPosiz( ptInt, true, m_Info[nInt].IciA[0].dU, nPosL)) + return false ; + // posizione parametrica dell'intersezione sull'arco + if ( ! m_Arc.CalcPointParamPosiz( ptInt, m_Info[nInt].IciB[0].dU, nPosA)) + return false ; + // se soluzione non accettata, esco + if ( nPosL == ICurve::PP_NULL || nPosA == ICurve::PP_NULL) + return false ; + // calcolo i punti sulle due curve (possono differire in Z) + m_Info[nInt].IciA[0].ptI = m_Line.GetStart() + m_Info[nInt].IciA[0].dU * m_vtDirL ; + m_Arc.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, m_Info[nInt].IciB[0].ptI) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +IntersLineArc::CalcTgIntersTopolData( int nInt, int nPosL, int nPosA) +{ + // calcolo dati ausiliari + bool bCCW = (( m_Arc.GetAngCenter() > 0 && m_Arc.GetNormVersor().IsZplus()) || + ( m_Arc.GetAngCenter() < 0 && m_Arc.GetNormVersor().IsZminus())) ; + double dCrossXY = CrossXY( m_vtDirL, ( m_Arc.GetCenter() - m_Info[nInt].IciB[0].ptI)) ; + + // calcolo tipo di intersezione + m_Info[nInt].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciA[0].nNextTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nNextTy = ICCT_NULL ; + // si incontrano alle estremità, non si può dire alcunché + if ( ( nPosL == ICurve::PP_START || nPosL == ICurve::PP_END) && + ( nPosA == ICurve::PP_START || nPosA == ICurve::PP_END)) { + ; // rimangono tutti NULL + } + // l'inizio di L interseca il mezzo di A + else if ( nPosL == ICurve::PP_START) { + if ( bCCW) + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; // NULL + IN + // curva B NULL + NULL + } + // la fine di L interseca il mezzo di A + else if ( nPosL == ICurve::PP_END) { + if ( bCCW) + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL + // curva B NULL + NULL + } + // l'inizio di A interseca il mezzo di L + else if ( nPosA == ICurve::PP_START) { + // curva A NULL + NULL + if ( - dCrossXY > 0) + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; // NULL + IN + } + // la fine di A interseca il mezzo di L + else if ( nPosA == ICurve::PP_END) { + // curva A NULL + NULL + if ( - dCrossXY > 0) + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL + } + // si intersecano nel mezzo + else { + if ( bCCW) { // OUT + OUT + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; + } + else { // IN + IN + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; + } + if ( - dCrossXY > 0) { // OUT + OUT + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; + } + else { // IN + IN + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +IntersLineArc::CalcSecIntersTopolData( int nInt, int nPosL, int nPosA) +{ + // calcolo dati ausiliari + Point3d ptIntA ; + Vector3d vtDirA ; + m_Arc.GetPointD1D2( m_Info[nInt].IciB[0].dU, ICurve::FROM_MINUS, ptIntA, &vtDirA) ; + double dCrossXY = CrossXY( m_vtDirL, vtDirA) ; + // calcolo tipo di intersezione + m_Info[nInt].IciA[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciA[0].nNextTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nPrevTy = ICCT_NULL ; + m_Info[nInt].IciB[0].nNextTy = ICCT_NULL ; + // si incontrano alle estremità, non si può dire alcunché + if ( ( nPosL == ICurve::PP_START || nPosL == ICurve::PP_END) && + ( nPosA == ICurve::PP_START || nPosA == ICurve::PP_END)) { + ; // rimangono tutti NULL + } + // l'inizio di 1 interseca il mezzo di 2 + else if ( nPosL == ICurve::PP_START) { + if ( dCrossXY > 0) + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; // NULL + IN + // curva B NULL + NULL + } + // la fine di 1 interseca il mezzo di 2 + else if ( nPosL == ICurve::PP_END) { + if ( dCrossXY < 0) + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; // IN + NULL + // curva B NULL + NULL + } + // l'inizio di 2 interseca il mezzo di 1 + else if ( nPosA == ICurve::PP_START) { + // curva A NULL + NULL + if ( - dCrossXY > 0) + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT + else + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; // NULL + IN + } + // la fine di 2 interseca il mezzo di 1 + else if ( nPosA == ICurve::PP_END) { + // curva A NULL + NULL + if ( - dCrossXY < 0) + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL + else + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; // IN + NULL + } + // si intersecano nel mezzo + else { + if ( CrossXY( ( m_Line.GetStart() - ( ptIntA - vtDirA)), vtDirA) > 0) { + m_Info[nInt].IciA[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciA[0].nNextTy = ICCT_IN ; + } + else { + m_Info[nInt].IciA[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciA[0].nNextTy = ICCT_OUT ; + } + if ( CrossXY( ( ( ptIntA - vtDirA) - m_Line.GetStart()), m_vtDirL) > 0) { + m_Info[nInt].IciB[0].nPrevTy = ICCT_OUT ; + m_Info[nInt].IciB[0].nNextTy = ICCT_IN ; + } + else { + m_Info[nInt].IciB[0].nPrevTy = ICCT_IN ; + m_Info[nInt].IciB[0].nNextTy = ICCT_OUT ; + } + } + + return true ; +} diff --git a/IntersLineArc.h b/IntersLineArc.h new file mode 100644 index 0000000..a112ead --- /dev/null +++ b/IntersLineArc.h @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : IntersLineArc.h Data : 07.07.14 Versione : 1.5g2 +// Contenuto : Dichiarazione della classe intersezione linea/arco. +// +// +// +// Modifiche : 07.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkIntersCurveCurve.h" +#include "CurveLine.h" +#include "CurveArc.h" + + +//----------------------------------------------------------------------------- +class IntersLineArc +{ + friend class IntersCurveCurve ; + + public : + IntersLineArc( const ICurveLine& Line, const ICurveArc& Arc) ; + + public : + bool GetOverlaps( void) + { return false ; } + int GetNumInters( void) + { return m_nNumInters ; } + bool GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) + { if ( nInd < 0 || nInd >= m_nNumInters) + return false ; + aInfo = m_Info[nInd] ; + return true ; } + + private : + IntersLineArc( void) ; + bool CalcIntersGeomData( int nInt, const Point3d& ptInt, int& nPosL, int& nPosA) ; + bool CalcTgIntersTopolData( int nInt, int nPosL, int nPosA) ; + bool CalcSecIntersTopolData( int nInt, int nPosL, int nPosA) ; + + private : + static const int MAX_INTERS = 2 ; + + private : + CurveLine m_Line ; + Vector3d m_vtDirL ; + CurveArc m_Arc ; + int m_nNumInters ; + IntCrvCrvInfo m_Info[MAX_INTERS] ; +} ; + diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index 97d119b..01890a6 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -158,26 +158,24 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li // posizioni parametriche dell'intersezione sulle linee m_Info.IciA[0].dU = CrossXY( ( ptS2 - ptS1), vtDir2) / dCrossXY ; m_Info.IciB[0].dU = CrossXY( ( ptS2 - ptS1), vtDir1) / dCrossXY ; - // tipo di posizione - enum IntPos { IP_NULL = 0, IP_START = 1, IP_MID = 2, IP_END = 3} ; // verifica posizione intersezione su prima linea - int nPos1 = IP_NULL ; // fuori + int nPos1 = ICurve::PP_NULL ; // fuori if ( ( m_Info.IciA[0].dU * vtDir1).IsSmall()) - nPos1 = IP_START ; // vicino a inizio + nPos1 = ICurve::PP_START ; // vicino a inizio else if ( (( 1 - m_Info.IciA[0].dU) * vtDir1).IsSmall()) - nPos1 = IP_END ; // vicino a fine + nPos1 = ICurve::PP_END ; // vicino a fine else if ( m_Info.IciA[0].dU > 0 && m_Info.IciA[0].dU < 1) - nPos1 = IP_MID ; // nell'interno + nPos1 = ICurve::PP_MID ; // nell'interno // verifica posizione intersezione su seconda linea - int nPos2 = IP_NULL ; // fuori + int nPos2 = ICurve::PP_NULL ; // fuori if ( ( m_Info.IciB[0].dU * vtDir2).IsSmall()) - nPos2 = IP_START ; // vicino a inizio + nPos2 = ICurve::PP_START ; // vicino a inizio else if ( (( 1 - m_Info.IciB[0].dU) * vtDir2).IsSmall()) - nPos2 = IP_END ; // vicino a fine + nPos2 = ICurve::PP_END ; // vicino a fine else if ( m_Info.IciB[0].dU > 0 && m_Info.IciB[0].dU < 1) - nPos2 = IP_MID ; // nell'interno + nPos2 = ICurve::PP_MID ; // nell'interno // se soluzione non accettata, esco - if ( nPos1 == IP_NULL || nPos2 == IP_NULL) + if ( nPos1 == ICurve::PP_NULL || nPos2 == ICurve::PP_NULL) return ; // limito i parametri a stare sui segmenti (0...1) m_Info.IciA[0].dU = min( max( m_Info.IciA[0].dU, 0.), 1.) ; @@ -191,12 +189,12 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li m_Info.IciB[0].nPrevTy = ICCT_NULL ; m_Info.IciB[0].nNextTy = ICCT_NULL ; // si incontrano alle estremità, non si può dire alcunché - if ( ( nPos1 == IP_START || nPos1 == IP_END) && - ( nPos2 == IP_START || nPos2 == IP_END)) { + if ( ( nPos1 == ICurve::PP_START || nPos1 == ICurve::PP_END) && + ( nPos2 == ICurve::PP_START || nPos2 == ICurve::PP_END)) { ; // rimangono tutti NULL } // l'inizio di 1 interseca il mezzo di 2 - else if ( nPos1 == IP_START) { + else if ( nPos1 == ICurve::PP_START) { if ( dCrossXY > 0) m_Info.IciA[0].nNextTy = ICCT_OUT ; // NULL + OUT else @@ -204,7 +202,7 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li // curva B NULL + NULL } // la fine di 1 interseca il mezzo di 2 - else if ( nPos1 == IP_END) { + else if ( nPos1 == ICurve::PP_END) { if ( dCrossXY < 0) m_Info.IciA[0].nPrevTy = ICCT_OUT ; // OUT + NULL else @@ -212,7 +210,7 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li // curva B NULL + NULL } // l'inizio di 2 interseca il mezzo di 1 - else if ( nPos2 == IP_START) { + else if ( nPos2 == ICurve::PP_START) { // curva A NULL + NULL if ( - dCrossXY > 0) m_Info.IciB[0].nNextTy = ICCT_OUT ; // NULL + OUT @@ -220,7 +218,7 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li m_Info.IciB[0].nNextTy = ICCT_IN ; // NULL + IN } // la fine di 2 interseca il mezzo di 1 - else if ( nPos2 == IP_END) { + else if ( nPos2 == ICurve::PP_END) { // curva A NULL + NULL if ( - dCrossXY < 0) m_Info.IciB[0].nPrevTy = ICCT_OUT ; // OUT + NULL @@ -253,7 +251,6 @@ IntersLineLine::IntersFiniteLines( const ICurveLine& Line1, const ICurveLine& Li } // se le linee sono parallele e non coincidenti - //if ( fabs( CrossXY( ( ptS2 - ptS1), vtDir1)) > EPS_SMALL * dLen1XY) if ( bParallel && bFarEnds) return ; // non ci sono intersezioni diff --git a/PolyLine.cpp b/PolyLine.cpp index a09c57e..de59e87 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -327,7 +327,7 @@ PolyLine::GetNextULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* //---------------------------------------------------------------------------- bool -PolyLine::NewellPlane( Plane3d& plPlane) const +PolyLine::NewellPlane( Plane3d& plPlane, double& dArea) const { // Compute normal as being proportional to projected areas of polygon onto the yz, // xz, and xy planes. Also compute centroid as representative point on the plane @@ -356,21 +356,25 @@ PolyLine::NewellPlane( Plane3d& plPlane) const if ( nNumSide < 3) return false ; // Normal must be normalizable (the length of the normal is the double of the area of the polygon) - if ( ! vtN.Normalize()) + double dLenN = vtN.Len() ; + if ( dLenN < EPS_SMALL) return false ; - // Normalize normal and fill in the plane equation fields + vtN /= dLenN ; + // Fill in the plane equation fields plPlane.vtN = vtN ; plPlane.dDist = ( ( ptCen - ORIG) * plPlane.vtN) / nNumSide ; // “centroid / n” is the true centroid point + // Set area + dArea = 0.5 * dLenN ; return true ; } //---------------------------------------------------------------------------- bool -PolyLine::IsPlanar( Plane3d& plPlane, double dToler) const +PolyLine::IsPlanar( Plane3d& plPlane, double& dArea, double dToler) const { // Compute a representative plane for the polygon - if ( ! NewellPlane( plPlane)) + if ( ! NewellPlane( plPlane, dArea)) return false ; // Test each vertex to see if it is farther from plane than allowed max distance Point3d ptP ; @@ -383,6 +387,23 @@ PolyLine::IsPlanar( Plane3d& plPlane, double dToler) const return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::GetAreaXY( double& dArea) const +{ + // verifico sia chiusa + if ( ! IsClosed()) + return false ; + // calcolo l'area considerando solo XY (è la Z di Newell) + dArea = 0 ; + Point3d ptIni, ptFin ; + for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { + dArea += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy + } + dArea = 0.5 * dArea ; + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::GetMaxDistanceFromLine( double& dMaxDist, const Point3d& ptAx, diff --git a/Triangulate.cpp b/Triangulate.cpp index 63c8bf6..4b5ee73 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -31,8 +31,9 @@ Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr) if ( ! PL.IsClosed()) return false ; // calcolo il piano medio del poligono + double dArea ; Plane3d plPlane ; - if ( ! PL.IsPlanar( plPlane, 50 * EPS_SMALL)) + if ( ! PL.IsPlanar( plPlane, dArea, 50 * EPS_SMALL)) return false ; bool bCCW ; if ( fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.x) &&