d9c9622972
- aggiunta vista prospettica con due modalità di zoom ( standard e dolly).
1311 lines
50 KiB
C++
1311 lines
50 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2014-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : SceneSnap.cpp Data : 09.10.14 Versione : 1.5j1
|
|
// Contenuto : Implementazione snap di punti trmite selezione.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 09.10.14 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "Scene.h"
|
|
#include "ObjEGrGraphics.h"
|
|
#include "/EgtDev/Include/EGkGeomDB.h"
|
|
#include "/EgtDev/Include/EGkGeoPoint3d.h"
|
|
#include "/EgtDev/Include/EGkGeoVector3d.h"
|
|
#include "/EgtDev/Include/EGkFrame3d.h"
|
|
#include "/EgtDev/Include/EGkCurve.h"
|
|
#include "/EgtDev/Include/EGkCurveArc.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkSurfTriMesh.h"
|
|
#include "/EgtDev/Include/EGkSurfFlatRegion.h"
|
|
#include "/EgtDev/Include/EGkSurfBezier.h"
|
|
#include "/EgtDev/Include/EGkVolZmap.h"
|
|
#include "/EgtDev/Include/EGkExtText.h"
|
|
#include "/EgtDev/Include/EGkExtDimension.h"
|
|
#include "/EgtDev/Include/EGkIntersCurves.h"
|
|
#include "/EgtDev/Include/EGkIntersLinePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
|
|
#include "/EgtDev/Include/EGkIntersLineVolZmap.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <array>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const double SRF_SMALL_SQDIST = 100 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::GetGraphicSnapPoint( int nSnap, const Point3d& ptWin, int nW, int nH, Point3d& ptSel)
|
|
{
|
|
// reset dati associati a ultimo punto snap
|
|
m_nLastSnapId = GDB_ID_NULL ;
|
|
m_bLastSnapDirOk = false ;
|
|
// verifico validità GDB
|
|
if ( m_pGeomDB == nullptr)
|
|
return false ;
|
|
// se Snap Sketch o Grid, devo trovare il punto sulla griglia
|
|
if ( nSnap == SP_SKETCH || nSnap == SP_GRID) {
|
|
if ( FindGridSnapPoint( ( nSnap == SP_SKETCH), ptWin)) {
|
|
ptSel = m_ptLastSnapPnt ;
|
|
return true ;
|
|
}
|
|
}
|
|
// se Snap Intersection, devo trovare l'intersezione tra due entità inquadrate
|
|
else if ( nSnap == SP_INTERS) {
|
|
if ( FindSelectedIntersectionPoint( ptWin, nW, nH)) {
|
|
ptSel = m_ptLastSnapPnt ;
|
|
return true ;
|
|
}
|
|
}
|
|
// altrimenti devo trovare il punto dall'entità inquadrata
|
|
else {
|
|
if ( FindSelectedSnapPoint( nSnap, ptWin, nW, nH)) {
|
|
ptSel = m_ptLastSnapPnt ;
|
|
return true ;
|
|
}
|
|
}
|
|
// non trovato
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::GetGridSnapPointZ( bool bSketch, const Point3d& ptWin, const Point3d& ptGrid, Point3d& ptSel) const
|
|
{
|
|
// recupero il riferimento di griglia
|
|
Frame3d frGrid = GetGridFrame() ;
|
|
|
|
// calcolo un punto e la direzione della linea di mira
|
|
Point3d ptLine ;
|
|
if ( ! UnProject( ptWin, ptLine))
|
|
return false ;
|
|
Vector3d vtLine = - m_vtDirCamera ;
|
|
if ( ! m_bOrthographic) {
|
|
// nella vista prospettica la direzione di mira è data dalla linea che coingiunge le proiezioni di ptWin sui piani near e far
|
|
Point3d ptLine2 ;
|
|
if ( ! UnProject( Point3d( ptWin.x, ptWin.y, 1), ptLine2))
|
|
return false ;
|
|
vtLine = ptLine - ptLine2 ;
|
|
vtLine.Normalize() ;
|
|
}
|
|
|
|
// piano di elevazione :
|
|
// per il punto di griglia, contenente la perp. alla griglia e più perp. possibile alla direzione di mira
|
|
Vector3d vtNorm = vtLine - ( vtLine * frGrid.VersZ()) * frGrid.VersZ() ;
|
|
if ( ! vtNorm.Normalize())
|
|
return false ;
|
|
|
|
// determino l'intersezione della linea di mira con il piano di elevazione
|
|
double dDenom = vtLine * vtNorm ;
|
|
if ( abs( dDenom) < COS_ORTO_ANG_SMALL)
|
|
return false ;
|
|
double dU = ( ( ptGrid - ptLine) * vtNorm) / dDenom ;
|
|
Point3d ptNear = ptLine + dU * vtLine ;
|
|
|
|
// proietto il punto sulla linea di elevazione
|
|
double dDeltaZ = ( ptNear - ptGrid) * frGrid.VersZ() ;
|
|
if ( ! bSketch)
|
|
dDeltaZ = floor( dDeltaZ / m_dSnapStep + 0.5) * m_dSnapStep ;
|
|
ptSel = ptGrid + dDeltaZ * frGrid.VersZ() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindGridSnapPoint( bool bSketch, const Point3d& ptWin)
|
|
{
|
|
// recupero il riferimento di griglia
|
|
Frame3d frGrid = GetGridFrame() ;
|
|
|
|
// calcolo un punto e la direzione della linea di mira
|
|
Point3d ptLine ;
|
|
if ( ! UnProject( ptWin, ptLine))
|
|
return false ;
|
|
Vector3d vtLine = - m_vtDirCamera ;
|
|
if ( ! m_bOrthographic) {
|
|
// nella vista prospettica la direzione di mira è data dalla linea che coingiunge le proiezioni di ptWin sui piani near e far
|
|
Point3d ptLine2 ;
|
|
if ( ! UnProject( Point3d( ptWin.x, ptWin.y, 1), ptLine2))
|
|
return false ;
|
|
vtLine = ptLine - ptLine2 ;
|
|
vtLine.Normalize() ;
|
|
}
|
|
|
|
// determino l'intersezione di questa linea con il piano della griglia
|
|
double dDenom = vtLine * frGrid.VersZ() ;
|
|
if ( abs( dDenom) < COS_ORTO_ANG_SMALL)
|
|
return false ;
|
|
double dU = ( ( frGrid.Orig() - ptLine) * frGrid.VersZ()) / dDenom ;
|
|
m_ptLastSnapPnt = ptLine + dU * vtLine ;
|
|
|
|
// porto il punto sul piano di griglia
|
|
m_ptLastSnapPnt.ToLoc( frGrid) ;
|
|
// se punto grid, devo arrotondare al nodo di griglia più vicino
|
|
if ( ! bSketch) {
|
|
m_ptLastSnapPnt.x = floor( m_ptLastSnapPnt.x / m_dSnapStep + 0.5) * m_dSnapStep ;
|
|
m_ptLastSnapPnt.y = floor( m_ptLastSnapPnt.y / m_dSnapStep + 0.5) * m_dSnapStep ;
|
|
}
|
|
// il punto deve stare sulla griglia
|
|
m_ptLastSnapPnt.z = 0 ;
|
|
// lo riporto in globale
|
|
m_ptLastSnapPnt.ToGlob( frGrid) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindSelectedIntersectionPoint( const Point3d& ptWin, int nW, int nH)
|
|
{
|
|
// --- l'intersezione viene calcolata nel piano della griglia ---
|
|
// salvo eventuale ultima entità precedentemente selezionata
|
|
int nPrevSel = GetFirstSelectedObj() ;
|
|
// verifico siano state selezionate delle entità
|
|
int nSel ;
|
|
Select( ptWin, nW, nH, nSel) ;
|
|
if ( nSel <= 0)
|
|
return false ;
|
|
// cerco le prime due curve inquadrate con i loro riferimenti
|
|
const ICurve* pCrv[2] ;
|
|
Frame3d frEnt[2] ;
|
|
int nIds[2] ;
|
|
double dWinZ = 0 ;
|
|
int nCrvNum = 0 ;
|
|
for ( int nObjId = GetFirstSelectedObj() ; nObjId != GDB_ID_NULL && nCrvNum < 2 ; nObjId = GetNextSelectedObj()) {
|
|
// se non è entità geometrica
|
|
const IGeoObj* pGObj ;
|
|
if ( ( pGObj = m_pGeomDB->GetGeoObj( nObjId)) == nullptr)
|
|
continue ;
|
|
if ( ( pGObj->GetType() & GEO_CURVE) != 0) {
|
|
pCrv[nCrvNum] = GetCurve( pGObj) ;
|
|
if ( ! m_pGeomDB->GetGlobFrame( nObjId, frEnt[nCrvNum]))
|
|
return false ;
|
|
nIds[nCrvNum] = nObjId ;
|
|
dWinZ += 0.5 * GetSelectedObjWinZ() ;
|
|
++ nCrvNum ;
|
|
}
|
|
}
|
|
// se nessuna curva, esco
|
|
if ( nCrvNum == 0)
|
|
return false ;
|
|
// se una sola curva, può essere auto intersezione
|
|
if ( nCrvNum == 1) {
|
|
// recupero il riferimento di griglia
|
|
Frame3d frGrid = GetGridFrame() ;
|
|
// se il riferimento della curva è diverso da quello della griglia, devo trasformarla
|
|
PtrOwner<ICurve> pcrvTrans0 ;
|
|
if ( ! AreSameFrame( frEnt[0], frGrid)) {
|
|
pcrvTrans0.Set( pCrv[0]->Clone()) ;
|
|
if ( IsNull( pcrvTrans0))
|
|
return false ;
|
|
pcrvTrans0->LocToLoc( frEnt[0], frGrid) ;
|
|
pCrv[0] = pcrvTrans0 ;
|
|
}
|
|
// uso il punto sketch come punto vicino e lo porto nel riferimento della griglia
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, dWinZ) ;
|
|
Point3d ptNear ;
|
|
if ( ! UnProject( ptWinZ, ptNear))
|
|
ptNear = ORIG ;
|
|
ptNear.ToLoc( frGrid) ;
|
|
// calcolo il punto di intersezione sulla prima curva più vicino al punto di riferimento
|
|
SelfIntersCurve sintC( *pCrv[0]) ;
|
|
if ( ! sintC.GetIntersPointNearTo( ptNear, m_ptLastSnapPnt))
|
|
return false ;
|
|
m_nLastSnapId = nIds[0] ;
|
|
m_ptLastSnapPnt.ToGlob( frGrid) ;
|
|
m_bLastSnapDirOk = false ;
|
|
return true ;
|
|
}
|
|
// altrimenti due curve, procedo normalmente
|
|
// recupero il riferimento di griglia
|
|
Frame3d frGrid = GetGridFrame() ;
|
|
// se il riferimento della prima curva è diverso da quello della griglia, devo trasformarla
|
|
PtrOwner<ICurve> pcrvTrans0 ;
|
|
if ( ! AreSameFrame( frEnt[0], frGrid)) {
|
|
pcrvTrans0.Set( pCrv[0]->Clone()) ;
|
|
if ( IsNull( pcrvTrans0))
|
|
return false ;
|
|
pcrvTrans0->LocToLoc( frEnt[0], frGrid) ;
|
|
pCrv[0] = pcrvTrans0 ;
|
|
}
|
|
// se il riferimento della seconda curva è diverso da quello della griglia, devo trasformarla
|
|
PtrOwner<ICurve> pcrvTrans1 ;
|
|
if ( ! AreSameFrame( frEnt[1], frGrid)) {
|
|
pcrvTrans1.Set( pCrv[1]->Clone()) ;
|
|
if ( IsNull( pcrvTrans1))
|
|
return false ;
|
|
pcrvTrans1->LocToLoc( frEnt[1], frGrid) ;
|
|
pCrv[1] = pcrvTrans1 ;
|
|
}
|
|
// uso il punto sketch come punto vicino e lo porto nel riferimento della griglia
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, dWinZ) ;
|
|
Point3d ptNear ;
|
|
if ( ! UnProject( ptWinZ, ptNear))
|
|
ptNear = ORIG ;
|
|
ptNear.ToLoc( frGrid) ;
|
|
// calcolo il punto di intersezione sulla prima curva più vicino al punto di riferimento
|
|
IntersCurveCurve intCC( *pCrv[0], *pCrv[1], true) ;
|
|
if ( ! intCC.GetIntersPointNearTo( ( nPrevSel == nIds[1] ? 1 : 0), ptNear, m_ptLastSnapPnt))
|
|
return false ;
|
|
m_nLastSnapId = nIds[0] ;
|
|
m_ptLastSnapPnt.ToGlob( frGrid) ;
|
|
m_bLastSnapDirOk = false ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindSelectedSnapPoint( int nSnap, const Point3d& ptWin, int nW, int nH)
|
|
{
|
|
// seleziono e verifico siano state selezionate delle entità
|
|
int nSel ;
|
|
Select( ptWin, nW, nH, nSel) ;
|
|
if ( nSel <= 0)
|
|
return false ;
|
|
// cerco il punto notevole più vicino alla selezione tra le entità selezionate
|
|
bool bFound = false ;
|
|
double dMinSqDist = INFINITO * INFINITO ;
|
|
for ( int nId = GetFirstSelectedObj() ; nId != GDB_ID_NULL ; nId = GetNextSelectedObj()) {
|
|
// se non è entità geometrica
|
|
const IGeoObj* pGObj ;
|
|
if ( ( pGObj = m_pGeomDB->GetGeoObj( nId)) == nullptr)
|
|
continue ;
|
|
// recupero riferimento dell'entità
|
|
Frame3d frEnt ;
|
|
if ( ! m_pGeomDB->GetGlobFrame( nId, frEnt))
|
|
continue ;
|
|
// se punto
|
|
if ( pGObj->GetType() == GEO_PNT3D) {
|
|
// recupero il geo-punto
|
|
const IGeoPoint3d* pGP = GetGeoPoint3d( pGObj) ;
|
|
// recupero il punto
|
|
Point3d ptP = GetToGlob( pGP->GetPoint(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
// se vettore
|
|
else if ( pGObj->GetType() == GEO_VECT3D) {
|
|
// recupero il geo-vettore
|
|
const IGeoVector3d* pGV = GetGeoVector3d( pGObj) ;
|
|
// recupero il punto base
|
|
Point3d ptP = GetToGlob( pGV->GetBase(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pGV->GetVector(), frEnt) ;
|
|
}
|
|
// recupero il punto tip
|
|
Point3d ptTip = GetToGlob( pGV->GetBase() + pGV->GetVector(), frEnt) ;
|
|
if ( VerifySnapPoint( ptTip, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptTip ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pGV->GetVector(), frEnt) ;
|
|
}
|
|
}
|
|
// se frame
|
|
else if ( pGObj->GetType() == GEO_FRAME3D) {
|
|
// recupero il geo-frame
|
|
const IGeoFrame3d* pGF = GetGeoFrame3d( pGObj) ;
|
|
// recupero l'origine del riferimento
|
|
Point3d ptP = GetToGlob( pGF->GetFrame().Orig(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
// se curva composita
|
|
else if ( pGObj->GetType() == CRV_COMPO) {
|
|
// recupero la curva composita
|
|
const ICurveComposite* pCrvCompo = GetCurveComposite( pGObj) ;
|
|
// verifico i punti notevoli della curva composita
|
|
if ( FindCurveCompoSnapPoint( nSnap, ptWin, nId, frEnt, pCrvCompo, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se curva semplice
|
|
else if ( ( pGObj->GetType() & GEO_CURVE) != 0) {
|
|
// recupero la curva
|
|
const ICurve* pCrv = GetCurve( pGObj) ;
|
|
// verifico i punti notevoli della curva
|
|
if ( FindCurveSnapPoint( nSnap, ptWin, nId, frEnt, pCrv, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se superficie trimesh
|
|
else if ( pGObj->GetType() == SRF_TRIMESH) {
|
|
// recupero la superficie
|
|
const ISurfTriMesh* pStm = GetSurfTriMesh( pGObj) ;
|
|
// verifico i punti notevoli della superficie
|
|
if ( FindSurfTMSnapPoint( nSnap, ptWin, nId, frEnt, pStm, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se regione
|
|
else if ( pGObj->GetType() == SRF_FLATRGN) {
|
|
// recupero la regione
|
|
const ISurfFlatRegion* pReg = GetSurfFlatRegion( pGObj) ;
|
|
// verifico i punti notevoli della regione
|
|
if ( FindSurfFRSnapPoint( nSnap, ptWin, nId, frEnt, pReg, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se superficie di Bezier
|
|
else if ( pGObj->GetType() == SRF_BEZIER) {
|
|
// recupero la superficie
|
|
const ISurfBezier* pSbz = GetSurfBezier( pGObj) ;
|
|
const ISurfTriMesh* pStm = pSbz->GetAuxSurf() ;
|
|
// verifico i punti notevoli della superficie ausiliaria associata
|
|
if ( FindSurfTMSnapPoint( nSnap, ptWin, nId, frEnt, pStm, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se solido Zmap
|
|
else if ( pGObj->GetType() == VOL_ZMAP) {
|
|
// recupero il solido
|
|
const IVolZmap* pVzm = GetVolZmap( pGObj) ;
|
|
// verifico i punti notevoli del solido
|
|
if ( FindVolZmapSnapPoint( nSnap, ptWin, nId, frEnt, pVzm, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se testo
|
|
else if ( pGObj->GetType() == EXT_TEXT) {
|
|
// recupero il testo
|
|
const IExtText* pTxt = GetExtText( pGObj) ;
|
|
// verifico i punti notevoli del testo
|
|
if ( FindTextSnapPoint( nSnap, ptWin, nId, frEnt, pTxt, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
// se quotatura
|
|
else if ( pGObj->GetType() == EXT_DIMENSION) {
|
|
// recupero la quotatura
|
|
const IExtDimension* pDim = GetExtDimension( pGObj) ;
|
|
// verifico i punti notevoli della quotatura
|
|
if ( FindDimensionSnapPoint( nSnap, ptWin, nId, frEnt, pDim, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
}
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindCurveSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const ICurve* pCrv, double& dMinSqDist)
|
|
{
|
|
// recupero il punto
|
|
bool bFound = false ;
|
|
Point3d ptP ;
|
|
switch ( nSnap) {
|
|
case SP_END :
|
|
// punto iniziale
|
|
if ( pCrv->GetStartPoint( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
pCrv->GetStartDir( m_vtLastSnapDir) ;
|
|
m_vtLastSnapDir.ToGlob( frEnt) ;
|
|
m_vtLastSnapDir.Invert() ;
|
|
}
|
|
}
|
|
// punto finale
|
|
if ( pCrv->GetEndPoint( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
pCrv->GetEndDir( m_vtLastSnapDir) ;
|
|
m_vtLastSnapDir.ToGlob( frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_MID :
|
|
if ( pCrv->GetMidPoint( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
pCrv->GetMidDir( m_vtLastSnapDir) ;
|
|
m_vtLastSnapDir.ToGlob( frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTER :
|
|
if ( pCrv->GetCenterPoint( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
if ( pCrv->GetType() == CRV_ARC) {
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetCurveArc( pCrv)->GetNormVersor() ;
|
|
m_vtLastSnapDir.ToGlob( frEnt) ;
|
|
}
|
|
else
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTROID :
|
|
if ( pCrv->GetCentroid( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_NEAR :
|
|
case SP_TANG :
|
|
case SP_PERP :
|
|
case SP_MINDIST :
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z media da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjWinZ()) ;
|
|
// lo porto da spazio grafico a spazio geometrico globale
|
|
Point3d ptRef ;
|
|
UnProject( ptWinZ, ptRef) ;
|
|
// lo porto nel frame della curva
|
|
ptRef.ToLoc( frEnt) ;
|
|
// determino il punto più vicino della curva a questo
|
|
MinDistPCInfo mdInfo ;
|
|
DistPointCurve dstPtCurve( ptRef, *pCrv) ;
|
|
if ( dstPtCurve.GetMinDistInfo( 0, mdInfo)) {
|
|
ptP = mdInfo.ptQ ;
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrv, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWinZ, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
Point3d ptTmp ;
|
|
pCrv->GetPointTang( mdInfo.dPar, ICurve::FROM_MINUS, ptTmp, m_vtLastSnapDir) ;
|
|
m_vtLastSnapDir.ToGlob( frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::VerifySnapPoint( const Point3d& ptP, const Point3d& ptWin, double& dMinSqDist) const
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z minima (più vicina a osservatore) da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjMinWinZ()) ;
|
|
// punto di riferimento nello spazio geometrico 3d
|
|
Point3d ptRef ;
|
|
if ( ! UnProject( ptWinZ, ptRef))
|
|
return false ;
|
|
// recupero la direzione di mira
|
|
Vector3d vtDir = - m_vtDirCamera ;
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal punto dato
|
|
Point3d ptCfr = ptRef + (( ptP - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptP, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
dMinSqDist = dSqDist ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::AdjustForCurveExtr( const Point3d& ptWin, const Frame3d& frEnt, const ICurve* pCrv,
|
|
Point3d& ptP)
|
|
{
|
|
// recupero l'eventuale estrusione della curva
|
|
double dTh ;
|
|
Vector3d vtExtr ;
|
|
if ( ! pCrv->GetExtrusion( vtExtr) || vtExtr.IsSmall() ||
|
|
! pCrv->GetThickness( dTh) || abs( dTh) < EPS_SMALL)
|
|
return false ;
|
|
vtExtr *= dTh ;
|
|
|
|
// il punto di riferimento deriva da XY su viewport e Z media da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjWinZ()) ;
|
|
// lo porto da spazio grafico a spazio geometrico globale
|
|
Point3d ptRef ;
|
|
UnProject( ptWinZ, ptRef) ;
|
|
// lo porto nel frame della curva
|
|
ptRef.ToLoc( frEnt) ;
|
|
|
|
// determino la minima distanza dalla curva base
|
|
double dBaseSqDist = INFINITO ;
|
|
DistPointCurve dstPtBCurve( ptRef, *pCrv) ;
|
|
dstPtBCurve.GetSqDist( dBaseSqDist) ;
|
|
// determino la minima distanza dalla curva estrusa (sposto il punto del contrario dell'estrusione)
|
|
double dExtrSqDist = INFINITO ;
|
|
DistPointCurve dstPtECurve( ptRef - vtExtr, *pCrv) ;
|
|
dstPtECurve.GetSqDist( dExtrSqDist) ;
|
|
// se più vicino a base non devo modificare il punto
|
|
if ( dBaseSqDist <= dExtrSqDist)
|
|
return false ;
|
|
// più vicino ad estrusione, quindi la aggiungo
|
|
ptP += vtExtr ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindCurveCompoSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const ICurveComposite* pCrvCompo, double& dMinSqDist)
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z media da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjWinZ()) ;
|
|
// punto di riferimento nello spazio geometrico 3d
|
|
Point3d ptRef ;
|
|
if ( ! UnProject( ptWinZ, ptRef))
|
|
return false ;
|
|
// porto il punto nel riferimento della curva
|
|
ptRef.ToLoc( frEnt) ;
|
|
// se richiesto il centro di gravità (baricentro, centroide)
|
|
if ( nSnap == SP_CENTROID) {
|
|
Point3d ptP ;
|
|
bool bFound = false ;
|
|
if ( pCrvCompo->GetCentroid( ptP)) {
|
|
AdjustForCurveExtr( ptWin, frEnt, pCrvCompo, ptP) ;
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
return bFound ;
|
|
}
|
|
// altrimenti opero sulle curve componenti elementari
|
|
// determino la curva elementare più vicina al punto di riferimento
|
|
int nCrv = - 1 ;
|
|
double dPar ;
|
|
int nFlag ;
|
|
// cerco il punto della curva più vicino, dal suo parametro deduco la curva elementare
|
|
if ( DistPointCurve( ptRef, *pCrvCompo).GetParamAtMinDistPoint( 0, dPar, nFlag))
|
|
nCrv = static_cast<int>( dPar) ;
|
|
// lavoro sulla curva elementare
|
|
bool bFound = false ;
|
|
const ICurve* pCrv = pCrvCompo->GetCurve( nCrv) ;
|
|
if ( pCrv != nullptr) {
|
|
// vettore estrusione e spessore della curva composita
|
|
Vector3d vtExtr = V_NULL ;
|
|
pCrvCompo->GetExtrusion( vtExtr) ;
|
|
double dThick = 0 ;
|
|
pCrvCompo->GetThickness( dThick) ;
|
|
// imposto estrusione e spessore della curva composita
|
|
(const_cast<ICurve*>(pCrv))->SetExtrusion( vtExtr) ;
|
|
(const_cast<ICurve*>(pCrv))->SetThickness( dThick) ;
|
|
// verifico i punti notevoli della curva
|
|
if ( FindCurveSnapPoint( nSnap, ptWin, nId, frEnt, pCrv, dMinSqDist))
|
|
bFound = true ;
|
|
// ripristino valori originali
|
|
(const_cast<ICurve*>(pCrv))->SetExtrusion( V_NULL) ;
|
|
(const_cast<ICurve*>(pCrv))->SetThickness( 0) ;
|
|
}
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindSurfTMSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const ISurfTriMesh* pStm, double& dMinSqDist)
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z minima (più vicina a osservatore) da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjMinWinZ()) ;
|
|
// punto di riferimento nello spazio geometrico 3d
|
|
Point3d ptRef ;
|
|
if ( ! UnProject( ptWinZ, ptRef))
|
|
return false ;
|
|
// porto il punto nel riferimento della superficie
|
|
ptRef.ToLoc( frEnt) ;
|
|
// recupero la direzione di mira e la porto nel riferimento della superficie
|
|
Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ;
|
|
// recupero il raggio del box di ingombro
|
|
double dBlRad = 1000 ;
|
|
const ObjEGrGraphics* pGraphics = GetObjEGrGraphics( pStm) ;
|
|
if ( pGraphics != nullptr) {
|
|
BBox3d b3Loc ;
|
|
if ( pGraphics->GetLocalBBox( b3Loc))
|
|
b3Loc.GetRadius( dBlRad) ;
|
|
}
|
|
// punto davanti all'oggetto lungo il raggio di mira
|
|
Point3d ptMir = ptRef - vtDir * 2 * dBlRad ;
|
|
double dLenMir = 4 * dBlRad ;
|
|
|
|
// determino se oggetto trasparente
|
|
Color cCol ;
|
|
bool bAlpha = ( m_pGeomDB->GetCalcMaterial( nId, cCol) && cCol.GetIntAlpha() <= ALPHA_LIM) ;
|
|
|
|
// se richiesto il centro di gravità (baricentro, centroide)
|
|
if ( nSnap == SP_CENTROID) {
|
|
Point3d ptP ;
|
|
bool bFound = false ;
|
|
if ( pStm->GetCentroid( ptP)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal vertice
|
|
Point3d ptCfr = ptRef + (( ptP - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptP, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptP, frEnt) ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
// se trovato e modalità shading o hiddenline, la favorisco perchè davanti alle possibili successive
|
|
if ( bFound && ! ( bAlpha || m_nShowMode == SM_WIREFRAME))
|
|
dMinSqDist = 0 ;
|
|
return bFound ;
|
|
}
|
|
|
|
// cerco i triangoli intersecati dalla linea di mira
|
|
ILSIVECTOR vInfo ;
|
|
if ( ! IntersLineSurfTm( ptMir, vtDir, dLenMir, *pStm, vInfo))
|
|
return false ;
|
|
// se non trovato alcunchè, cerco le linee che partono dagli angoli e dai punti medi dei lati del rettangolo di mira
|
|
VCT3DVECTOR vVtWind = { {0.51, 0.51, 0}, {0, 0.51, 0}, {-0.51, 0.51, 0}, {-0.51, 0, 0},
|
|
{-0.51, -0.51, 0}, {0, -0.51, 0}, {0.51, -0.51, 0}, {0.51, 0, 0},
|
|
{0.25, 0.51, 0}, {-0.25, 0.51, 0}, {-0.51, 0.25, 0}, {-0.51, -0.25, 0},
|
|
{-0.25, -0.51, 0}, {0.25, -0.51, 0}, {0.51, -0.25, 0}, {0.51, 0.25, 0}} ;
|
|
for ( int i = 0 ; i < int( vVtWind.size()) && vInfo.empty() ; ++ i) {
|
|
// determino punto su vertice del rettangolo di selezione
|
|
Point3d ptWinZ2 = ptWinZ + vVtWind[i].x * m_nSelH * X_AX + vVtWind[i].y * m_nSelW * Y_AX ;
|
|
// ne ricavo punto di mira
|
|
Point3d ptMir2 ;
|
|
if ( ! UnProject( ptWinZ2, ptMir2))
|
|
return false ;
|
|
ptMir2.ToLoc( frEnt) ;
|
|
ptMir2 -= vtDir * 2 * dBlRad ;
|
|
// interseco con la superficie
|
|
if ( ! IntersLineSurfTm( ptMir2, vtDir, dLenMir, *pStm, vInfo))
|
|
return false ;
|
|
}
|
|
if ( vInfo.empty())
|
|
return false ;
|
|
|
|
// elaborazione a seconda del tipo di snap
|
|
bool bFound = false ;
|
|
switch ( nSnap) {
|
|
case SP_END :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// punto di intersezione
|
|
Point3d ptInt = vInfo[i].ptI ;
|
|
// punto finale più vicino
|
|
int nF = pStm->GetFacetFromTria( vInfo[i].nT) ;
|
|
Point3d ptEnd ;
|
|
Vector3d vtN ;
|
|
if ( pStm->GetFacetNearestEndPoint( nF, ptInt, ptEnd, vtN)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal vertice
|
|
Point3d ptCfr = ptRef + (( ptEnd - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptEnd, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptEnd, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( vtN, frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_MID :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// punto di intersezione
|
|
Point3d ptInt = vInfo[i].ptI ;
|
|
// punto medio più vicino
|
|
int nF = pStm->GetFacetFromTria( vInfo[i].nT) ;
|
|
Point3d ptMid ;
|
|
Vector3d vtN ;
|
|
if ( pStm->GetFacetNearestMidPoint( nF, ptInt, ptMid, vtN)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal punto medio
|
|
Point3d ptCfr = ptRef + (( ptMid - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptMid, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptMid, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( vtN, frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTER :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// centro più vicino
|
|
int nF = pStm->GetFacetFromTria( vInfo[i].nT) ;
|
|
Point3d ptCen ;
|
|
Vector3d vtN ;
|
|
if ( pStm->GetFacetCenter( nF, ptCen, vtN)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal centro
|
|
Point3d ptCfr = ptRef + (( ptCen - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptCen, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptCen, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( vtN, frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_NEAR :
|
|
case SP_TANG :
|
|
case SP_PERP :
|
|
case SP_MINDIST :
|
|
// considero solo il primo triangolo intersecato
|
|
// la distanza è nulla e la confronto con il minimo
|
|
if ( 0 < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = 0 ;
|
|
m_nLastSnapId = nId ;
|
|
// punto
|
|
Point3d ptInt = vInfo[0].ptI ;
|
|
m_ptLastSnapPnt = GetToGlob( ptInt, frEnt) ;
|
|
// direzione
|
|
Triangle3d Tria ;
|
|
TriNormals3d Tnorms ;
|
|
Vector3d vtNorm ;
|
|
if ( pStm->GetTriangle( vInfo[0].nT, Tria) &&
|
|
pStm->GetTriangleSmoothNormals( vInfo[0].nT, Tnorms) &&
|
|
CalcNormal( ptInt, Tria, Tnorms, vtNorm)) {
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( vtNorm, frEnt) ;
|
|
}
|
|
else
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
|
|
// se trovato e modalità shading o hiddenline, la favorisco perchè davanti alle possibili successive
|
|
if ( bFound && ! ( bAlpha || m_nShowMode == SM_WIREFRAME) && dMinSqDist < SRF_SMALL_SQDIST)
|
|
dMinSqDist = 0 ;
|
|
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindSurfFRSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const ISurfFlatRegion* pSfr, double& dMinSqDist)
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z minima (più vicina a osservatore) da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjMinWinZ()) ;
|
|
// punto di riferimento nello spazio geometrico 3d
|
|
Point3d ptRef ;
|
|
if ( ! UnProject( ptWinZ, ptRef))
|
|
return false ;
|
|
// porto il punto nel riferimento della superficie
|
|
ptRef.ToLoc( frEnt) ;
|
|
// recupero la direzione di mira e la porto nel riferimento della superficie
|
|
Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ;
|
|
|
|
// determino se oggetto trasparente
|
|
Color cCol ;
|
|
bool bAlpha = ( m_pGeomDB->GetCalcMaterial( nId, cCol) && cCol.GetIntAlpha() <= ALPHA_LIM) ;
|
|
|
|
// elaborazione a seconda del tipo di snap
|
|
bool bFound = false ;
|
|
// se richiesto il centro di gravità (baricentro, centroide)
|
|
if ( nSnap == SP_CENTROID) {
|
|
Point3d ptP ;
|
|
if ( pSfr->GetCentroid( ptP)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal centro
|
|
Point3d ptCfr = ptRef + (( ptP - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptP, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptP, frEnt) ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
}
|
|
// se richiesto il centro (è il centroide del chunk più vicino)
|
|
else if ( nSnap == SP_CENTER) {
|
|
Point3d ptP ;
|
|
for ( int i = 0 ; i < pSfr->GetChunkCount() ; ++ i) {
|
|
if ( pSfr->GetChunkCentroid( i, ptP)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal centro
|
|
Point3d ptCfr = ptRef + (( ptP - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptP, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptP, frEnt) ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se richiesto punto vicino o assimilabile
|
|
else if ( nSnap == SP_NEAR || nSnap == SP_TANG || nSnap == SP_PERP || nSnap == SP_MINDIST) {
|
|
// recupero il piano della regione
|
|
Plane3d plReg ;
|
|
plReg.Set( pSfr->GetPlanePoint(), pSfr->GetNormVersor()) ;
|
|
// interseco la linea di mira con il piano della regione
|
|
Point3d ptInt ;
|
|
if ( IntersLinePlane( ptRef, vtDir, INFINITO, plReg, ptInt, false) != ILPT_YES)
|
|
return false ;
|
|
// assegno il risultato
|
|
bFound = true ;
|
|
dMinSqDist = 0 ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptInt, frEnt) ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
// in tutti gli altri casi
|
|
else {
|
|
// cerco sui contorni della regione
|
|
for ( int i = 0 ; i < pSfr->GetChunkCount() ; ++ i) {
|
|
for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; ++ j) {
|
|
PtrOwner<ICurve> pCrv( pSfr->GetLoop( i, j)) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
if ( pCrv->GetType() == CRV_COMPO) {
|
|
ICurveComposite* pCrvCompo = GetCurveComposite( pCrv) ;
|
|
if ( FindCurveCompoSnapPoint( nSnap, ptWin, nId, frEnt, pCrvCompo, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
else {
|
|
if ( FindCurveSnapPoint( nSnap, ptWin, nId, frEnt, pCrv, dMinSqDist))
|
|
bFound = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// se trovato e modalità shading o hiddenline, la favorisco perchè davanti alle possibili successive
|
|
if ( bFound && ! ( bAlpha || m_nShowMode == SM_WIREFRAME) && dMinSqDist < SRF_SMALL_SQDIST)
|
|
dMinSqDist = 0 ;
|
|
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindVolZmapSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const IVolZmap* pVzm, double& dMinSqDist)
|
|
{
|
|
// il punto di riferimento deriva da XY su viewport e Z minima (più vicina a osservatore) da selezione
|
|
Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjMinWinZ()) ;
|
|
// punto di riferimento nello spazio geometrico 3d
|
|
Point3d ptRef ;
|
|
if ( ! UnProject( ptWinZ, ptRef))
|
|
return false ;
|
|
// porto il punto nel riferimento della superficie
|
|
ptRef.ToLoc( frEnt) ;
|
|
// recupero la direzione di mira e la porto nel riferimento della superficie
|
|
Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ;
|
|
// recupero il raggio del box di ingombro
|
|
double dBlRad = 1000 ;
|
|
const ObjEGrGraphics* pGraphics = GetObjEGrGraphics( pVzm) ;
|
|
if ( pGraphics != nullptr) {
|
|
BBox3d b3Loc ;
|
|
if ( pGraphics->GetLocalBBox( b3Loc))
|
|
b3Loc.GetRadius( dBlRad) ;
|
|
}
|
|
// punto davanti all'oggetto lungo il raggio di mira
|
|
Point3d ptMir = ptRef - vtDir * 2 * dBlRad ;
|
|
|
|
// determino se oggetto trasparente
|
|
Color cCol ;
|
|
bool bAlpha = ( m_pGeomDB->GetCalcMaterial( nId, cCol) && cCol.GetIntAlpha() <= ALPHA_LIM) ;
|
|
|
|
// se richiesto il centro di gravità (baricentro, centroide)
|
|
if ( nSnap == SP_CENTROID) {
|
|
Point3d ptP ;
|
|
bool bFound = false ;
|
|
BBox3d b3Loc ;
|
|
if ( pVzm->GetLocalBBox( b3Loc) && b3Loc.GetCenter( ptP)) {
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal vertice
|
|
Point3d ptCfr = ptRef + (( ptP - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptP, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptP, frEnt) ;
|
|
m_bLastSnapDirOk = false ;
|
|
}
|
|
}
|
|
// se trovato e modalità shading o hiddenline, la favorisco perchè davanti alle possibili successive
|
|
if ( bFound && ! ( bAlpha || m_nShowMode == SM_WIREFRAME))
|
|
dMinSqDist = 0 ;
|
|
return bFound ;
|
|
}
|
|
|
|
// cerco i triangoli intersecati dalla linea di mira
|
|
ILZIVECTOR vInfo ;
|
|
if ( ! IntersLineVolZmap( ptMir, vtDir, *pVzm, vInfo))
|
|
return false ;
|
|
// se non trovato alcunchè, cerco le linee che partono dagli angoli del rettangolo di mira
|
|
Vector3d vtWinD( -1, -1, 0) ;
|
|
for ( int i = 0 ; i < 4 && vInfo.size() == 0 ; ++ i) {
|
|
// determino punto su vertice del rettangolo di selezione
|
|
Point3d ptWinZ2 = ptWinZ + vtWinD.x * m_nSelH * X_AX + vtWinD.y * m_nSelW * Y_AX ;
|
|
vtWinD.Rotate( Z_AX, 0, 1) ;
|
|
// ne ricavo punto di mira
|
|
Point3d ptMir2 ;
|
|
if ( ! UnProject( ptWinZ2, ptMir2))
|
|
return false ;
|
|
ptMir2.ToLoc( frEnt) ;
|
|
ptMir2 -= vtDir * 2 * dBlRad ;
|
|
// interseco con la superficie
|
|
if ( ! IntersLineVolZmap( ptMir2, vtDir, *pVzm, vInfo))
|
|
return false ;
|
|
}
|
|
if ( vInfo.size() == 0)
|
|
return false ;
|
|
|
|
// elaborazione a seconda del tipo di snap
|
|
bool bFound = false ;
|
|
switch ( nSnap) {
|
|
case SP_END :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// triangolo
|
|
Triangle3d& trTria = vInfo[i].trTria ;
|
|
// recupero il vertice del triangolo più vicino alla linea di mira
|
|
int nVert ; double dSqDist ;
|
|
if ( GetTriaVertexNearestToLine( trTria, ptRef, vtDir, nVert, dSqDist) && dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( trTria.GetP( nVert), frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( trTria.GetN(), frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_MID :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// triangolo
|
|
Triangle3d& trTria = vInfo[i].trTria ;
|
|
// recupero il punto medio del lato del triangolo più vicino alla linea di mira
|
|
Point3d ptMid ; double dSqDist ;
|
|
if ( GetTriaMidEdgeNearestToLine( trTria, ptRef, vtDir, ptMid, dSqDist) && dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptMid, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( trTria.GetN(), frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTER :
|
|
{
|
|
// con wireframe devo provare tutti i triangoli intersecati, con shading e hiddenline solo il primo
|
|
int nTtot = (( bAlpha || m_nShowMode == SM_WIREFRAME) ? int( vInfo.size()) : 1) ;
|
|
for ( int i = 0 ; i < nTtot ; ++ i) {
|
|
// triangolo
|
|
Triangle3d& trTria = vInfo[i].trTria ;
|
|
// centro più vicino
|
|
Point3d ptCen = trTria.GetCentroid() ;
|
|
// il punto di confronto è quello sulla linea di mira a minima distanza dal centro
|
|
Point3d ptCfr = ptRef + (( ptCen - ptRef) * vtDir) * vtDir ;
|
|
// determino la distanza e la confronto con il minimo
|
|
double dSqDist = SqDist( ptCen, ptCfr) ;
|
|
if ( dSqDist < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = dSqDist ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( ptCen, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( trTria.GetN(), frEnt) ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case SP_NEAR :
|
|
case SP_TANG :
|
|
case SP_PERP :
|
|
case SP_MINDIST :
|
|
// considero solo il primo triangolo intersecato
|
|
// la distanza è nulla e la confronto con il minimo
|
|
if ( 0 < dMinSqDist) {
|
|
bFound = true ;
|
|
dMinSqDist = 0 ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = GetToGlob( vInfo[0].ptI, frEnt) ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( vInfo[0].trTria.GetN(), frEnt) ;
|
|
}
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
|
|
// se trovato e modalità shading o hiddenline, la favorisco perchè davanti alle possibili successive
|
|
if ( bFound && ! ( bAlpha || m_nShowMode == SM_WIREFRAME) && dMinSqDist < SRF_SMALL_SQDIST)
|
|
dMinSqDist = 0 ;
|
|
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindTextSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const IExtText* pTxt, double& dMinSqDist)
|
|
{
|
|
// cerco il punto
|
|
bool bFound = false ;
|
|
Point3d ptP ;
|
|
switch ( nSnap) {
|
|
case SP_END :
|
|
// punto iniziale
|
|
if ( pTxt->GetStartPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto sopra iniziale
|
|
if ( pTxt->GetOverStartPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto finale
|
|
if ( pTxt->GetEndPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto sopra finale
|
|
if ( pTxt->GetOverEndPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_MID :
|
|
// punto medio
|
|
if ( pTxt->GetMidPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTER :
|
|
case SP_CENTROID :
|
|
// centro
|
|
if ( pTxt->GetCenterPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pTxt->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::FindDimensionSnapPoint( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt,
|
|
const IExtDimension* pDim, double& dMinSqDist)
|
|
{
|
|
// cerco il punto
|
|
bool bFound = false ;
|
|
Point3d ptP ;
|
|
switch ( nSnap) {
|
|
case SP_END :
|
|
// punto iniziale
|
|
if ( pDim->IsValid()) {
|
|
ptP = GetToGlob( pDim->GetStart(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto sopra iniziale
|
|
if ( pDim->IsValid()) {
|
|
ptP = GetToGlob( pDim->GetOverStart(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto finale
|
|
if ( pDim->IsValid()) {
|
|
ptP = GetToGlob( pDim->GetEnd(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
// punto sopra finale
|
|
if ( pDim->IsValid()) {
|
|
ptP = GetToGlob( pDim->GetOverEnd(), frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_MID :
|
|
// punto medio
|
|
if ( pDim->GetMidPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
case SP_CENTER :
|
|
case SP_CENTROID :
|
|
// centro
|
|
if ( pDim->GetCenterPoint( ptP)) {
|
|
ptP.ToGlob( frEnt) ;
|
|
if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) {
|
|
bFound = true ;
|
|
m_nLastSnapId = nId ;
|
|
m_ptLastSnapPnt = ptP ;
|
|
m_bLastSnapDirOk = true ;
|
|
m_vtLastSnapDir = GetToGlob( pDim->GetNormVersor(), frEnt) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
return bFound ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::GetPlaneSnapPoint( const Point3d& ptWin, const Plane3d& plPlane, Point3d& ptSel) const
|
|
{
|
|
// calcolo un punto e la direzione della linea di mira
|
|
Point3d ptLine ;
|
|
if ( ! UnProject( ptWin, ptLine))
|
|
return false ;
|
|
Vector3d vtLine = - m_vtDirCamera ;
|
|
if ( ! m_bOrthographic) {
|
|
// nella vista prospettica la direzione di mira è data dalla linea che coingiunge le proiezioni di ptWin sui piani near e far
|
|
Point3d ptLine2 ;
|
|
if ( ! UnProject( Point3d( ptWin.x, ptWin.y, 1), ptLine2))
|
|
return false ;
|
|
vtLine = ptLine - ptLine2 ;
|
|
vtLine.Normalize() ;
|
|
}
|
|
|
|
// determino l'intersezione di questa linea con il piano
|
|
double dDenom = vtLine * plPlane.GetVersN() ;
|
|
if ( abs( dDenom) < COS_ORTO_ANG_ZERO)
|
|
return false ;
|
|
double dU = ( plPlane.GetDist() - ( ptLine - ORIG) * plPlane.GetVersN()) / dDenom ;
|
|
ptSel = ptLine + dU * vtLine ;
|
|
return true ;
|
|
}
|