//---------------------------------------------------------------------------- // 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 CurveLine& Line, const CurveArc& 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 ( abs( Arc.GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) return ; // 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() ; Vector3d vtDirLXY = m_vtDirL ; vtDirLXY.z = 0 ; if ( m_vtDirL.IsSmallXY()) return ; // arco : copia m_Arc.CopyFrom( &Arc) ; // punto proiezione del centro arco sulla linea double dU = (( m_Arc.GetCenter() - m_Line.GetStart()) * vtDirLXY) / vtDirLXY.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 punto proiettato approssima uno degli estremi dell'arco, annullo dSqDelta Point3d ptArcStart, ptArcEnd ; if ( m_Arc.GetStartPoint( ptArcStart) && AreSamePointXYApprox( ptPrjCen, ptArcStart)) dSqDelta = 0 ; else if ( m_Arc.GetEndPoint( ptArcEnd) && AreSamePointXYApprox( ptPrjCen, ptArcEnd)) dSqDelta = 0 ; // se distanza uguale al raggio -> una intersezione tangente, è la proiezione // (corrisponde a una differenza max di EPS_SMALL tra le intersezioni) if ( dSqDelta < EPS_SMALL * 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 ; }