d0521e8f92
- sistemata approssimazione di curve di Bezier con archi - aggiunta a CurveBezier metodo per sapere se è collassata in un punto - in PolyArc e PolyLine sostituite Splice con Join e aggiunte Split - in TSC non si accetta più la creazione di una curva di Bezier collassata in un punto.
293 lines
9.9 KiB
C++
293 lines
9.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : ArcXxTgArc.cpp Data : 12.06.14 Versione : 1.5f4
|
|
// Contenuto : Implementazione funzioni per calcolo archi tangenti a archi.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 12.06.14 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "/EgtDev/Include/EgkCurveLine.h"
|
|
#include "/EgtDev/Include/EgkArcXxTgArc.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
static int CalcCircleCenTgCircle( const Point3d& ptC, const Point3d& ptCen, double dRad, BIPNTVECTOR& vCenPtg) ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveArc*
|
|
GetCircleCenTgArc( const Point3d& ptCen, const ICurveArc& crvArc, const Point3d& ptNear)
|
|
{
|
|
// calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X)
|
|
Frame3d frIntr ;
|
|
if ( ! frIntr.Set( crvArc.GetCenter(), crvArc.GetNormVersor(), crvArc.GetStartVersor()))
|
|
return nullptr ;
|
|
|
|
// porto il punto nel riferimento intrinseco
|
|
Point3d ptCLoc = ptCen ;
|
|
ptCLoc.ToLoc( frIntr) ;
|
|
|
|
// calcolo le circonferenze tangenti alla circonferenza
|
|
BIPNTVECTOR vCenPtg( 2) ;
|
|
int nSol = CalcCircleCenTgCircle( ptCLoc, ORIG, crvArc.GetRadius(), vCenPtg) ;
|
|
if ( nSol == 0)
|
|
return nullptr ;
|
|
|
|
// porto i punti nel riferimento standard dell'arco
|
|
for ( size_t i = 0 ; i < vCenPtg.size() ; ++ i) {
|
|
vCenPtg[i].first.ToGlob( frIntr) ;
|
|
vCenPtg[i].second.ToGlob( frIntr) ;
|
|
}
|
|
|
|
// elimino le soluzioni che non stanno sull'arco
|
|
for ( int i = 1 ; i >= 0 ; -- i) {
|
|
if ( nSol > i) {
|
|
if ( ! crvArc.IsPointOn( vCenPtg[i].second)) {
|
|
-- nSol ;
|
|
for ( int j = i ; j < nSol ; ++ j)
|
|
vCenPtg[j] = vCenPtg[j+1] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se non sono rimaste soluzioni, esco
|
|
if ( nSol == 0)
|
|
return nullptr ;
|
|
|
|
// scelgo la soluzione più vicina al punto di riferimento
|
|
int nIdOk = 0 ;
|
|
double dMinSqDist = INFINITO * INFINITO ;
|
|
for ( int i = 0 ; i < nSol ; ++ i) {
|
|
double dSqDist = SqDist( vCenPtg[i].second, ptNear) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
nIdOk = i ;
|
|
}
|
|
}
|
|
|
|
// creo l'arco
|
|
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
|
|
if ( IsNull( pCrvArc))
|
|
return nullptr ;
|
|
|
|
// costruisco la circonferenza corrispondente alla soluzione scelta
|
|
double dRad = DistXY( vCenPtg[nIdOk].first, vCenPtg[nIdOk].second) ;
|
|
if ( pCrvArc->Set( vCenPtg[nIdOk].first, crvArc.GetNormVersor(), dRad))
|
|
return Release( pCrvArc) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveArc*
|
|
GetArcCenTgArcPnt( const Point3d& ptCen, const ICurveArc& crvArc,
|
|
const Point3d& ptNearTg, const Point3d& ptNearEnd)
|
|
{
|
|
// calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X)
|
|
Frame3d frIntr ;
|
|
if ( ! frIntr.Set( crvArc.GetCenter(), crvArc.GetNormVersor(), crvArc.GetStartVersor()))
|
|
return nullptr ;
|
|
|
|
// porto il centro nel riferimento intrinseco
|
|
Point3d ptCLoc = ptCen ;
|
|
ptCLoc.ToLoc( frIntr) ;
|
|
|
|
// calcolo le circonferenze tangenti alla circonferenza
|
|
BIPNTVECTOR vCenPtg( 2) ;
|
|
int nSol = CalcCircleCenTgCircle( ptCLoc, ORIG, crvArc.GetRadius(), vCenPtg) ;
|
|
if ( nSol == 0)
|
|
return nullptr ;
|
|
|
|
// porto i punti nel riferimento standard dell'arco
|
|
for ( size_t i = 0 ; i < vCenPtg.size() ; ++ i) {
|
|
vCenPtg[i].first.ToGlob( frIntr) ;
|
|
vCenPtg[i].second.ToGlob( frIntr) ;
|
|
}
|
|
|
|
// elimino le soluzioni che non stanno sull'arco
|
|
for ( int i = 1 ; i >= 0 ; -- i) {
|
|
if ( nSol > i) {
|
|
if ( ! crvArc.IsPointOn( vCenPtg[i].second)) {
|
|
-- nSol ;
|
|
for ( int j = i ; j < nSol ; ++ j)
|
|
vCenPtg[j] = vCenPtg[j+1] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se non sono rimaste soluzioni, esco
|
|
if ( nSol == 0)
|
|
return nullptr ;
|
|
|
|
// scelgo la soluzione più vicina al punto di riferimento
|
|
int nIdOk = 0 ;
|
|
double dMinSqDist = INFINITO * INFINITO ;
|
|
for ( int i = 0 ; i < nSol ; ++ i) {
|
|
double dSqDist = SqDist( vCenPtg[i].second, ptNearTg) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
nIdOk = i ;
|
|
}
|
|
}
|
|
|
|
// creo l'arco
|
|
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
|
|
if ( IsNull( pCrvArc))
|
|
return nullptr ;
|
|
|
|
// posso costruire l'arco solo nel riferimento intrinseco e poi portarlo in quello standard
|
|
vCenPtg[nIdOk].first.ToLoc( frIntr) ;
|
|
vCenPtg[nIdOk].second.ToLoc( frIntr) ;
|
|
Point3d ptNEloc = ptNearEnd ;
|
|
ptNEloc.ToLoc( frIntr) ;
|
|
if ( pCrvArc->SetC2P( vCenPtg[nIdOk].first, vCenPtg[nIdOk].second, ptNEloc) &&
|
|
pCrvArc->ToGlob( frIntr))
|
|
return Release( pCrvArc) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Come la CurveArc::Set2PD, ma se raggio infinito restituisce una retta
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArc2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStartDeg)
|
|
{
|
|
// creo l'oggetto arco
|
|
ICurveArc* pArc = CreateCurveArc() ;
|
|
if ( pArc == nullptr)
|
|
return nullptr ;
|
|
// inizializzo il puntatore a curva con l'arco
|
|
PtrOwner<ICurve> pCrv( pArc) ;
|
|
|
|
// calcolo l'arco, se ok lo restituisco ed esco
|
|
if ( pArc->Set2PD( ptStart, ptEnd, dDirStartDeg))
|
|
return Release( pCrv) ;
|
|
|
|
// calcolo arco non riuscito, verifico se retta va bene
|
|
Vector3d vtDiff = ptEnd - ptStart ;
|
|
vtDiff.z = 0 ;
|
|
Vector3d vtDir = FromPolar( 1, dDirStartDeg) ;
|
|
// verifico se i punti sono allineati con la direzione e nel giusto verso
|
|
if ( fabs( CrossXY( vtDiff, vtDir)) < EPS_SMALL && ScalarXY( vtDiff, vtDir) > EPS_SMALL) {
|
|
// creo l'oggetto retta
|
|
ICurveLine* pLine = CreateCurveLine() ;
|
|
if ( pLine == nullptr)
|
|
return nullptr ;
|
|
// inizializzo il puntatore a curva con la retta
|
|
pCrv.Set( pLine) ;
|
|
// calcolo retta, se ok la restituisco ed esco
|
|
if ( pLine->Set( ptStart, ptEnd))
|
|
return Release( pCrv) ;
|
|
}
|
|
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgArc( const Point3d& ptP, double dDirStartDeg, const ICurveArc& crvArc, const Point3d& ptNearTg)
|
|
{
|
|
// se il raggio è praticamente nullo
|
|
if ( crvArc.GetRadius() < EPS_SMALL) {
|
|
return GetArc2PD( ptP, crvArc.GetCenter(), dDirStartDeg) ;
|
|
}
|
|
|
|
// versore ortogonale alla direzione iniziale (si lavora nel piano XY locale)
|
|
Vector3d vtOrtho = FromPolar( 1, dDirStartDeg) ;
|
|
vtOrtho.Rotate( Z_AX, 0, 1) ;
|
|
|
|
// calcolo arco spostando il punto iniziale di + raggio in direzione ortogonale
|
|
Point3d ptP1 = ptP + vtOrtho * crvArc.GetRadius() ;
|
|
PtrOwner<ICurve> pCrv1( GetArc2PD( ptP1, crvArc.GetCenter(), dDirStartDeg)) ;
|
|
bool bOk1 = ( ! IsNull( pCrv1)) ;
|
|
// compenso lo spostamento
|
|
bOk1 = bOk1 && pCrv1->Offset( crvArc.GetRadius(), ICurve::OFF_RIGHT) ;
|
|
// verifico se il punto di tangenza sta sull'arco
|
|
Point3d ptEnd1 ;
|
|
bOk1 = bOk1 && pCrv1->GetEndPoint( ptEnd1) && crvArc.IsPointOn( ptEnd1) ;
|
|
|
|
|
|
// calcolo arco spostando il punto iniziale di - raggio in direzione ortogonale
|
|
Point3d ptP2 = ptP - vtOrtho * crvArc.GetRadius() ;
|
|
PtrOwner<ICurve> pCrv2( GetArc2PD( ptP2, crvArc.GetCenter(), dDirStartDeg)) ;
|
|
bool bOk2 = ( ! IsNull( pCrv2)) ;
|
|
// compenso lo spostamento
|
|
bOk2 = bOk2 && pCrv2->Offset( crvArc.GetRadius(), ICurve::OFF_LEFT) ;
|
|
// verifico se il punto di tangenza sta sull'arco
|
|
Point3d ptEnd2 ;
|
|
bOk2 = bOk2 && pCrv2->GetEndPoint( ptEnd2) && crvArc.IsPointOn( ptEnd2) ;
|
|
|
|
// se due soluzioni, verifico quale ha il punto di tg più vicino al richiesto
|
|
if ( bOk1 && bOk2) {
|
|
if ( SqDist( ptEnd1, ptNearTg) <= SqDist( ptEnd2, ptNearTg))
|
|
bOk2 = false ;
|
|
else
|
|
bOk1 = false ;
|
|
}
|
|
|
|
// restituisco la soluzione
|
|
if ( bOk1)
|
|
return Release( pCrv1) ;
|
|
else if ( bOk2)
|
|
return Release( pCrv2) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static int
|
|
CalcCircleCenTgCircle( const Point3d& ptC, const Point3d& ptCen, double dRad, BIPNTVECTOR& vCenPtg)
|
|
{
|
|
// --- si lavora nel piano XY ---
|
|
|
|
// svuoto il vettore dei risultati (sono coppie centro-punto di tangenza)
|
|
vCenPtg.clear() ;
|
|
|
|
// se il raggio è negativo non ci sono soluzioni
|
|
if ( dRad < - EPS_SMALL)
|
|
return 0 ;
|
|
|
|
// versore e distanza tra i centri nel piano XY
|
|
Vector3d vtDir = ptCen - ptC ;
|
|
vtDir.z = 0 ;
|
|
double dDist = vtDir.Len() ;
|
|
vtDir /= dDist ;
|
|
|
|
// se il raggio è nullo ...
|
|
if ( dRad < EPS_SMALL) {
|
|
// se la distanza tra i punti è significativa, c'è una soluzione
|
|
if ( dDist > EPS_SMALL) {
|
|
vCenPtg.push_back( make_pair( ptC, ptCen)) ;
|
|
return 1 ;
|
|
}
|
|
// altrimenti, nessuna soluzione
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
// se questa distanza è uguale al raggio, non ci sono soluzioni
|
|
if ( fabs( dDist - dRad) < EPS_SMALL)
|
|
return 0 ;
|
|
// se è minore del raggio, c'è una sola soluzione
|
|
else if ( dDist < dRad) {
|
|
vCenPtg.push_back( make_pair( ptC, ptCen - vtDir * dRad)) ;
|
|
return 1 ;
|
|
}
|
|
// altrimenti ci sono due soluzioni
|
|
else {
|
|
vCenPtg.push_back( make_pair( ptC, ptCen - vtDir * dRad)) ;
|
|
vCenPtg.push_back( make_pair( ptC, ptCen + vtDir * dRad)) ;
|
|
return 2 ;
|
|
}
|
|
}
|