6962aeced4
- aggiunto P_INVALID Pointt3d non definito (IsValid ritorna false) - aggiunto V_INVALID Vector3d non definito (IsValid ritorna false) - aggiunte raccolte di puntatori a ICurveLine.
464 lines
20 KiB
C++
464 lines
20 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2023
|
|
//----------------------------------------------------------------------------
|
|
// File : EGkVector3d.h Data : 23.08.23 Versione : 2.5h2
|
|
// Contenuto : Dichiarazione della classe Vettore 3d.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 31.12.13 DS Creazione modulo.
|
|
// 14.12.19 DS Aggiunti confronti con Epsilon.
|
|
// 23.08.23 DS Aggiunto V_INVALID.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include "/EgtDev/Include/EGkGeoConst.h"
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
//----------------------- Macro per import/export -----------------------------
|
|
#undef EGK_EXPORT
|
|
#if defined( I_AM_EGK) // da definirsi solo nella DLL
|
|
#define EGK_EXPORT __declspec( dllexport)
|
|
#else
|
|
#define EGK_EXPORT __declspec( dllimport)
|
|
#endif
|
|
|
|
//-------------------------- Forward Definition -------------------------------
|
|
class Frame3d ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
class EGK_EXPORT Vector3d
|
|
{
|
|
public :
|
|
//! Costruttore del vettore con tre componenti X, Y e Z
|
|
Vector3d( double dX, double dY, double dZ) : x( dX), y( dY), z( dZ) {}
|
|
//! Costruttore del vettore da un array di tre componenti
|
|
Vector3d( const double V[3]) : x( V[0]), y( V[1]), z( V[2]) {}
|
|
//! Costruttore del vettore con due componenti X e Y, Z = 0
|
|
Vector3d( double dX, double dY) : x( dX), y( dY), z( 0) {}
|
|
//! Costruttore del vettore nullo X = Y = Z = 0
|
|
Vector3d( void) : x( 0), y( 0), z( 0) {}
|
|
//! Assegnazione delle componenti X, Y e Z al vettore
|
|
void Set( double dX, double dY, double dZ) { x = dX ; y = dY ; z = dZ ; }
|
|
|
|
public :
|
|
//! Verifica la validità delle coordinate del vettore
|
|
bool IsValid( void) const
|
|
{ return ( std::isfinite( x) && std::isfinite( y) && std::isfinite( z)) ; }
|
|
//! Quadrato della lunghezza del vettore
|
|
double SqLen( void) const
|
|
{ return ( x * x + y * y + z * z) ; }
|
|
//! Lunghezza del vettore
|
|
double Len( void) const ;
|
|
//! Quadrato della lunghezza del vettore nel piano XY
|
|
double SqLenXY( void) const
|
|
{ return ( x * x + y * y ) ; }
|
|
//! Lunghezza del vettore nel piano XY
|
|
double LenXY( void) const ;
|
|
//! Verifica se il vettore è quasi nullo
|
|
bool IsSmall( void) const
|
|
{ return ( ( x * x + y * y + z * z) < SQ_EPS_SMALL) ; }
|
|
//! Verifica se il vettore è esattamente nullo
|
|
bool IsZero( void) const
|
|
{ return ( ( x * x + y * y + z * z) < SQ_EPS_ZERO) ; }
|
|
//! Verifica se il vettore è quasi nullo nel piano XY
|
|
bool IsSmallXY( void) const
|
|
{ return ( ( x * x + y * y) < SQ_EPS_SMALL) ; }
|
|
//! Verifica se il vettore è esattamente nullo nel piano XY
|
|
bool IsZeroXY( void) const
|
|
{ return ( ( x * x + y * y) < SQ_EPS_ZERO) ; }
|
|
//! Verifica se il vettore è normalizzato (è un versore)
|
|
bool IsNormalized( void) const
|
|
{ return ( abs( 1.0 - (x * x + y * y + z * z)) < ( 2 * EPS_ZERO)) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con X+
|
|
bool IsXplus( void) const
|
|
{ double dMO = std::max( abs( y), abs( z)) ;
|
|
return ( x > EPS_ZERO && dMO < 10 * EPS_ZERO && x > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con X-
|
|
bool IsXminus( void) const
|
|
{ double dMO = std::max( abs( y), abs( z)) ;
|
|
return ( x < -EPS_ZERO && dMO < 10 * EPS_ZERO && x < -KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo a X
|
|
bool IsX( void) const
|
|
{ double dMO = std::max( abs( y), abs( z)) ;
|
|
return ( abs( x) > EPS_ZERO && dMO < 10 * EPS_ZERO && abs( x) > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con Y+
|
|
bool IsYplus( void) const
|
|
{ double dMO = std::max( abs( z), abs( x)) ;
|
|
return ( y > EPS_ZERO && dMO < 10 * EPS_ZERO && y > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con Y-
|
|
bool IsYminus( void) const
|
|
{ double dMO = std::max( abs( z), abs( x)) ;
|
|
return ( y < -EPS_ZERO && dMO < 10 * EPS_ZERO && y < -KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo a Y
|
|
bool IsY( void) const
|
|
{ double dMO = std::max( abs( z), abs( x)) ;
|
|
return ( abs( y) > EPS_ZERO && dMO < 10 * EPS_ZERO && abs( y) > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con Z+
|
|
bool IsZplus( void) const
|
|
{ double dMO = std::max( abs( x), abs( y)) ;
|
|
return ( z > EPS_ZERO && dMO < 10 * EPS_ZERO && z > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo ed equiverso con Z-
|
|
bool IsZminus( void) const
|
|
{ double dMO = std::max( abs( x), abs( y)) ;
|
|
return ( z < -EPS_ZERO && dMO < 10 * EPS_ZERO && z < -KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è parallelo a Z
|
|
bool IsZ( void) const
|
|
{ double dMO = std::max( abs( x), abs( y)) ;
|
|
return ( abs( z) > EPS_ZERO && dMO < 10 * EPS_ZERO && abs( z) > KV_BIG * dMO) ; }
|
|
//! Verifica se il vettore è generico
|
|
bool IsGeneric( void) const
|
|
{ return ( ! IsX() && ! IsY() && ! IsZ()) ; }
|
|
//! Somma sul posto con altro vettore
|
|
Vector3d& operator +=( const Vector3d& vtV)
|
|
{ x += vtV.x ; y += vtV.y ; z += vtV.z ; return *this ; }
|
|
//! Sottrazione sul posto con altro vettore
|
|
Vector3d& operator -=( const Vector3d& vtV)
|
|
{ x -= vtV.x ; y -= vtV.y ; z -= vtV.z ; return *this ; }
|
|
//! Moltiplicazione sul posto con un numero
|
|
Vector3d& operator *=( double dMul)
|
|
{ x *= dMul ; y *= dMul ; z *= dMul ; return *this ; }
|
|
//! Divisione sul posto con un numero
|
|
Vector3d& operator /=( double dDiv)
|
|
{ double dMul = 1 / dDiv ; x *= dMul ; y *= dMul ; z *= dMul ; return *this ; }
|
|
//! Ritorna la rappresentazione in coordinate sferiche
|
|
void ToSpherical( double* pdLen, double* pdAngVertDeg, double* pdAngOrizzDeg) const ;
|
|
//! Inversione del vettore
|
|
void Invert( void)
|
|
{ x = -x ; y = -y ; z = -z ; }
|
|
//! Normalizzazione del vettore (trasformazione in versore)
|
|
bool Normalize( double dEps = EPS_SMALL) ;
|
|
//! Rotazione attorno ad un asse, dato l'angolo in gradi
|
|
bool Rotate( const Vector3d& vtAx, double dAngDeg) ;
|
|
//! Rotazione attorno ad un asse, dati coseno e seno dell'angolo di rotazione
|
|
bool Rotate( const Vector3d& vtAx, double dCosAng, double dSinAng) ;
|
|
//! Scalatura non uniforme
|
|
bool Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) ;
|
|
//! Specchiatura
|
|
bool Mirror( const Vector3d& vtNorm) ;
|
|
//! Scorrimento
|
|
bool Shear( const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) ;
|
|
//! Cambio di riferimento : dal riferimento al globale
|
|
bool ToGlob( const Frame3d& frRef) ;
|
|
//! Cambio di riferimento : dal globale al riferimento
|
|
bool ToLoc( const Frame3d& frRef) ;
|
|
//! Cambio di riferimento : dal primo riferimento al secondo
|
|
bool LocToLoc( const Frame3d& frOri, const Frame3d& frDest) ;
|
|
//! Calcolo dell'angolo tra il vettore e un altro
|
|
bool GetAngle( const Vector3d& vtEnd, double& dAngDeg) const ;
|
|
//! Calcolo dell'angolo tra il vettore e un altro nel piano XY
|
|
bool GetAngleXY( const Vector3d& vtEnd, double& dAngDeg) const ;
|
|
//! \brief Calcolo angolo di rotazione per portare la componente del vettore perpendicolare
|
|
//! all'asse di rotazione sulla stessa direzione della componente perpendicolare di vtEnd
|
|
bool GetRotation( const Vector3d& vtEnd, const Vector3d& vtAx, double dEpsZero, double& dAngDeg, bool& bDet) const ;
|
|
bool GetRotation( const Vector3d& vtEnd, const Vector3d& vtAx, double& dAngDeg, bool& bDet) const
|
|
{ return GetRotation( vtEnd, vtAx, EPS_ZERO, dAngDeg, bDet) ;}
|
|
|
|
public :
|
|
union {
|
|
struct {
|
|
double x ; //!< componente sull'asse X
|
|
double y ; //!< componente sull'asse Y
|
|
double z ; //!< componente sull'asse Z
|
|
} ;
|
|
double v[3] ; //!< equivalente vettoriale delle tre componenti
|
|
} ;
|
|
} ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Vettori notevoli
|
|
//----------------------------------------------------------------------------
|
|
//! Vettore non valido
|
|
const Vector3d V_INVALID( NAN, NAN, NAN) ;
|
|
//! Vettore nullo
|
|
const Vector3d V_NULL( 0, 0, 0) ;
|
|
//! Versore asse X
|
|
const Vector3d X_AX( 1, 0, 0) ;
|
|
//! Versore asse Y
|
|
const Vector3d Y_AX( 0, 1, 0) ;
|
|
//! Versore asse Z
|
|
const Vector3d Z_AX( 0, 0, 1) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Definizione a partire da coordinate sferiche
|
|
//----------------------------------------------------------------------------
|
|
EGK_EXPORT Vector3d FromSpherical( double dLen, double dAngVertDeg, double dAngOrizzDeg) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Definizione a partire da coordinate polari ( nel piano XY, Z = 0)
|
|
//----------------------------------------------------------------------------
|
|
EGK_EXPORT Vector3d FromPolar( double dLen, double dAngDeg) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Definizione come più verticale dei vettori ortogonali a quello ricevuto
|
|
//----------------------------------------------------------------------------
|
|
EGK_EXPORT Vector3d FromUprightOrtho( const Vector3d& vtV) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Definizione come ortogonale al primo ricevuto, orizzontale e più vicino al secondo
|
|
//----------------------------------------------------------------------------
|
|
EGK_EXPORT Vector3d FromNearestHorizontalOrtho( const Vector3d& vtV, const Vector3d& vtNear) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Opposto di un vettore
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator-( const Vector3d& vtV)
|
|
{
|
|
return ( Vector3d( - vtV.x, - vtV.y, - vtV.z)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Somma di due vettori
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator+( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( Vector3d( vtV1.x + vtV2.x, vtV1.y + vtV2.y, vtV1.z + vtV2.z)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Sottrazione di due vettori
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator-( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( Vector3d( vtV1.x - vtV2.x, vtV1.y - vtV2.y, vtV1.z - vtV2.z)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto con uno scalare
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator*( const Vector3d& vtV, double dMul)
|
|
{
|
|
return ( Vector3d( vtV.x * dMul, vtV.y * dMul, vtV.z * dMul)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto di uno scalare con un vettore
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator*( double dMul, const Vector3d& vtV)
|
|
{
|
|
return ( Vector3d( vtV.x * dMul, vtV.y * dMul, vtV.z * dMul)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Divisione con uno scalare
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator/( const Vector3d& vtV, double dDiv)
|
|
{
|
|
double dMul = 1 / dDiv ;
|
|
return ( Vector3d( vtV.x * dMul, vtV.y * dMul, vtV.z * dMul)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto scalare
|
|
//----------------------------------------------------------------------------
|
|
inline double
|
|
operator*( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( vtV1.x * vtV2.x + vtV1.y * vtV2.y + vtV1.z * vtV2.z) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto scalare nel piano XY
|
|
//----------------------------------------------------------------------------
|
|
inline double
|
|
ScalarXY( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( vtV1.x * vtV2.x + vtV1.y * vtV2.y) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto vettoriale
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
operator^( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( Vector3d( vtV1.y * vtV2.z - vtV1.z * vtV2.y,
|
|
vtV1.z * vtV2.x - vtV1.x * vtV2.z,
|
|
vtV1.x * vtV2.y - vtV1.y * vtV2.x)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Prodotto vettoriale nel piano XY
|
|
//----------------------------------------------------------------------------
|
|
inline double
|
|
CrossXY( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( vtV1.x * vtV2.y - vtV1.y * vtV2.x) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Somma mediata di due vettori (baricentrica)
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
Media( const Vector3d& vtV1, const Vector3d& vtV2, double dCoeff = 0.5)
|
|
{
|
|
return ( Vector3d( ( 1 - dCoeff) * vtV1.x + dCoeff * vtV2.x,
|
|
( 1 - dCoeff) * vtV1.y + dCoeff * vtV2.y,
|
|
( 1 - dCoeff) * vtV1.z + dCoeff * vtV2.z)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Restituisce il componente del vettore parallelo a quello di riferimento
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
ParallCompo( const Vector3d& vtV, const Vector3d& vtRef)
|
|
{
|
|
if ( vtRef.IsNormalized())
|
|
return ( ( vtV * vtRef) * vtRef) ;
|
|
else
|
|
return ( ( vtV * vtRef) * vtRef / vtRef.SqLen()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Restituisce il componente del vettore ortogonale a quello di riferimento
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
OrthoCompo( const Vector3d& vtV, const Vector3d& vtRef)
|
|
{
|
|
if ( vtRef.IsNormalized())
|
|
return ( vtV - ( vtV * vtRef) * vtRef) ;
|
|
else
|
|
return ( vtV - ( vtV * vtRef) * vtRef / vtRef.SqLen()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi coincidenti (tolleranza come parametro)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameVectorEpsilon( const Vector3d& vtV1, const Vector3d& vtV2, double dToler)
|
|
{
|
|
return ( ( vtV1 - vtV2).SqLen() < ( dToler * dToler)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi coincidenti (Small error -> Approx)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameVectorApprox( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 - vtV2).IsSmall()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono esattamente coincidenti (Zero error -> Exact)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameVectorExact( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 - vtV2).IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi opposti (tolleranza come parametro)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreOppositeVectorEpsilon( const Vector3d& vtV1, const Vector3d& vtV2, double dToler)
|
|
{
|
|
return ( ( vtV1 + vtV2).SqLen() < ( dToler * dToler)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi opposti (Small error -> Approx)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreOppositeVectorApprox( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 + vtV2).IsSmall()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono esattamente opposti (Zero error -> Exact)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreOppositeVectorExact( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 + vtV2).IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi coincidenti o opposti (tolleranza come parametro)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameOrOppositeVectorEpsilon( const Vector3d& vtV1, const Vector3d& vtV2, double dToler)
|
|
{
|
|
return ( ( vtV1 - vtV2).SqLen() < ( dToler * dToler) || ( vtV1 + vtV2).SqLen() < ( dToler * dToler)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono quasi coincidenti o opposti (Small error -> Approx)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameOrOppositeVectorApprox( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 - vtV2).IsSmall() || ( vtV1 + vtV2).IsSmall()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due vettori sono esattamente coincidenti o opposti (Zero error -> Exact)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreSameOrOppositeVectorExact( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( ( vtV1 - vtV2).IsZero() || ( vtV1 + vtV2).IsZero()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due versori sono ortogonali (Small error -> Approx)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreOrthoApprox( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( abs( vtV1 * vtV2) < COS_ORTO_ANG_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Verifica se due versori sono ortogonali (Zero error -> Exact)
|
|
//----------------------------------------------------------------------------
|
|
inline bool
|
|
AreOrthoExact( const Vector3d& vtV1, const Vector3d& vtV2)
|
|
{
|
|
return ( abs( vtV1 * vtV2) < COS_ORTO_ANG_ZERO) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Restituisce una copia in locale del vettore passato
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
GetToLoc( const Vector3d& vtV, const Frame3d& frRef)
|
|
{
|
|
Vector3d vtW = vtV ;
|
|
vtW.ToLoc( frRef) ;
|
|
return vtW ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Restituisce una copia in globale del vettore passato
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
GetToGlob( const Vector3d& vtV, const Frame3d& frRef)
|
|
{
|
|
Vector3d vtW = vtV ;
|
|
vtW.ToGlob( frRef) ;
|
|
return vtW ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//! Restituisce una copia dal primo al secondo riferimento del vettore passato
|
|
//----------------------------------------------------------------------------
|
|
inline const Vector3d
|
|
GetLocToLoc( const Vector3d& vtV, const Frame3d& frOri, const Frame3d& frDest)
|
|
{
|
|
Vector3d vtW = vtV ;
|
|
vtW.LocToLoc( frOri, frDest) ;
|
|
return vtW ;
|
|
}
|