63fb9a638b
- a SimpleOffset di Curve aggiunto parametro opzionale dMaxAngExt (angolo esterno oltre il quale estendi diventa smussa) con default 90deg.
2311 lines
71 KiB
C++
2311 lines
71 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2014-2018
|
|
//----------------------------------------------------------------------------
|
|
// File : CurveArc.cpp Data : 23.11.18 Versione : 1.9k2
|
|
// Contenuto : Implementazione della classe Arco di Circonferenza.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 16.04.13 DS Creazione modulo.
|
|
// 03.01.16 DS Agg. SetCPA e SetCPAN.
|
|
// 23.11.18 DS Corretta ApproxWithArcs ora vtExtr assegnato.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveComposite.h"
|
|
#include "DistPointArc.h"
|
|
#include "PolygonPlane.h"
|
|
#include "GeoConst.h"
|
|
#include "GeoObjFactory.h"
|
|
#include "NgeWriter.h"
|
|
#include "NgeReader.h"
|
|
#include "Voronoi.h"
|
|
#include "/EgtDev/Include/EGkAngle.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EGkUiUnits.h"
|
|
#include "/EgtDev/Include/ENkPolynomialRoots.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <new>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
GEOOBJ_REGISTER( CRV_ARC, NGE_C_ARC, CurveArc) ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
class ArcApproxer
|
|
{
|
|
public :
|
|
ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc) ;
|
|
bool GetPoint( double& dU, Point3d& ptP) ;
|
|
|
|
private :
|
|
Point3d m_PtCen ;
|
|
Vector3d m_VtN ;
|
|
double m_dRad ;
|
|
double m_dDeltaN ;
|
|
Vector3d m_vtA1 ;
|
|
Vector3d m_vtA2 ;
|
|
double m_dCosA ;
|
|
double m_dSinA ;
|
|
int m_nTotPnt ;
|
|
int m_nCurrPnt ;
|
|
bool m_bInside ;
|
|
} ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveArc::CurveArc( void)
|
|
: m_nStatus( TO_VERIFY), m_PtCen(), m_VtN(), m_VtS(), m_dRad(),
|
|
m_dAngCenDeg(), m_dDeltaN(), m_VtExtr(), m_dThick(), m_nTempProp{0,0}, m_dTempParam{0.0, 0.0}, m_pVoronoiObj( nullptr)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveArc::~CurveArc( void)
|
|
{
|
|
ResetVoronoiObject() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set generico, richiede tutti i parametri
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set( const Point3d& ptCen, const Vector3d& vtN, double dRad,
|
|
const Vector3d& vtS, double dAngCenDeg, double dDeltaN)
|
|
{
|
|
// assegno i dati
|
|
m_PtCen = ptCen ;
|
|
m_VtN = vtN ;
|
|
m_VtS = vtS ;
|
|
m_dRad = dRad ;
|
|
m_dAngCenDeg = dAngCenDeg ;
|
|
m_dDeltaN = dDeltaN ;
|
|
m_nStatus = TO_VERIFY ;
|
|
|
|
// sistemo i versori
|
|
m_VtN.Normalize() ;
|
|
m_VtS.Normalize() ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per circonferenza completa
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set( const Point3d& ptCen, const Vector3d& vtN, double dRad)
|
|
{
|
|
// assegno e calcolo i dati
|
|
m_PtCen = ptCen ;
|
|
m_VtN = vtN ;
|
|
m_VtN.Normalize() ;
|
|
Frame3d frF ;
|
|
if ( ! frF.Set( ORIG, vtN))
|
|
return false ;
|
|
m_VtS = frF.VersX() ;
|
|
m_dRad = dRad ;
|
|
m_dAngCenDeg = ANG_FULL ;
|
|
m_dDeltaN = 0 ;
|
|
m_nStatus = TO_VERIFY ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza nel piano XY
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetXY( const Point3d& ptCen, double dRad, double dAngIniDeg, double dAngCenDeg, double dDeltaZ)
|
|
{
|
|
// assegno e calcolo i dati
|
|
m_PtCen = ptCen ;
|
|
m_VtN = Z_AX ;
|
|
m_VtS = FromPolar( 1, dAngIniDeg) ;
|
|
m_dRad = dRad ;
|
|
m_dAngCenDeg = dAngCenDeg ;
|
|
m_dDeltaN = dDeltaZ ;
|
|
m_nStatus = TO_VERIFY ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per circonferenza completa nel piano XY
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetXY( const Point3d& ptCen, double dRad)
|
|
{
|
|
// assegno e calcolo i dati
|
|
m_PtCen = ptCen ;
|
|
m_VtN = Z_AX ;
|
|
m_VtS = X_AX ;
|
|
m_dRad = dRad ;
|
|
m_dAngCenDeg = ANG_FULL ;
|
|
m_dDeltaN = 0 ;
|
|
m_nStatus = TO_VERIFY ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonf. o circonferenza completa per 3 Punti
|
|
// ( algoritmo da Comp. Geom. di Faux e Pratt pagg. 67 e 68 )
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set3P( const Point3d& ptStart, const Point3d& ptOther, const Point3d& ptEnd, bool bCirc)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// vettori dal primo punto agli altri due
|
|
Vector3d vtA = ptOther - ptStart ;
|
|
Vector3d vtB = ptEnd - ptStart ;
|
|
// calcolo del versore normale
|
|
m_VtN = vtA ^ vtB ;
|
|
double dNSqLen = m_VtN.SqLen() ;
|
|
// se i punti sono praticamente allineati non si può calcolare la circonferenza
|
|
if ( ! m_VtN.Normalize( EPS_ZERO))
|
|
return false ;
|
|
// calcolo del centro
|
|
m_PtCen = ptStart + ( vtB.SqLen() * ( vtA.SqLen() - vtA * vtB) * vtA +
|
|
vtA.SqLen() * ( vtB.SqLen() - vtA * vtB) * vtB) / ( 2 * dNSqLen) ;
|
|
// calcolo del versore start e del raggio
|
|
m_VtS = ptStart - m_PtCen ;
|
|
m_dRad = m_VtS.Len() ;
|
|
if ( m_dRad < EPS_SMALL)
|
|
return false ;
|
|
m_VtS /= m_dRad ;
|
|
// calcolo dell'angolo al centro
|
|
if ( bCirc)
|
|
m_dAngCenDeg = ANG_FULL ;
|
|
else {
|
|
// calcolo dell'angolo di rotazione attorno al centro dal primo al secondo punto
|
|
bool bDet1 ;
|
|
double dAng1Deg ;
|
|
if ( ! m_VtS.GetRotation( ( ptOther - m_PtCen), m_VtN, dAng1Deg, bDet1) || ! bDet1)
|
|
return false ;
|
|
// calcolo dell'angolo di rotazione attorno al centro dal primo al terzo punto
|
|
bool bDet2 ;
|
|
double dAng2Deg ;
|
|
if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, dAng2Deg, bDet2) || ! bDet2)
|
|
return false ;
|
|
// deduzione dell'angolo al centro
|
|
// se uno dei due angoli è nullo, errore
|
|
if ( abs( dAng1Deg) < EPS_ANG_SMALL || abs( dAng2Deg) < EPS_ANG_SMALL)
|
|
return false ;
|
|
// se i due angoli hanno lo stesso segno e Ang1 è minore di Ang2 in modulo
|
|
else if ( dAng1Deg * dAng2Deg > 0 && abs( dAng1Deg) < abs( dAng2Deg))
|
|
m_dAngCenDeg = dAng2Deg ;
|
|
// altrimenti hanno segno opposto oppure Ang1 è maggiore di Ang2 in modulo
|
|
else
|
|
m_dAngCenDeg = - _copysign( ANG_FULL, dAng2Deg) + dAng2Deg ;
|
|
}
|
|
// non c'è DeltaN
|
|
m_dDeltaN = 0 ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonf. definito dagli estremi, versore normale e bulge
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set2PNB( const Point3d& ptIni, const Point3d& ptFin, const Vector3d& vtN, double dBulge)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// versore normale
|
|
m_VtN = vtN ;
|
|
if ( ! m_VtN.Normalize())
|
|
return false ;
|
|
// vettore da inizio a fine
|
|
Vector3d vtDiff = ptFin - ptIni ;
|
|
if ( vtDiff.IsSmall())
|
|
return false ;
|
|
// deltaN eventuale ( è componente parallela a VtN)
|
|
m_dDeltaN = vtDiff * m_VtN ;
|
|
vtDiff -= m_dDeltaN * m_VtN ;
|
|
if ( abs( m_dDeltaN) < EPS_SMALL)
|
|
m_dDeltaN = 0 ;
|
|
// verifico sia un arco (uso la lunghezza della saetta)
|
|
double dDist = vtDiff.Len() ;
|
|
if ( abs( dBulge * 0.5 * dDist) < EPS_ZERO)
|
|
return false ;
|
|
// calcolo del centro
|
|
Vector3d vtOrtho = vtDiff ;
|
|
// ruoto di +90 deg attorno a vtN (la moltiplica successiva tiene conto del segno di bulge)
|
|
vtOrtho.Rotate( m_VtN, 0, 1) ;
|
|
vtOrtho *= ( 1 - dBulge * dBulge) / ( 4 * dBulge) ;
|
|
m_PtCen = ptIni + 0.5 * vtDiff + vtOrtho ;
|
|
// calcolo il raggio
|
|
m_dRad = abs( dDist * ( 1 + dBulge * dBulge) / ( 4 * dBulge)) ;
|
|
// calcolo il versore iniziale
|
|
m_VtS = ptIni - m_PtCen ;
|
|
m_VtS.Normalize() ;
|
|
// calcolo l'angolo al centro
|
|
m_dAngCenDeg = 4 * atan( dBulge) * RADTODEG ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza nel piano XY con ptStart, ptEnd, dirStart
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStartDeg)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// vettore tangente iniziale ( nel piano XY)
|
|
Vector3d vtA = FromPolar( 1, dDirStartDeg) ;
|
|
// vettore da inizio a fine ( nel piano XY)
|
|
Vector3d vtB = ptEnd - ptStart ;
|
|
vtB.z = 0 ;
|
|
// calcolo del versore normale
|
|
m_VtN = vtA ^ vtB ;
|
|
double dNSqLen = m_VtN.SqLen() ;
|
|
// se tangente e punti sono praticamente allineati non si può calcolare la circonferenza
|
|
if ( ! m_VtN.Normalize( EPS_ZERO))
|
|
return false ;
|
|
// calcolo del centro
|
|
m_PtCen = ptStart + vtB.SqLen() * ( vtB - ( vtA * vtB) * vtA) / ( 2 * dNSqLen) ;
|
|
// calcolo del versore start e del raggio
|
|
m_VtS = ptStart - m_PtCen ;
|
|
m_dRad = m_VtS.Len() ;
|
|
if ( m_dRad < EPS_SMALL)
|
|
return false ;
|
|
m_VtS /= m_dRad ;
|
|
// calcolo dell'angolo al centro
|
|
// angolo di rotazione da start a end
|
|
bool bDet1 ;
|
|
double dAng1Deg ;
|
|
if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, dAng1Deg, bDet1) || ! bDet1)
|
|
return false ;
|
|
// poichè il senso di rotazione è sempre CCW, se l'angolo è negativo prendo il suo complemento al giro
|
|
if ( dAng1Deg < 0)
|
|
m_dAngCenDeg = ANG_FULL + dAng1Deg ;
|
|
else
|
|
m_dAngCenDeg = dAng1Deg ;
|
|
// DeltaN
|
|
m_dDeltaN = ( ptEnd.z - ptStart.z) * m_VtN.z ;
|
|
|
|
// se normale con Z negativa, inverto senza modificare la geometria
|
|
if ( m_VtN.z < 0) {
|
|
m_VtN.Invert() ;
|
|
m_dAngCenDeg = - m_dAngCenDeg ;
|
|
m_dDeltaN = - m_dDeltaN ;
|
|
}
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza in un piano generico con ptStart, ptEnd, vtDirStart, vtN
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set2PVN( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDirS, const Vector3d& vtN)
|
|
{
|
|
// calcolo il riferimento OCS derivato da vtN
|
|
Frame3d frOcs ;
|
|
if ( ! frOcs.Set( ORIG, vtN))
|
|
return false ;
|
|
// porto i punti in questo riferimento
|
|
Point3d ptSloc = ptStart ;
|
|
ptSloc.ToLoc( frOcs) ;
|
|
Point3d ptEloc = ptEnd ;
|
|
ptEloc.ToLoc( frOcs) ;
|
|
// porto la direzione in questo riferimento e verifico che definisca un angolo nel piano
|
|
Vector3d vtSloc = vtDirS ;
|
|
vtSloc.ToLoc( frOcs) ;
|
|
if ( abs( vtSloc.x) < EPS_SMALL && abs( vtSloc.y) < EPS_SMALL)
|
|
return false ;
|
|
double dDirStartDeg ;
|
|
vtSloc.ToSpherical( nullptr, nullptr, &dDirStartDeg) ;
|
|
// calcolo l'arco in questo piano
|
|
if ( ! Set2PD( ptSloc, ptEloc, dDirStartDeg))
|
|
return false ;
|
|
// riporto l'arco nel riferimento naturale
|
|
return ToGlob( frOcs) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza nel piano XY con ptStart, ptEnd, dRad, bCCW
|
|
// ( si suppone |dAngCenDeg| <= 180deg)
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set2PRS( const Point3d& ptStart, const Point3d& ptEnd, double dRad, bool bCCW)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// il piano dell'arco coincide con XY
|
|
m_VtN = Z_AX ;
|
|
m_dDeltaN = ptEnd.z - ptStart.z ;
|
|
// semi-vettore da inizio a fine
|
|
Vector3d vtA = 0.5 * ( ptEnd - ptStart) ;
|
|
vtA.z = 0 ;
|
|
double dLenA = vtA.Len() ;
|
|
if ( dLenA < EPS_ZERO || dLenA > ( dRad + EPS_ZERO))
|
|
return false ;
|
|
// distanza del centro dalla corda tra inizio e fine
|
|
double dLenH ;
|
|
if ( dLenA > ( dRad - EPS_ZERO))
|
|
dLenH = 0 ;
|
|
else
|
|
dLenH = sqrt( dRad * dRad - dLenA * dLenA) ;
|
|
// versore dal punto medio della corda al centro
|
|
Vector3d vtH = vtA / dLenA ;
|
|
vtH.Rotate( Z_AX, 0, ( bCCW ? 1 : -1)) ;
|
|
// calcolo del centro
|
|
m_PtCen = ptStart + vtA + vtH * dLenH ;
|
|
// assegno il raggio
|
|
if ( dRad < EPS_ZERO)
|
|
return false ;
|
|
m_dRad = dRad ;
|
|
// calcolo il versore di start
|
|
m_VtS = ( ptStart - m_PtCen) / m_dRad ;
|
|
m_VtS.Normalize() ;
|
|
// calcolo l'angolo al centro
|
|
bool bDet ;
|
|
if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, m_dAngCenDeg, bDet) || ! bDet)
|
|
return false ;
|
|
// quando è 180deg il segno è determinato solo dal senso
|
|
if ( abs( m_dAngCenDeg - ANG_STRAIGHT) < 10 * EPS_ANG_SMALL &&
|
|
( ( bCCW && m_dAngCenDeg < 0) ||
|
|
( ! bCCW && m_dAngCenDeg > 0)))
|
|
m_dAngCenDeg = - m_dAngCenDeg ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza in un piano generico con ptStart, ptEnd, vtN, dRad, bCCW
|
|
// ( si suppone |dAngCenDeg| <= 180deg)
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Set2PNRS( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtN, double dRad, bool bCCW)
|
|
{
|
|
// calcolo il riferimento OCS derivato da vtN
|
|
Frame3d frOcs ;
|
|
if ( ! frOcs.Set( ORIG, vtN))
|
|
return false ;
|
|
// porto i punti in questo riferimento
|
|
Point3d ptSloc = ptStart ;
|
|
ptSloc.ToLoc( frOcs) ;
|
|
Point3d ptEloc = ptEnd ;
|
|
ptEloc.ToLoc( frOcs) ;
|
|
// calcolo l'arco in questo piano
|
|
if ( ! Set2PRS( ptSloc, ptEloc, dRad, bCCW))
|
|
return false ;
|
|
// riporto l'arco nel riferimento naturale
|
|
return ToGlob( frOcs) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza nel piano XY con ptCen, ptStart, dAngCenDeg, dDeltaZ
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetCPA( const Point3d& ptCen, const Point3d& ptStart, double dAngCenDeg, double dDeltaZ)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// il piano dell'arco coincide con XY
|
|
m_VtN = Z_AX ;
|
|
m_dDeltaN = dDeltaZ ;
|
|
// assegno il centro
|
|
m_PtCen = ptCen ;
|
|
m_PtCen.z = ptStart.z ;
|
|
// assegno il versore iniziale e il raggio
|
|
m_VtS = ptStart - m_PtCen ;
|
|
m_dRad = m_VtS.Len() ;
|
|
if ( m_dRad < EPS_ZERO)
|
|
return false ;
|
|
m_VtS /= m_dRad ;
|
|
// assegno l'angolo al centro
|
|
m_dAngCenDeg = dAngCenDeg ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza in un piano generico con ptCen, ptStart, dAngCenDeg, dDeltaZ, vtN
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetCPAN( const Point3d& ptCen, const Point3d& ptStart, double dAngCenDeg, double dDeltaZ, const Vector3d& vtN)
|
|
{
|
|
// calcolo il riferimento OCS derivato da vtN
|
|
Frame3d frOcs ;
|
|
if ( ! frOcs.Set( ORIG, vtN))
|
|
return false ;
|
|
// porto i punti in questo riferimento
|
|
Point3d ptCloc = ptCen ;
|
|
ptCloc.ToLoc( frOcs) ;
|
|
Point3d ptSloc = ptStart ;
|
|
ptSloc.ToLoc( frOcs) ;
|
|
// calcolo l'arco in questo piano
|
|
if ( ! SetCPA( ptCloc, ptSloc, dAngCenDeg, dDeltaZ))
|
|
return false ;
|
|
// riporto l'arco nel riferimento naturale
|
|
return ToGlob( frOcs) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza nel piano XY con ptCen, ptStart, ptNearEnd
|
|
// ( si suppone |dAngCenDeg| <= 180deg)
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetC2P( const Point3d& ptCen, const Point3d& ptStart, const Point3d& ptNearEnd)
|
|
{
|
|
// arco non ancora definito correttamente
|
|
m_nStatus = ERR ;
|
|
|
|
// il piano dell'arco coincide con XY
|
|
m_VtN = Z_AX ;
|
|
m_dDeltaN = ptNearEnd.z - ptStart.z ;
|
|
// assegno il centro
|
|
m_PtCen = ptCen ;
|
|
m_PtCen.z = ptStart.z ;
|
|
// assegno il versore iniziale e il raggio
|
|
m_VtS = ptStart - m_PtCen ;
|
|
m_dRad = m_VtS.Len() ;
|
|
if ( m_dRad < EPS_ZERO)
|
|
return false ;
|
|
m_VtS /= m_dRad ;
|
|
// calcolo l'angolo al centro (la funzione trova sempre il più piccolo)
|
|
bool bDet ;
|
|
if ( ! m_VtS.GetRotation( ( ptNearEnd - m_PtCen), m_VtN, m_dAngCenDeg, bDet) || ! bDet)
|
|
return false ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set per arco di circonferenza in un piano generico con ptCen, ptStart, ptNearEnd, vtN
|
|
// ( si suppone |dAngCenDeg| <= 180deg)
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SetC2PN( const Point3d& ptCen, const Point3d& ptStart, const Point3d& ptNearEnd, const Vector3d& vtN)
|
|
{
|
|
// calcolo il riferimento OCS derivato da vtN
|
|
Frame3d frOcs ;
|
|
if ( ! frOcs.Set( ORIG, vtN))
|
|
return false ;
|
|
// porto i punti in questo riferimento
|
|
Point3d ptCloc = ptCen ;
|
|
ptCloc.ToLoc( frOcs) ;
|
|
Point3d ptSloc = ptStart ;
|
|
ptSloc.ToLoc( frOcs) ;
|
|
Point3d ptNEloc = ptNearEnd ;
|
|
ptNEloc.ToLoc( frOcs) ;
|
|
// calcolo l'arco in questo piano
|
|
if ( ! SetC2P( ptCloc, ptSloc, ptNEloc))
|
|
return false ;
|
|
// riporto l'arco nel riferimento naturale
|
|
return ToGlob( frOcs) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveArc*
|
|
CurveArc::Clone( void) const
|
|
{
|
|
// alloco oggetto
|
|
CurveArc* pCrv = new( nothrow) CurveArc ;
|
|
if ( pCrv != nullptr) {
|
|
if ( ! pCrv->CopyFrom( *this)) {
|
|
delete pCrv ;
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
return pCrv ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::CopyFrom( const IGeoObj* pGObjSrc)
|
|
{
|
|
const CurveArc* pCA = GetBasicCurveArc( pGObjSrc) ;
|
|
if ( pCA == nullptr)
|
|
return false ;
|
|
return CopyFrom( *pCA) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::CopyFrom( const CurveArc& caSrc)
|
|
{
|
|
if ( &caSrc == this)
|
|
return true ;
|
|
m_VtExtr = caSrc.m_VtExtr ;
|
|
m_dThick = caSrc.m_dThick ;
|
|
m_nTempProp[0] = caSrc.m_nTempProp[0] ;
|
|
m_nTempProp[1] = caSrc.m_nTempProp[1] ;
|
|
m_dTempParam[0] = caSrc.m_dTempParam[0] ;
|
|
m_dTempParam[1] = caSrc.m_dTempParam[1] ;
|
|
return Set( caSrc.m_PtCen, caSrc.m_VtN, caSrc.m_dRad,
|
|
caSrc.m_VtS, caSrc.m_dAngCenDeg, caSrc.m_dDeltaN) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
GeoObjType
|
|
CurveArc::GetType( void) const
|
|
{
|
|
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( CurveArc)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const string&
|
|
CurveArc::GetTitle( void) const
|
|
{
|
|
static const string sTitle = "Arc" ;
|
|
return sTitle ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Dump( string& sOut, bool bMM, const char* szNewLine) const
|
|
{
|
|
// dati generali di una curva
|
|
if ( ! CurveDump( *this, sOut, bMM, szNewLine))
|
|
return false ;
|
|
// parametri : Centro, Normale, DirStart, Rad, AngCenDeg, DeltaN
|
|
sOut += "C(" + ToString( GetInUiUnits( m_PtCen, bMM), 3) + ") " + szNewLine ;
|
|
sOut += "VN(" + ToString( m_VtN, 6) + ") " + szNewLine ;
|
|
sOut += "VS(" + ToString( m_VtS, 6) + ") " + szNewLine ;
|
|
sOut += "R=" + ToString( GetInUiUnits( m_dRad, bMM), 3) ;
|
|
sOut += " Ac=" + ToString( m_dAngCenDeg, 3) ;
|
|
sOut += " Dn=" + ToString( GetInUiUnits( m_dDeltaN, bMM), 3) + szNewLine ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
CurveArc::GetNgeId( void) const
|
|
{
|
|
return GEOOBJ_GETNGEID( CurveArc) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Save( NgeWriter& ngeOut) const
|
|
{
|
|
// centro
|
|
if ( ! ngeOut.WritePoint( m_PtCen, ";"))
|
|
return false ;
|
|
// versore Normale
|
|
if ( ! ngeOut.WriteVector( m_VtN, ";"))
|
|
return false ;
|
|
// raggio
|
|
if ( ! ngeOut.WriteDouble( m_dRad, ";"))
|
|
return false ;
|
|
// versore Iniziale
|
|
if ( ! ngeOut.WriteVector( m_VtS, ";"))
|
|
return false ;
|
|
// angolo al centro
|
|
int nDec = ( m_dRad < 0.1 * BIG_ARC_RAD ? 6 : 9) ;
|
|
if ( ! ngeOut.WriteDouble( m_dAngCenDeg, ";", false, nDec))
|
|
return false ;
|
|
// deltaN
|
|
if ( ! ngeOut.WriteDouble( m_dDeltaN, ";", true))
|
|
return false ;
|
|
// da versione 1008 : linea con VtEstrusione e Spessore
|
|
if ( ! ngeOut.WriteVector( m_VtExtr, ";"))
|
|
return false ;
|
|
if ( ! ngeOut.WriteDouble( m_dThick, ";", true))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Load( NgeReader& ngeIn)
|
|
{
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// leggo la prossima linea ( 6 parametri)
|
|
// recupero il centro
|
|
if ( ! ngeIn.ReadPoint( m_PtCen, ";"))
|
|
return false ;
|
|
// recupero il versore normale
|
|
if ( ! ngeIn.ReadVector( m_VtN, ";"))
|
|
return false ;
|
|
// recupero il raggio
|
|
if ( ! ngeIn.ReadDouble( m_dRad, ";"))
|
|
return false ;
|
|
// recupero il versore iniziale
|
|
if ( ! ngeIn.ReadVector( m_VtS, ";"))
|
|
return false ;
|
|
m_VtS.Normalize() ; // per garantire la precisione con raggi grandi
|
|
// recupero l'angolo al centro
|
|
if ( ! ngeIn.ReadDouble( m_dAngCenDeg, ";"))
|
|
return false ;
|
|
// recupero il delta N
|
|
if ( ! ngeIn.ReadDouble( m_dDeltaN, ";", true))
|
|
return false ;
|
|
// da versione 1008 : linea con VtEstrusione e Spessore
|
|
if ( ngeIn.GetFileVersion() >= NGE_VER_1008) {
|
|
if ( ! ngeIn.ReadVector( m_VtExtr, ";"))
|
|
return false ;
|
|
if ( ! ngeIn.ReadDouble( m_dThick, ";", true))
|
|
return false ;
|
|
}
|
|
// eseguo validazione
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
|
|
{
|
|
// richiamo della funzione generale
|
|
return GetBBox( GLOB_FRM, b3Loc, nFlag) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del frame
|
|
if ( frRef.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
// assegno il box nel riferimento
|
|
b3Ref.Reset() ;
|
|
|
|
// ricavo il riferimento intrinseco dell'arco
|
|
Frame3d frArc;
|
|
frArc.Set( m_PtCen, ( m_dAngCenDeg > 0 ? m_VtN : -m_VtN), m_VtS) ;
|
|
|
|
// pendenza intrinseca
|
|
double dPitch = m_dDeltaN * ( m_dAngCenDeg > 0 ? 1 : -1) / abs( m_dAngCenDeg * DEGTORAD) ;
|
|
|
|
// cordinate nel frRef dei versori del sistema di riferimento dell'arco
|
|
Vector3d vtXRef = frArc.VersX() ;
|
|
vtXRef.ToGlob( frRef) ;
|
|
Vector3d vtYRef = frArc.VersY() ;
|
|
vtYRef.ToGlob( frRef) ;
|
|
Vector3d vtZRef = frArc.VersZ() ;
|
|
vtZRef.ToGlob( frRef) ;
|
|
|
|
// il punto iniziale e finale sono punti candidati per estremanti
|
|
Point3d ptS, ptE ;
|
|
GetStartPoint( ptS) ;
|
|
ptS.ToGlob( frRef) ;
|
|
b3Ref.Add( ptS) ;
|
|
GetEndPoint( ptE) ;
|
|
ptE.ToGlob( frRef) ;
|
|
b3Ref.Add( ptE) ;
|
|
|
|
// vettore degli angoli dei punti candidati estremi
|
|
DBLVECTOR vdTheta ;
|
|
|
|
// arco piatto
|
|
if ( abs( dPitch) < EPS_SMALL) {
|
|
double dAngXDeg = atan2( vtYRef.x, vtXRef.x) * RADTODEG ;
|
|
bool bAngXSmall = (abs( dAngXDeg) <= EPS_ANG_ZERO) ;
|
|
if ( ! bAngXSmall) {
|
|
vdTheta.push_back( dAngXDeg) ;
|
|
vdTheta.push_back( dAngXDeg + ANG_STRAIGHT) ;
|
|
}
|
|
double dAngYDeg = atan2( vtYRef.y, vtXRef.y) * RADTODEG ;
|
|
bool bAngYSmall = (abs( dAngYDeg) <= EPS_ANG_ZERO) ;
|
|
if ( ! bAngYSmall) {
|
|
vdTheta.push_back( dAngYDeg) ;
|
|
vdTheta.push_back( dAngYDeg + ANG_STRAIGHT) ;
|
|
}
|
|
double dAngZDeg = atan2( vtYRef.z, vtXRef.z) * RADTODEG ;
|
|
bool bAngZSmall = (abs( dAngZDeg) <= EPS_ANG_ZERO) ;
|
|
if ( ! bAngZSmall) {
|
|
vdTheta.push_back( dAngZDeg) ;
|
|
vdTheta.push_back( dAngZDeg + ANG_STRAIGHT) ;
|
|
}
|
|
if ( bAngXSmall || bAngYSmall || bAngZSmall)
|
|
vdTheta.push_back( ANG_STRAIGHT) ;
|
|
}
|
|
// altrimenti arco di elica
|
|
else {
|
|
for ( int i = 0 ; i < 3 ; ++ i) {
|
|
DBLVECTOR vdPoly{ m_dRad * vtYRef.v[i] + dPitch * vtZRef.v[i],
|
|
- 2 * m_dRad * vtXRef.v[i],
|
|
- m_dRad * vtYRef.v[i] + dPitch * vtZRef.v[i]} ;
|
|
DBLVECTOR vdRoot ;
|
|
int nRoot = PolynomialRoots( 2, vdPoly, vdRoot) ;
|
|
for ( int i = 0 ; i < nRoot ; ++ i) {
|
|
double dAngDeg = atan2( 2 * vdRoot[i], (1 - vdRoot[i] * vdRoot[i])) * RADTODEG ;
|
|
if ( abs( dAngDeg) > EPS_ANG_ZERO) {
|
|
vdTheta.push_back( dAngDeg) ;
|
|
vdTheta.push_back( dAngDeg + ANG_STRAIGHT) ;
|
|
}
|
|
else
|
|
vdTheta.push_back( ANG_STRAIGHT) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// verifica degli angoli sull'arco ed eventuale considerazione dei punti
|
|
for ( int i = 0 ; i < int( vdTheta.size()) ; ++ i) {
|
|
double dTheta = ( vdTheta[i] > 0 ? vdTheta[i] : vdTheta[i] + ANG_FULL) ;
|
|
if ( dTheta < abs( m_dAngCenDeg)) {
|
|
Point3d ptP ;
|
|
GetPointD1D2( dTheta / ( abs( m_dAngCenDeg)), FROM_MINUS, ptP) ;
|
|
ptP.ToGlob( frRef) ;
|
|
b3Ref.Add( ptP) ;
|
|
}
|
|
}
|
|
|
|
// se c'è estrusione, devo tenerne conto
|
|
if ( ! m_VtExtr.IsSmall() && abs( m_dThick) > EPS_SMALL) {
|
|
Vector3d vtFrExtr = m_VtExtr ;
|
|
vtFrExtr.ToGlob( frRef) ;
|
|
Point3d ptMinExtr = b3Ref.GetMin() + vtFrExtr * m_dThick ;
|
|
Point3d ptMaxExtr = b3Ref.GetMax() + vtFrExtr * m_dThick ;
|
|
b3Ref.Add( ptMinExtr) ;
|
|
b3Ref.Add( ptMaxExtr) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Validate( void)
|
|
{
|
|
if ( m_nStatus == TO_VERIFY) {
|
|
// limito l'angolo al centro a un giro se è piatto ( non è elica)
|
|
if ( abs( m_dDeltaN) < EPS_SMALL) {
|
|
if ( m_dAngCenDeg > ANG_FULL)
|
|
m_dAngCenDeg = ANG_FULL ;
|
|
else if ( m_dAngCenDeg < - ANG_FULL)
|
|
m_dAngCenDeg = - ANG_FULL ;
|
|
}
|
|
// eseguo il controllo
|
|
m_nStatus = ( ( m_PtCen.IsValid() &&
|
|
m_VtN.IsNormalized() && m_VtS.IsNormalized() && AreOrthoApprox( m_VtN, m_VtS) &&
|
|
m_dRad > EPS_SMALL && m_dRad < MAX_ARC_RAD &&
|
|
abs( m_dAngCenDeg) > EPS_ANG_ZERO) ? OK : ERR) ;
|
|
}
|
|
|
|
return ( m_nStatus == OK) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::IsFlat( Plane3d& plPlane, bool bUseExtrusion, double dToler) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// assegno dati possibile piano
|
|
bool bFlat = IsPlane( dToler) ;
|
|
Vector3d vtN ;
|
|
if ( ! bUseExtrusion || m_VtExtr.IsSmall()) {
|
|
vtN = m_VtN ;
|
|
}
|
|
else {
|
|
vtN = m_VtExtr ;
|
|
bFlat = bFlat && AreSameOrOppositeVectorApprox( m_VtExtr, m_VtN) ;
|
|
}
|
|
plPlane.Set( m_PtCen, vtN) ;
|
|
// ritorno conferma
|
|
return bFlat ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetStartPoint( Point3d& ptStart) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// calcolo il punto
|
|
ptStart = m_PtCen + m_dRad * m_VtS ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetEndPoint( Point3d& ptEnd) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// calcolo il punto
|
|
double dAng = m_dAngCenDeg * DEGTORAD ;
|
|
Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ;
|
|
ptEnd = m_PtCen + m_dRad * vtDir ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
ptEnd += m_dDeltaN * m_VtN ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetMidPoint( Point3d& ptMid) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// calcolo il punto
|
|
double dAng = 0.5 * m_dAngCenDeg * DEGTORAD ;
|
|
Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ;
|
|
ptMid = m_PtCen + m_dRad * vtDir ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
ptMid += ( 0.5 * m_dDeltaN) * m_VtN ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetCenterPoint( Point3d& ptCen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// assegno il centro
|
|
ptCen = m_PtCen ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetCentroid( Point3d& ptCen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// approssimo la curva con una polilinea
|
|
PolyLine PL ;
|
|
if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, APL_STD, PL))
|
|
return false ;
|
|
// calcolo il centro mediante PolygonPlane
|
|
Point3d ptP ;
|
|
PolygonPlane PolyPlane ;
|
|
for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP))
|
|
PolyPlane.AddPoint( ptP) ;
|
|
if ( PolyPlane.GetCentroid( ptCen))
|
|
return true ;
|
|
// se non riuscito, uso il punto medio
|
|
return GetMidPoint( ptCen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetDir( double dU, Vector3d& vtDir) const
|
|
{
|
|
// la curva deve essere valida
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// il parametro U deve essere compreso tra 0 e 1
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
|
|
// versore al punto nel piano della circonferenza (ruoto m_VtS di dU * m_dAngCenDeg attorno a m_VtN)
|
|
double dAng = dU * m_dAngCenDeg * DEGTORAD ;
|
|
Vector3d vtRad = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ;
|
|
// calcolo della tangente nel punto finale
|
|
vtDir = ( m_dRad * m_dAngCenDeg * DEGTORAD) * ( m_VtN ^ vtRad) ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
vtDir += m_dDeltaN * m_VtN ;
|
|
// normalizzo
|
|
return vtDir.Normalize( EPS_ZERO) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const
|
|
{
|
|
// la curva deve essere valida
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// il parametro U deve essere compreso tra 0 e 1
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
|
|
// versore al punto nel piano della circonferenza (ruoto m_VtS di dU di m_dAngCenDeg attorno a m_VtN)
|
|
double dAng = dU * m_dAngCenDeg * DEGTORAD ;
|
|
Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ;
|
|
|
|
// calcolo del punto
|
|
ptPos = m_PtCen + m_dRad * vtDir ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
ptPos += ( dU * m_dDeltaN) * m_VtN ;
|
|
|
|
// calcolo della derivata prima
|
|
if ( pvtDer1 != nullptr) {
|
|
*pvtDer1 = ( m_dRad * m_dAngCenDeg * DEGTORAD) * ( m_VtN ^ vtDir) ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
*pvtDer1 += m_dDeltaN * m_VtN ;
|
|
}
|
|
|
|
// calcolo della derivata seconda
|
|
if ( pvtDer2 != nullptr && pvtDer1 != nullptr)
|
|
*pvtDer2 = - ( m_dRad * m_dAngCenDeg * DEGTORAD * m_dAngCenDeg * DEGTORAD) * vtDir ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetLength( double& dLen) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// lunghezza dell'arco piano
|
|
dLen = m_dRad * abs( m_dAngCenDeg) * DEGTORAD ;
|
|
// aggiunta eventuale parte ortogonale
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
dLen = sqrt( dLen * dLen + m_dDeltaN * m_dDeltaN) ;
|
|
|
|
return ( dLen > EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetLengthAtParam( double dU, double& dLen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// fuori dominio del parametro -> errore
|
|
if ( dU < 0 - EPS_PARAM)
|
|
return false ;
|
|
if ( dU > ( 1 + EPS_PARAM))
|
|
return false ;
|
|
|
|
// inizio
|
|
if ( dU < 0 + EPS_PARAM) {
|
|
dLen = 0 ;
|
|
return true ;
|
|
}
|
|
|
|
// lunghezza totale
|
|
double dTotLen ;
|
|
if ( ! GetLength( dTotLen))
|
|
return false ;
|
|
|
|
// fine
|
|
if ( dU > 1 - EPS_PARAM) {
|
|
dLen = dTotLen ;
|
|
return true ;
|
|
}
|
|
|
|
// posizione intermedia
|
|
dLen = dU * dTotLen ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetParamAtLength( double dLen, double& dU) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// se prima di inizio, errore
|
|
if ( dLen < - EPS_SMALL)
|
|
return false ;
|
|
|
|
// inizio
|
|
if ( dLen < EPS_SMALL) {
|
|
dU = 0 ;
|
|
return true ;
|
|
}
|
|
|
|
// lunghezza totale
|
|
double dTotLen ;
|
|
if ( ! GetLength( dTotLen))
|
|
return false ;
|
|
|
|
// se dopo fine, errore
|
|
if ( dLen > dTotLen + EPS_SMALL)
|
|
return false ;
|
|
|
|
// fine
|
|
if ( dLen > dTotLen - EPS_SMALL) {
|
|
dU = 1 ;
|
|
return true ;
|
|
}
|
|
|
|
// posizione intermedia
|
|
dU = dLen / dTotLen ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::IsPointOn( const Point3d& ptP, double dTol) const
|
|
{
|
|
// verifico la distanza
|
|
return ( DistPointArc( ptP, *this).IsEpsilon( dTol)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetParamAtPoint( const Point3d& ptP, double& dPar, double dTol) const
|
|
{
|
|
DistPointArc DPA( ptP, *this) ;
|
|
if ( ! DPA.IsEpsilon( dTol))
|
|
return false ;
|
|
int nFlag ;
|
|
return DPA.GetParamAtMinDistPoint( 0, dPar, nFlag) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::GetLengthAtPoint( const Point3d& ptP, double& dLen, double dTol) const
|
|
{
|
|
double dU ;
|
|
if ( ! GetParamAtPoint( ptP, dU, dTol))
|
|
return false ;
|
|
return GetLengthAtParam( dU, dLen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const
|
|
{
|
|
// pulisco la polilinea
|
|
PL.Clear() ;
|
|
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determino se approssimazione interna o esterna
|
|
Vector3d vtExtr = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
|
|
bool bCCW = ( (( vtExtr * m_VtN) > - EPS_ZERO) ? ( m_dAngCenDeg > 0) : ( m_dAngCenDeg < 0)) ;
|
|
bool bInside = true ;
|
|
if ( ( ( nType == APL_RIGHT || nType == APL_RIGHT_CONVEX) && bCCW) ||
|
|
( ( nType == APL_LEFT || nType == APL_LEFT_CONVEX) && ! bCCW))
|
|
bInside = false ;
|
|
|
|
// eseguo approssimazione
|
|
ArcApproxer aAppr( dLinTol, dAngTolDeg, bInside, *this) ;
|
|
double dU ;
|
|
Point3d ptPos ;
|
|
while ( aAppr.GetPoint( dU, ptPos)) {
|
|
if ( ! PL.AddUPoint( dU, ptPos))
|
|
return false ;
|
|
}
|
|
|
|
// se necessario, sistemo per convessità dalla parte ammessa
|
|
if ( nType == APL_RIGHT_CONVEX || nType == APL_LEFT_CONVEX) {
|
|
if ( ! PL.MakeConvex( vtExtr, ( nType == APL_LEFT_CONVEX)))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
|
|
{
|
|
// pulisco la polilinea
|
|
PA.Clear() ;
|
|
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determinazione versore normale al piano di riferimento
|
|
Vector3d vtNref = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
|
|
|
|
// assegno estrusione al poliarco
|
|
PA.SetExtrusion( vtNref) ;
|
|
|
|
// se l'arco non ha direzione normale coincidente con il versore del piano, approssimo con rette
|
|
if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref)) {
|
|
ArcApproxer aAppr( dLinTol, dAngTolDeg, true, *this) ;
|
|
double dU ;
|
|
Point3d ptPos ;
|
|
while ( aAppr.GetPoint( dU, ptPos)) {
|
|
if ( ! PA.AddUPoint( dU, ptPos, 0))
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
// calcolo il numero di archi con bulge da usare ( ognuno deve avere un angolo al centro <= 240deg)
|
|
const double MAX_ANG_ARC_BULGE = 240 ;
|
|
int nArcs = int( ceil( abs( m_dAngCenDeg) / MAX_ANG_ARC_BULGE)) ;
|
|
nArcs = max( nArcs, 1) ;
|
|
double dBulge = tan( m_dAngCenDeg / ( 4 * nArcs) * DEGTORAD) ;
|
|
// se direzioni opposte, senso di rotazione contrario
|
|
if ( m_VtN * vtNref < 0)
|
|
dBulge = - dBulge ;
|
|
// inserisco i punti di inizio di ogni arco
|
|
for ( int i = 0 ; i < nArcs ; ++ i) {
|
|
Point3d ptStart ;
|
|
double dU = i / double( nArcs) ;
|
|
if ( ! GetPointD1D2( dU, ICurve::FROM_MINUS, ptStart) ||
|
|
! PA.AddUPoint( dU, ptStart, dBulge))
|
|
return false ;
|
|
}
|
|
|
|
// inserisco punto finale senza bulge
|
|
Point3d ptEnd ;
|
|
if ( ! GetEndPoint( ptEnd) ||
|
|
! PA.AddUPoint( 1, ptEnd, 0))
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
CurveArc::CopyParamRange( double dUStart, double dUEnd) const
|
|
{
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStart < - EPS_PARAM || dUStart > 1 + EPS_PARAM ||
|
|
dUEnd < - EPS_PARAM || dUEnd > 1 + EPS_PARAM)
|
|
return nullptr ;
|
|
// se il parametro start supera quello di end
|
|
if ( dUStart > dUEnd - EPS_PARAM) {
|
|
// se curva aperta, il trim la cancella completamente quindi non resta alcunchè
|
|
if ( ! IsClosed())
|
|
return nullptr ;
|
|
// se curva chiusa, il trim si avvolge attorno al punto di giunzione
|
|
else {
|
|
// eseguo la copia sulla curva composita equivalente
|
|
CurveComposite cCompo ;
|
|
cCompo.CopyFrom( this) ;
|
|
return cCompo.CopyParamRange( dUStart, dUEnd) ;
|
|
}
|
|
}
|
|
// creo l'arco copia
|
|
PtrOwner<CurveArc> pCopy( Clone()) ;
|
|
if ( IsNull( pCopy))
|
|
return nullptr ;
|
|
// eseguo il trim
|
|
if ( ! pCopy->TrimStartEndAtParam( dUStart, dUEnd))
|
|
return nullptr ;
|
|
return ( ::Release( pCopy)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Invert( void)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// il centro va spostato di DeltaN
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
m_PtCen += m_dDeltaN * m_VtN ;
|
|
// il versore normale rimane inalterato
|
|
// il versore iniziale diventa quello finale
|
|
double dAng = m_dAngCenDeg * DEGTORAD ;
|
|
m_VtS = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ;
|
|
// il raggio non cambia
|
|
// l'angolo al centro inverte il segno
|
|
m_dAngCenDeg = - m_dAngCenDeg ;
|
|
// l'incremento sulla normale inverte il segno
|
|
m_dDeltaN = - m_dDeltaN ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::SimpleOffset( double dDist, int nType, double dMaxAngExt)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determinazione versore normale al piano di offset
|
|
Vector3d vtNref = Z_AX ;
|
|
if ( ! m_VtExtr.IsSmall())
|
|
vtNref = m_VtExtr ;
|
|
|
|
// la normale deve coincidere con il versore del piano di offset
|
|
if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref))
|
|
return false ;
|
|
|
|
// calcolo il nuovo raggio e lo valido
|
|
bool bCCW = ( ( m_dAngCenDeg > 0 && m_VtN * vtNref > 0) ||
|
|
( m_dAngCenDeg < 0 && m_VtN * vtNref < 0)) ;
|
|
double dNewRad = m_dRad + ( bCCW ? + dDist : - dDist) ;
|
|
if ( dNewRad < EPS_SMALL)
|
|
return false ;
|
|
|
|
// aggiorno il raggio
|
|
m_dRad = dNewRad ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::MyExtendedOffset( double dDist, bool bAll)
|
|
{
|
|
// bAll == true fa accettare raggi nulli ==> da usare solo internamente
|
|
// quando si è sicuri di aumentare subito il raggio o di cancellare
|
|
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determinazione versore normale al piano di offset
|
|
Vector3d vtNref = Z_AX ;
|
|
if ( ! m_VtExtr.IsSmall())
|
|
vtNref = m_VtExtr ;
|
|
|
|
// la normale deve coincidere con il versore del piano di offset
|
|
if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref))
|
|
return false ;
|
|
|
|
// calcolo il nuovo raggio e lo valido
|
|
bool bCCW = ( ( m_dAngCenDeg > 0 && m_VtN * vtNref > 0) ||
|
|
( m_dAngCenDeg < 0 && m_VtN * vtNref < 0)) ;
|
|
double dNewRad = m_dRad + ( bCCW ? + dDist : - dDist) ;
|
|
if ( abs( dNewRad) < EPS_SMALL) {
|
|
if ( bAll)
|
|
dNewRad = 0.1 * EPS_SMALL ;
|
|
else
|
|
return false ;
|
|
}
|
|
if ( dNewRad < 0) {
|
|
dNewRad = - dNewRad ;
|
|
m_VtS = - m_VtS ;
|
|
}
|
|
|
|
// aggiorno il raggio
|
|
m_dRad = dNewRad ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// quando raggio nullo ritorno false come indicativo dello stato
|
|
return ( m_dRad > EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ModifyStart( const Point3d& ptNewStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// inverto l'arco
|
|
Invert() ;
|
|
// modifico la fine dell'arco invertito
|
|
bool bOk = ModifyEnd( ptNewStart) ;
|
|
// re-inverto
|
|
Invert() ;
|
|
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ModifyEnd( const Point3d& ptNewEnd)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X)
|
|
Frame3d frIntr ;
|
|
if ( ! frIntr.Set( m_PtCen, m_VtN, m_VtS))
|
|
return false ;
|
|
// determino vecchio e nuovo punto finale nel riferimento intrinsseco
|
|
Point3d ptOldEndIntr ;
|
|
GetEndPoint( ptOldEndIntr) ;
|
|
ptOldEndIntr.ToLoc( frIntr) ;
|
|
Point3d ptEndIntr = ptNewEnd ;
|
|
ptEndIntr.ToLoc( frIntr) ;
|
|
// se coincidono nel piano XY, è cambiato solo il deltaN
|
|
if ( AreSamePointXYExact( ptOldEndIntr, ptEndIntr)) {
|
|
m_dDeltaN += ptEndIntr.z - ptOldEndIntr.z ;
|
|
}
|
|
// altrimenti, calcolo un arco ausiliario nel riferimento intrinseco con i nuovi dati
|
|
else {
|
|
Point3d ptStartIntr ;
|
|
GetStartPoint( ptStartIntr) ;
|
|
ptStartIntr.ToLoc( frIntr) ;
|
|
double dOldAngCenDeg = m_dAngCenDeg ;
|
|
CurveArc arcAux ;
|
|
if ( ! arcAux.Set2PD( ptStartIntr, ptEndIntr, ( m_dAngCenDeg > 0 ? ANG_RIGHT : - ANG_RIGHT)))
|
|
return false ;
|
|
// aggiorno i dati dell'arco con quelli appena calcolati
|
|
m_PtCen = arcAux.m_PtCen ;
|
|
m_PtCen.ToGlob( frIntr) ;
|
|
m_VtN = arcAux.m_VtN ;
|
|
m_VtN.ToGlob( frIntr) ;
|
|
m_VtS = arcAux.m_VtS ;
|
|
m_VtS.ToGlob( frIntr) ;
|
|
m_dRad = arcAux.m_dRad ;
|
|
// se elica, devo avere un numero di giri vicino ai precedenti
|
|
if ( abs( dOldAngCenDeg) >= ANG_FULL - EPS_ANG_ZERO)
|
|
m_dAngCenDeg = AngleNearAngle( arcAux.m_dAngCenDeg, dOldAngCenDeg) ;
|
|
else
|
|
m_dAngCenDeg = arcAux.m_dAngCenDeg ;
|
|
m_dDeltaN = arcAux.m_dDeltaN ;
|
|
}
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::TrimStartAtParam( double dUTrim)
|
|
{
|
|
// riporto i parametri nel loro range
|
|
dUTrim = Clamp( dUTrim, 0., 1.) ;
|
|
|
|
// recupero lunghezza
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
|
|
// utilizzo il trim sulle lunghezze
|
|
return TrimStartAtLen( dUTrim * dLen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::TrimEndAtParam( double dUTrim)
|
|
{
|
|
// riporto i parametri nel loro range
|
|
dUTrim = Clamp( dUTrim, 0., 1.) ;
|
|
|
|
// recupero lunghezza
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
|
|
// utilizzo il trim sulle lunghezze
|
|
return TrimEndAtLen( dUTrim * dLen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
|
|
{
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStartTrim < - EPS_PARAM || dUStartTrim > 1 + EPS_PARAM ||
|
|
dUEndTrim < - EPS_PARAM || dUEndTrim > 1 + EPS_PARAM)
|
|
return false ;
|
|
// verifico che i trim non cancellino interamente la curva
|
|
if ( dUStartTrim > dUEndTrim - EPS_PARAM)
|
|
return false ;
|
|
// trim finale
|
|
if ( ! TrimEndAtParam( dUEndTrim))
|
|
return false ;
|
|
// trim iniziale con il parametro opportunamente ricalcolato
|
|
double dNewUStartTrim = dUStartTrim / dUEndTrim ;
|
|
return TrimStartAtParam( dNewUStartTrim) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::TrimStartAtLen( double dLenTrim)
|
|
{
|
|
// lunghezze negative vengono considerate nulle
|
|
dLenTrim = max( dLenTrim, 0.) ;
|
|
|
|
// verifico che sia abbastanza lunga
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
if ( ( dLen - dLenTrim) < EPS_SMALL)
|
|
return false ;
|
|
|
|
// eseguo il trim
|
|
if ( dLenTrim > EPS_ZERO) {
|
|
double dAngRot ;
|
|
double dMoveN ;
|
|
dAngRot = m_dAngCenDeg * dLenTrim / dLen ;
|
|
m_VtS.Rotate( m_VtN, dAngRot) ;
|
|
m_dAngCenDeg -= dAngRot ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) {
|
|
dMoveN = m_dDeltaN * dLenTrim / dLen ;
|
|
m_PtCen.Translate( m_VtN * dMoveN) ;
|
|
m_dDeltaN -= dMoveN ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::TrimEndAtLen( double dLenTrim)
|
|
{
|
|
// lunghezze negative vengono considerate nulle
|
|
dLenTrim = max( dLenTrim, 0.) ;
|
|
|
|
// verifico che sia abbastanza lunga
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
if ( dLenTrim < EPS_SMALL)
|
|
return false ;
|
|
|
|
// eseguo il trim
|
|
if ( ( dLen - dLenTrim) > EPS_ZERO) {
|
|
m_dAngCenDeg *= dLenTrim / dLen ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
m_dDeltaN *= dLenTrim / dLen ;
|
|
}
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ExtendStartByLen( double dLenExt)
|
|
{
|
|
// la lunghezza di estensione deve essere positiva
|
|
if ( dLenExt < - EPS_ZERO)
|
|
return false ;
|
|
|
|
// inverto l'arco, lo estendo alla fine o lo reinverto
|
|
Invert() ;
|
|
bool bOk = ExtendEndByLen( dLenExt) ;
|
|
Invert() ;
|
|
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ExtendEndByLen( double dLenExt)
|
|
{
|
|
// la lunghezza deve essere positiva
|
|
if ( dLenExt < - EPS_ZERO)
|
|
return false ;
|
|
|
|
// ricavo la lunghezza originale
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
|
|
// eseguo l'estensione
|
|
double dCoeff = ( dLen + dLenExt) / dLen ;
|
|
m_dAngCenDeg *= dCoeff ;
|
|
if ( ! IsPlane())
|
|
m_dDeltaN *= dCoeff ;
|
|
else if ( abs( m_dAngCenDeg) > ANG_FULL)
|
|
m_dAngCenDeg = _copysign( ANG_FULL, m_dAngCenDeg) ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Translate( const Vector3d& vtMove)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// traslo Voronoi
|
|
if ( m_pVoronoiObj != nullptr)
|
|
m_pVoronoiObj->Translate( vtMove) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// traslo il centro
|
|
m_PtCen.Translate( vtMove) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità dell'asse di rotazione
|
|
if ( vtAx.IsSmall())
|
|
return false ;
|
|
|
|
// ruoto Voronoi
|
|
if ( m_pVoronoiObj != nullptr)
|
|
m_pVoronoiObj->Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// ruoto il centro e i versori
|
|
m_PtCen.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
|
|
m_VtN.Rotate( vtAx, dCosAng, dSinAng) ;
|
|
m_VtS.Rotate( vtAx, dCosAng, dSinAng) ;
|
|
// ruoto il vettore estrusione
|
|
m_VtExtr.Rotate( vtAx, dCosAng, dSinAng) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// se riferimento con asse Z perpendicolare al piano dell'arco
|
|
if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersZ())) {
|
|
// la scalatura deve essere uniforme nel piano dell'arco
|
|
if ( abs( dCoeffX - dCoeffY) > EPS_SMALL)
|
|
return false ;
|
|
// verifico non sia nulla
|
|
if ( abs( dCoeffX) < EPS_ZERO || m_dRad * abs( dCoeffX) <= EPS_SMALL)
|
|
return false ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// scalo il centro e le dimensioni lineari
|
|
m_PtCen.Scale( frRef, dCoeffX, dCoeffX, dCoeffZ) ;
|
|
m_dRad *= abs( dCoeffX) ;
|
|
m_dDeltaN *= dCoeffZ ;
|
|
if ( dCoeffZ < 0)
|
|
m_VtS = - m_VtS ;
|
|
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Scale( frRef, dCoeffX, dCoeffX, dCoeffZ) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
m_nStatus = TO_VERIFY ;
|
|
// ritorno risultato della validazione
|
|
return Validate() ;
|
|
}
|
|
// se riferimento con asse X perpendicolare al piano dell'arco
|
|
else if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersX())) {
|
|
// la scalatura deve essere uniforme nel piano dell'arco
|
|
if ( abs( dCoeffY - dCoeffZ) > EPS_SMALL)
|
|
return false ;
|
|
// verifico non sia nulla
|
|
if ( abs( dCoeffY) < EPS_ZERO || m_dRad * abs( dCoeffY) <= EPS_SMALL)
|
|
return false ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// scalo il centro e le dimensioni lineari
|
|
m_PtCen.Scale( frRef, dCoeffX, dCoeffY, dCoeffY) ;
|
|
m_dRad *= abs( dCoeffY) ;
|
|
m_dDeltaN *= dCoeffX ;
|
|
if ( dCoeffX < 0)
|
|
m_VtS = - m_VtS ;
|
|
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Scale( frRef, dCoeffX, dCoeffY, dCoeffY) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
m_nStatus = TO_VERIFY ;
|
|
// ritorno risultato della validazione
|
|
return Validate() ;
|
|
}
|
|
// se riferimento con asse Y perpendicolare al piano dell'arco
|
|
else if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersY())) {
|
|
// la scalatura deve essere uniforme nel piano dell'arco
|
|
if ( abs( dCoeffZ - dCoeffX) > EPS_SMALL)
|
|
return false ;
|
|
// verifico non sia nulla
|
|
if ( abs( dCoeffZ) < EPS_ZERO || m_dRad * abs( dCoeffZ) <= EPS_SMALL)
|
|
return false ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// scalo il centro e le dimensioni lineari
|
|
m_PtCen.Scale( frRef, dCoeffZ, dCoeffY, dCoeffZ) ;
|
|
m_dRad *= abs( dCoeffZ) ;
|
|
m_dDeltaN *= dCoeffY ;
|
|
if ( dCoeffY < 0)
|
|
m_VtS = - m_VtS ;
|
|
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Scale( frRef, dCoeffZ, dCoeffY, dCoeffZ) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
m_nStatus = TO_VERIFY ;
|
|
// ritorno risultato della validazione
|
|
return Validate() ;
|
|
}
|
|
// altrimenti riferimento generico rispetto all'arco
|
|
else {
|
|
// la scalatura deve essere completamente uniforme
|
|
if ( abs( dCoeffX - dCoeffY) > EPS_SMALL || abs( dCoeffX - dCoeffZ) > EPS_SMALL)
|
|
return false ;
|
|
// verifico non sia nulla
|
|
if ( abs( dCoeffX) < EPS_ZERO || m_dRad * abs( dCoeffX) <= EPS_SMALL)
|
|
return false ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// scalo il centro e le dimensioni lineari
|
|
m_PtCen.Scale( frRef, dCoeffX, dCoeffX, dCoeffX) ;
|
|
m_dRad *= abs( dCoeffX) ;
|
|
m_dDeltaN *= dCoeffX ;
|
|
if ( dCoeffX < 0)
|
|
m_VtS = - m_VtS ;
|
|
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Scale( frRef, dCoeffX, dCoeffX, dCoeffX) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
m_nStatus = TO_VERIFY ;
|
|
// ritorno risultato della validazione
|
|
return Validate() ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità del piano di specchiatura
|
|
if ( vtNorm.IsSmall())
|
|
return false ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// specchio il centro e i versori, inverto l'angolo al centro
|
|
m_PtCen.Mirror( ptOn, vtNorm) ;
|
|
m_VtN.Mirror( vtNorm) ;
|
|
m_VtS.Mirror( vtNorm) ;
|
|
m_dAngCenDeg *= -1 ;
|
|
// specchio il vettore estrusione
|
|
m_VtExtr.Mirror( vtNorm) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità dei parametri
|
|
if ( vtNorm.IsSmall() || vtDir.IsSmall())
|
|
return false ;
|
|
|
|
// possibile solo se l'arco è piatto e il piano di scorrimento coincide con quello dell'arco
|
|
if ( ! ( abs( m_dDeltaN) < EPS_SMALL) ||
|
|
! AreSameOrOppositeVectorExact( m_VtN, vtNorm))
|
|
return false ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo scorrimento del centro
|
|
m_PtCen.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
|
|
// eseguo scorrimento del vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Shear( vtNorm, vtDir, dCoeff) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ToGlob( const Frame3d& frRef)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del frame
|
|
if ( frRef.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se frame identità, non devo fare alcunché
|
|
if ( IsGlobFrame( frRef))
|
|
return true ;
|
|
|
|
// trasformo Voronoi
|
|
if ( m_pVoronoiObj != nullptr)
|
|
m_pVoronoiObj->ToGlob( frRef) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo il centro e i versori
|
|
return ( m_PtCen.ToGlob( frRef) &&
|
|
m_VtN.ToGlob( frRef) &&
|
|
m_VtS.ToGlob( frRef) &&
|
|
m_VtExtr.ToGlob( frRef)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ToLoc( const Frame3d& frRef)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del frame
|
|
if ( frRef.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se frame identità, non devo fare alcunché
|
|
if ( IsGlobFrame( frRef))
|
|
return true ;
|
|
|
|
// trasformo Voronoi
|
|
if ( m_pVoronoiObj != nullptr)
|
|
m_pVoronoiObj->ToLoc( frRef) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo il centro e i versori
|
|
return ( m_PtCen.ToLoc( frRef) &&
|
|
m_VtN.ToLoc( frRef) &&
|
|
m_VtS.ToLoc( frRef) &&
|
|
m_VtExtr.ToLoc( frRef)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità dei frame
|
|
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se i due riferimenti coincidono, non devo fare alcunché
|
|
if ( AreSameFrame( frOri, frDest))
|
|
return true ;
|
|
|
|
// trasformo Voronoi
|
|
if ( m_pVoronoiObj != nullptr)
|
|
m_pVoronoiObj->LocToLoc( frOri, frDest) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo il centro e i versori
|
|
return ( m_PtCen.LocToLoc( frOri, frDest) &&
|
|
m_VtN.LocToLoc( frOri, frDest) &&
|
|
m_VtS.LocToLoc( frOri, frDest) &&
|
|
m_VtExtr.LocToLoc( frOri, frDest)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::InvertN( void)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// si inverte il verso della normale senza modificare la geometria dell'arco
|
|
m_VtN.Invert() ;
|
|
m_dAngCenDeg = - m_dAngCenDeg ;
|
|
m_dDeltaN = - m_dDeltaN ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::IsPointInSector( const Point3d& ptP) const
|
|
{
|
|
// verifico sia compreso nell'angolo al centro
|
|
bool bDet ;
|
|
double dAngDeg ;
|
|
if ( ! m_VtS.GetRotation( ( ptP - m_PtCen), m_VtN, dAngDeg, bDet) || ! bDet)
|
|
return false ;
|
|
return AngleInSpan( dAngDeg, 0, m_dAngCenDeg) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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::MyCalcPointParamPosiz( const Point3d& ptP, double& dU, int& nPos, double dLinTol) 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 ( abs( DiffAngle( dAngDeg, 0) * DEGTORAD * m_dRad) < dLinTol) {
|
|
nPos = ( IsACircle() ? PP_MID : PP_START) ; // se cerchio è interno, altrimenti vicino a inizio
|
|
dU = AngleNearAngle( dAngDeg, 0) / m_dAngCenDeg ;
|
|
dU = max( dU, 0.) ;
|
|
}
|
|
else if ( abs( DiffAngle( dAngDeg, m_dAngCenDeg) * DEGTORAD * m_dRad) < dLinTol) {
|
|
nPos = ( IsACircle() ? PP_MID : PP_END) ; // se cerchio è interno, altrimenti 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)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità del raggio
|
|
if ( ! ( dNewRadius > EPS_SMALL && dNewRadius < MAX_ARC_RAD))
|
|
return false ;
|
|
|
|
// cambio il raggio
|
|
m_dRad = dNewRadius ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo validazione
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ChangeDeltaN( double dNewDeltaN)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// cambio il parametro
|
|
m_dDeltaN = dNewDeltaN ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo validazione
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ChangeAngCenter( double dNewAngCenDeg)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico accettabilità angolo
|
|
if ( ! ( abs( m_dAngCenDeg) > EPS_ANG_ZERO))
|
|
return false ;
|
|
|
|
// cambio il parametro
|
|
m_dAngCenDeg = dNewAngCenDeg ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo validazione
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ChangeStartPoint( double dU)
|
|
{
|
|
// la curva deve essere chiusa (ne verifica anche lo stato)
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
// recupero il punto che corrisponde al valore del parametro
|
|
Point3d ptP ;
|
|
if ( ! GetPointD1D2( dU, ICurve::FROM_MINUS, ptP))
|
|
return false ;
|
|
// cambio il versore start
|
|
Vector3d vtDir = ptP - m_PtCen ;
|
|
if ( ! vtDir.Normalize())
|
|
return false ;
|
|
m_VtS = vtDir ;
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::ToExplementary( void)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// l'angolo al centro deve essere minore di un giro
|
|
if ( abs( m_dAngCenDeg) > ( ANG_FULL - EPS_ANG_SMALL))
|
|
return false ;
|
|
|
|
// basta prendere l'angolo al centro che completa il giro
|
|
m_dAngCenDeg = - _copysign( ANG_FULL, m_dAngCenDeg) + m_dAngCenDeg ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::Flip( void)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// l'angolo al centro deve essere minore di un giro
|
|
if ( abs( m_dAngCenDeg) > ( ANG_FULL - EPS_ANG_SMALL))
|
|
return false ;
|
|
|
|
// si calcola l'arco simmetrico rispetto alla linea che unisce gli estremi
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! GetStartPoint( ptStart) || ! GetEndPoint( ptEnd))
|
|
return false ;
|
|
// il punto finale mi interessa nel piano dell'arco
|
|
if ( abs( m_dDeltaN) > EPS_SMALL)
|
|
ptEnd -= m_dDeltaN * m_VtN ;
|
|
m_PtCen = ptStart + ( ptEnd - m_PtCen) ;
|
|
m_VtS = ptStart - m_PtCen ;
|
|
m_VtS.Normalize() ;
|
|
m_dAngCenDeg = - m_dAngCenDeg ;
|
|
|
|
// imposto ricalcolo di Voronoi
|
|
ResetVoronoiObject() ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Oggetto locale per approssimazione di archi
|
|
// Approx interna è quella cordale standard.
|
|
// Approx esterna è quella tangente a inizio e fine con metà tratto e un punto in più.
|
|
// I punti si calcolano a partire dal triangolo tra due punti consecutivi interni e il centro,
|
|
// usando il versore medio dal centro e moltiplicandolo per il coefficiente ( 2 / ( 1 + cosA)).
|
|
// Il versore dell'ultimo punto è già stato calcolato per il penultimo.
|
|
//----------------------------------------------------------------------------
|
|
ArcApproxer::ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc)
|
|
{
|
|
// inizializzazioni
|
|
m_nTotPnt = 0 ;
|
|
m_nCurrPnt = - 1 ;
|
|
|
|
// la curva deve essere validata
|
|
if ( ! arArc.IsValid())
|
|
return ;
|
|
|
|
// limiti minimi su tolleranza e deviazione angolare
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
|
|
|
|
// limite massimo su deviazione angolare se approssimazione esterna
|
|
if ( ! bInside)
|
|
dAngTolDeg = min( dAngTolDeg, ANG_TOL_EXT_MAX_DEG) ;
|
|
|
|
// determinazione dello step angolare
|
|
double dAngStepDeg ;
|
|
double dLinTolRel = dLinTol / arArc.GetRadius() ;
|
|
if ( bInside)
|
|
dAngStepDeg = sqrt( 8 * dLinTolRel) * RADTODEG ;
|
|
else
|
|
dAngStepDeg = sqrt( 8 * dLinTolRel / ( 1 + dLinTolRel)) * RADTODEG ;
|
|
dAngStepDeg = min( dAngStepDeg, dAngTolDeg) ;
|
|
|
|
// dall'angolo al centro ricavo il numero di passi
|
|
int nStep = int( abs( arArc.GetAngCenter()) / dAngStepDeg + 0.999) ;
|
|
nStep = max( nStep, 1) ;
|
|
|
|
// sistemo lo step (per il numero intero di passi)
|
|
dAngStepDeg = arArc.GetAngCenter() / nStep ;
|
|
|
|
// versori di riferimento nel piano dell'arco
|
|
m_vtA1 = arArc.GetStartVersor() ;
|
|
m_vtA2 = arArc.GetNormVersor() ^ arArc.GetStartVersor() ;
|
|
|
|
// seno e coseno dell'angolo di step
|
|
m_dCosA = cos( dAngStepDeg * DEGTORAD) ;
|
|
m_dSinA = sin( dAngStepDeg * DEGTORAD) ;
|
|
|
|
// salvo i dati
|
|
m_bInside = bInside ;
|
|
m_nTotPnt = ( m_bInside ? ( nStep + 1) : ( nStep + 2)) ;
|
|
m_PtCen = arArc.GetCenter() ;
|
|
m_VtN = arArc.GetNormVersor() ;
|
|
m_dRad = arArc.GetRadius() ;
|
|
m_dDeltaN = arArc.GetDeltaN() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ArcApproxer::GetPoint( double& dU, Point3d& ptP)
|
|
{
|
|
// incremento indice punto corrente
|
|
++ m_nCurrPnt ;
|
|
|
|
// se oltrepassata la fine
|
|
if ( m_nCurrPnt >= m_nTotPnt)
|
|
return false ;
|
|
|
|
// primo punto
|
|
if ( m_nCurrPnt == 0) {
|
|
dU = 0 ;
|
|
ptP = m_PtCen + m_vtA1 * m_dRad ;
|
|
return true ;
|
|
}
|
|
|
|
// se approx esterna e ultimo punto (uso rotazione precedente)
|
|
if ( ! m_bInside && m_nCurrPnt == m_nTotPnt - 1) {
|
|
dU = 1 ;
|
|
ptP = m_PtCen + m_vtA1 * m_dRad ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
ptP += ( dU * m_dDeltaN) * m_VtN ;
|
|
return true ;
|
|
}
|
|
|
|
// punti successivi
|
|
// calcolo parametro
|
|
if ( m_bInside)
|
|
dU = m_nCurrPnt / (double) ( m_nTotPnt - 1) ;
|
|
else
|
|
dU = ( m_nCurrPnt - 0.5) / (double) ( m_nTotPnt - 2) ;
|
|
// nuovo valore versori
|
|
Vector3d vtA1p = m_vtA1 ;
|
|
Vector3d vtA2p = m_vtA2 ;
|
|
m_vtA1 = m_dCosA * vtA1p + m_dSinA * vtA2p ;
|
|
m_vtA2 = - m_dSinA * vtA1p + m_dCosA * vtA2p ;
|
|
// calcolo del punto
|
|
if ( m_bInside)
|
|
ptP = m_PtCen + m_vtA1 * m_dRad ;
|
|
else
|
|
ptP = m_PtCen + ( vtA1p + m_vtA1) * ( m_dRad / ( 1 + m_dCosA)) ;
|
|
if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL)
|
|
ptP += ( dU * m_dDeltaN) * m_VtN ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveArc::CalcVoronoiObject() const
|
|
{
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// creo oggetto vroni con la curva
|
|
m_pVoronoiObj = new( std::nothrow) Voronoi( this, false) ;
|
|
if ( m_pVoronoiObj == nullptr)
|
|
return false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Voronoi*
|
|
CurveArc::GetVoronoiObject() const
|
|
{
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
|
|
// se non è stato calcolato, lo calcolo
|
|
if ( m_pVoronoiObj == nullptr)
|
|
CalcVoronoiObject() ;
|
|
|
|
// restituisco Voronoi
|
|
return m_pVoronoiObj ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
CurveArc::ResetVoronoiObject() const
|
|
{
|
|
if ( m_pVoronoiObj != nullptr)
|
|
delete m_pVoronoiObj ;
|
|
m_pVoronoiObj = nullptr ;
|
|
}
|