2ed2a34d55
- modifiche per DistPointLine con interfaccia portata in Include.
347 lines
14 KiB
C++
347 lines
14 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2015
|
|
//----------------------------------------------------------------------------
|
|
// File : ArcPntDirTgCurve.cpp Data : 13.03.15 Versione : 1.6c2
|
|
// Contenuto : Implementazione funzioni per calcolo arco dato punto iniziale
|
|
// direzione e tangente a curva.
|
|
//
|
|
//
|
|
// Modifiche : 13.03.15 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "CurveBezier.h"
|
|
#include "CurveComposite.h"
|
|
#include "CreateCurveAux.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EGkArcPntDirTgCurve.h"
|
|
#include "/EgtDev/Include/EGkDistPointLine.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkArcSpecial.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
static ICurve* GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
|
|
static ICurve* GetArcPntDirTgLine( const Point3d& ptP, const Vector3d& vtDir, const CurveLine& crvLine,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
|
|
static ICurve* GetArcPntDirTgArc( const Point3d& ptP, const Vector3d& vtDir, const CurveArc& crvArc,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
|
|
static ICurve* GetArcPntDirTgBezier( const Point3d& ptP, const Vector3d& vtDir, const CurveBezier& crvBezier,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
|
|
static ICurve* GetArcPntDirTgCompo( const Point3d& ptP, const Vector3d& vtDir, const CurveComposite& crvCompo,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
|
|
const Point3d& ptNear, const Vector3d& vtN)
|
|
{
|
|
return GetArcPntDirTgCurve( ptP, vtDir, cCrv, ptNear, vtN, nullptr) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
|
|
{
|
|
// verifica dei parametri
|
|
if ( &ptP == nullptr || &vtDir == nullptr || &vtN == nullptr || &cCrv == nullptr || &ptNear == nullptr)
|
|
return nullptr ;
|
|
// eseguo calcoli a seconda della curva tg
|
|
switch ( cCrv.GetType()) {
|
|
case CRV_LINE :
|
|
{ const CurveLine& crvLine = *GetBasicCurveLine( &cCrv) ;
|
|
return GetArcPntDirTgLine( ptP, vtDir, crvLine, ptNear, vtN, pPtTg) ; }
|
|
case CRV_ARC :
|
|
{ const CurveArc& crvArc = *GetBasicCurveArc( &cCrv) ;
|
|
return GetArcPntDirTgArc( ptP, vtDir, crvArc, ptNear, vtN, pPtTg) ; }
|
|
case CRV_BEZIER :
|
|
{ const CurveBezier& crvBezier = *GetBasicCurveBezier( &cCrv) ;
|
|
return GetArcPntDirTgBezier( ptP, vtDir, crvBezier, ptNear, vtN, pPtTg) ; }
|
|
case CRV_COMPO :
|
|
{ const CurveComposite& crvCompo = *GetBasicCurveComposite( &cCrv) ;
|
|
return GetArcPntDirTgCompo( ptP, vtDir, crvCompo, ptNear, vtN, pPtTg) ; }
|
|
default :
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgLine( const Point3d& ptP, const Vector3d& vtDir, const CurveLine& crvLine,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
|
|
{
|
|
// calcolo il riferimento intrinseco dell'arco da creare (DirNorm->Z e DirStart->X)
|
|
Frame3d frIntr ;
|
|
if ( ! frIntr.Set( ptP, vtN, vtDir))
|
|
return nullptr ;
|
|
|
|
// porto la linea di tangenza in questo riferimento
|
|
CurveLine crvLineL = crvLine ;
|
|
crvLineL.ToLoc( frIntr) ;
|
|
|
|
// inclinazione della linea
|
|
Point3d ptP1 = crvLineL.GetStart() ;
|
|
Point3d ptP2 = crvLineL.GetEnd() ;
|
|
// se linea perpendicolare al piano XY
|
|
if ( AreSamePointXYApprox( ptP1, ptP2)) {
|
|
Point3d ptTg( ptP1.x, ptP1.y, 0) ;
|
|
PtrOwner<ICurve> pCrv( GetArc2PD( ORIG, ptTg, 0)) ;
|
|
if ( ! IsNull( pCrv) && pCrv->ToGlob( frIntr)) {
|
|
if ( pPtTg != nullptr) {
|
|
ptTg.ToGlob( frIntr) ;
|
|
*pPtTg = ptTg ;
|
|
}
|
|
return Release( pCrv) ;
|
|
}
|
|
else
|
|
return nullptr ;
|
|
}
|
|
// se linea parallela all'asse X
|
|
else if ( abs( ptP2.y - ptP1.y) < EPS_SMALL) {
|
|
Point3d ptTg( 0, ptP1.y, ptP1.z + ( 0 - ptP1.x) * ( ptP2.z - ptP1.z) / ( ptP2.x - ptP1.x)) ;
|
|
PtrOwner<ICurve> pCrv( GetArc2PD( ORIG, ptTg, 0)) ;
|
|
if ( ! IsNull( pCrv) && pCrv->ToGlob( frIntr)) {
|
|
if ( pPtTg != nullptr) {
|
|
ptTg.ToGlob( frIntr) ;
|
|
*pPtTg = ptTg ;
|
|
}
|
|
return Release( pCrv) ;
|
|
}
|
|
else
|
|
return nullptr ;
|
|
}
|
|
// altrimenti linea inclinata
|
|
else {
|
|
// intersezione con asse X (linea di direzione nel riferimento intrinseco)
|
|
double dCoeff = ( 0 - ptP1.y) / ( ptP2.y - ptP1.y) ;
|
|
Point3d ptInt( ptP1.x + dCoeff * ( ptP2.x - ptP1.x), 0, ptP1.z + dCoeff * ( ptP2.z - ptP1.z)) ;
|
|
// punto distante da intersezione in XY come intersezione da origine
|
|
double dLenXY = abs( ptInt.x) ;
|
|
Vector3d vtDir = ptP2 - ptP1 ;
|
|
vtDir.Normalize() ;
|
|
double dLen = dLenXY * vtDir.Len() / vtDir.LenXY() ;
|
|
// con segno +
|
|
Point3d PtTg1 = ptInt + dLen * vtDir ;
|
|
PtrOwner<ICurve> pCrv1( GetArc2PD( ORIG, PtTg1, 0)) ;
|
|
bool bOk1 = ( ! IsNull( pCrv1)) ;
|
|
// porto l'arco nel riferimento locale
|
|
bOk1 = bOk1 && pCrv1->ToGlob( frIntr) ;
|
|
// recupero il punto finale (è quello di tangenza)
|
|
Point3d ptEnd1 ;
|
|
bOk1 = bOk1 && pCrv1->GetEndPoint( ptEnd1) ;
|
|
// verifico se il punto di tangenza sta sul segmento
|
|
bOk1 = bOk1 && crvLine.IsPointOn( ptEnd1) ;
|
|
// con segno -
|
|
Point3d PtTg2 = ptInt - dLen * vtDir ;
|
|
PtrOwner<ICurve> pCrv2( GetArc2PD( ORIG, PtTg2, 0)) ;
|
|
bool bOk2 = ( ! IsNull( pCrv2)) ;
|
|
// porto l'arco nel riferimento locale
|
|
bOk2 = bOk2 && pCrv2->ToGlob( frIntr) ;
|
|
// recupero il punto finale (è quello di tangenza)
|
|
Point3d ptEnd2 ;
|
|
bOk2 = bOk2 && pCrv2->GetEndPoint( ptEnd2) ;
|
|
// verifico se il punto di tangenza sta sul segmento
|
|
bOk2 = bOk2 && crvLine.IsPointOn( ptEnd2) ;
|
|
// se due soluzioni, verifico quale ha il punto di tg più vicino al richiesto
|
|
if ( bOk1 && bOk2) {
|
|
if ( SqDist( ptEnd1, ptNear) <= SqDist( ptEnd2, ptNear))
|
|
bOk2 = false ;
|
|
else
|
|
bOk1 = false ;
|
|
}
|
|
// restituisco la soluzione
|
|
if ( bOk1) {
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptEnd1 ;
|
|
return Release( pCrv1) ;
|
|
}
|
|
else if ( bOk2) {
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptEnd2 ;
|
|
return Release( pCrv2) ;
|
|
}
|
|
else
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgArc( const Point3d& ptP, const Vector3d& vtDir, const CurveArc& crvArc,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
|
|
{
|
|
// verifico che la normale della circonferenza coincida con quella dell'arco di tg
|
|
if ( ! AreSameOrOppositeVectorApprox( vtN, crvArc.GetNormVersor()))
|
|
return nullptr ;
|
|
|
|
// calcolo il riferimento intrinseco dell'arco da creare (DirNorm->Z e DirStart->X)
|
|
Frame3d frIntr ;
|
|
if ( ! frIntr.Set( ptP, vtN, vtDir))
|
|
return nullptr ;
|
|
|
|
// porto l'arco di tangenza in questo riferimento
|
|
CurveArc crvArcL = crvArc ;
|
|
crvArcL.ToLoc( frIntr) ;
|
|
|
|
// versore ortogonale alla direzione iniziale (ora si lavora nel piano XY locale)
|
|
Vector3d vtOrtho = Y_AX ;
|
|
|
|
// angolo direzione iniziale
|
|
bool bOutSide = ( DistXY( ORIG, crvArcL.GetCenter()) >= crvArcL.GetRadius()) ;
|
|
|
|
// calcolo arco spostando il punto iniziale di + raggio in direzione ortogonale
|
|
Point3d ptP1 = ORIG + vtOrtho * crvArcL.GetRadius() ;
|
|
PtrOwner<ICurve> pCrv1( GetArc2PD( ptP1, crvArcL.GetCenter(), ( bOutSide ? 0 : 180))) ;
|
|
bool bOk1 = ( ! IsNull( pCrv1)) ;
|
|
// compenso lo spostamento ( più -> offset a destra)
|
|
if ( bOk1) {
|
|
double dOffset = ( bOutSide ? crvArcL.GetRadius() : - crvArcL.GetRadius()) ;
|
|
if ( pCrv1->GetType() == CRV_ARC)
|
|
bOk1 = (static_cast<CurveArc*>( Get( pCrv1)))->ExtendedOffset( dOffset) ;
|
|
else
|
|
bOk1 = pCrv1->SimpleOffset( dOffset) ;
|
|
}
|
|
// porto l'arco nel riferimento locale
|
|
bOk1 = bOk1 && pCrv1->ToGlob( frIntr) ;
|
|
// recupero il punto finale (è quello di tangenza)
|
|
Point3d ptEnd1 ;
|
|
bOk1 = bOk1 && pCrv1->GetEndPoint( ptEnd1) ;
|
|
// se l'arco di tangenza ha deltaN, devo considerarne quota parte
|
|
if ( bOk1 && abs( crvArc.GetDeltaN()) > EPS_SMALL) {
|
|
double dAngDeg ;
|
|
if ( crvArc.CalcPointAngle( ptEnd1, dAngDeg)) {
|
|
ptEnd1 += crvArc.GetNormVersor() * crvArc.GetDeltaN() * dAngDeg / crvArc.GetAngCenter() ;
|
|
bOk1 = bOk1 && pCrv1->ModifyEnd( ptEnd1) ;
|
|
}
|
|
else
|
|
bOk1 = false ;
|
|
}
|
|
// verifico se il punto di tangenza sta sull'arco
|
|
else
|
|
bOk1 = bOk1 && crvArc.IsPointOn( ptEnd1) ;
|
|
|
|
// calcolo arco spostando il punto iniziale di - raggio in direzione ortogonale
|
|
Point3d ptP2 = ORIG - vtOrtho * crvArcL.GetRadius() ;
|
|
PtrOwner<ICurve> pCrv2( GetArc2PD( ptP2, crvArcL.GetCenter(), ( bOutSide ? 0 : 180))) ;
|
|
bool bOk2 = ( ! IsNull( pCrv2)) ;
|
|
// compenso lo spostamento ( meno -> offset a sinistra)
|
|
if ( bOk2) {
|
|
double dOffset = ( bOutSide ? - crvArcL.GetRadius() : crvArcL.GetRadius()) ;
|
|
if ( pCrv2->GetType() == CRV_ARC)
|
|
bOk2 = (static_cast<CurveArc*>( Get( pCrv2)))->ExtendedOffset( dOffset) ;
|
|
else
|
|
bOk2 = pCrv2->SimpleOffset( dOffset) ;
|
|
}
|
|
// porto l'arco nel riferimento locale
|
|
bOk2 = bOk2 && pCrv2->ToGlob( frIntr) ;
|
|
// recupero il punto finale (è quello di tangenza)
|
|
Point3d ptEnd2 ;
|
|
bOk2 = bOk2 && pCrv2->GetEndPoint( ptEnd2) ;
|
|
// se l'arco di tangenza ha deltaN, devo considerarne quota parte
|
|
if ( bOk2 && abs( crvArc.GetDeltaN()) > EPS_SMALL) {
|
|
double dAngDeg ;
|
|
if ( crvArc.CalcPointAngle( ptEnd2, dAngDeg)) {
|
|
ptEnd2 += crvArc.GetNormVersor() * crvArc.GetDeltaN() * dAngDeg / crvArc.GetAngCenter() ;
|
|
bOk2 = bOk2 && pCrv2->ModifyEnd( ptEnd2) ;
|
|
}
|
|
else
|
|
bOk2 = false ;
|
|
}
|
|
// verifico se il punto di tangenza sta sull'arco
|
|
else
|
|
bOk2 = bOk2 && crvArc.IsPointOn( ptEnd2) ;
|
|
|
|
// se due soluzioni, verifico quale ha il punto di tg più vicino al richiesto
|
|
if ( bOk1 && bOk2) {
|
|
if ( SqDist( ptEnd1, ptNear) <= SqDist( ptEnd2, ptNear))
|
|
bOk2 = false ;
|
|
else
|
|
bOk1 = false ;
|
|
}
|
|
|
|
// restituisco la soluzione
|
|
if ( bOk1) {
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptEnd1 ;
|
|
return Release( pCrv1) ;
|
|
}
|
|
else if ( bOk2) {
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptEnd2 ;
|
|
return Release( pCrv2) ;
|
|
}
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgBezier( const Point3d& ptP, const Vector3d& vtDir, const CurveBezier& crvBezier,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
|
|
{
|
|
// calcolo approssimazione della curva di Bezier con archi e rette
|
|
PolyArc PA ;
|
|
if ( ! crvBezier.ApproxWithArcs( 10 * EPS_SMALL, ANG_TOL_STD_DEG, PA))
|
|
return nullptr ;
|
|
// la trasformo in curva composita
|
|
PtrOwner<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyArc( PA))
|
|
return nullptr ;
|
|
// calcolo la circonferenza tangente a questa approssimazione
|
|
Point3d ptTg ;
|
|
PtrOwner<ICurve> pCrv( GetArcPntDirTgCurve( ptP, vtDir, *pCrvCompo, ptNear, vtN, &ptTg)) ;
|
|
if ( IsNull( pCrv))
|
|
return nullptr ;
|
|
// porto il punto di tangenza della circonferenza esattamente sulla curva di Bezier
|
|
DistPointCurve dstPtCurve( ptTg, crvBezier) ;
|
|
Point3d ptTg2 ;
|
|
int nFlag ;
|
|
if ( ! dstPtCurve.GetMinDistPoint( 0, ptTg2, nFlag))
|
|
return nullptr ;
|
|
// calcolo il nuovo arco
|
|
pCrv.Set( GetArc2PVN( ptP, ptTg2, vtDir, vtN)) ;
|
|
if ( IsNull( pCrv))
|
|
return nullptr ;
|
|
// se richiesto, assegno il punto di tg
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptTg2 ;
|
|
// restituisco la circonferenza
|
|
return Release( pCrv) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
GetArcPntDirTgCompo( const Point3d& ptP, const Vector3d& vtDir, const CurveComposite& crvCompo,
|
|
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
|
|
{
|
|
// ciclo sulla curva composita
|
|
double dMinSqDist = SQ_INFINITO ;
|
|
PtrOwner<ICurve> pCrvNew ;
|
|
for ( const ICurve* pCrv = crvCompo.GetFirstCurve() ;
|
|
pCrv != nullptr ;
|
|
pCrv = crvCompo.GetNextCurve()) {
|
|
// recupero la circonferenza tangente alla curva elementare
|
|
Point3d ptTg ;
|
|
PtrOwner<ICurve> pCrvTmp( GetArcPntDirTgCurve( ptP, vtDir, *pCrv, ptNear, vtN, &ptTg)) ;
|
|
if ( IsNull( pCrvTmp))
|
|
continue ;
|
|
// verifico se è la più vicina al punto desiderato
|
|
double dSqDist = SqDist( ptNear, ptTg) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
pCrvNew.Set( pCrvTmp) ;
|
|
if ( pPtTg != nullptr)
|
|
*pPtTg = ptTg ;
|
|
}
|
|
}
|
|
|
|
return Release( pCrvNew) ;
|
|
} |