601c61f930
- migliorata la gestione dei layer importati.
1569 lines
67 KiB
C++
1569 lines
67 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2023
|
|
//----------------------------------------------------------------------------
|
|
// File : Import3dm.cpp Data : 23.06.23 Versione : 2.5f1
|
|
// Contenuto : Implementazione della classe per l'importazione di 3dm.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 23.06.23 DB Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "Import3dm.h"
|
|
#include "DllMain.h"
|
|
#include "/EgtDev/Include/EE3DllMain.h"
|
|
#include "/EgtDev/Include/EGnStringUtils.h"
|
|
#include "/EgtDev/Include/SELkKeyProc.h"
|
|
#include "/EgtDev/Include/EgtKeyCodes.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include "/EgtDev/Include/EGkGeoPoint3d.h"
|
|
#include "/EgtDev/Include/EGkCurveLine.h"
|
|
#include "/EgtDev/Include/EGkArcSpecial.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkCurveBezier.h"
|
|
#include "/EgtDev/Include/EGkCurveAux.h"
|
|
#include "/EgtDev/Include/EGkSurfAux.h"
|
|
#include "/EgtDev/Include/EGkStmFromCurves.h"
|
|
#include "/EgtDev/Include/EGkSurfBezier.h"
|
|
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EXeConst.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EGkExtText.h"
|
|
#include "/EgtDev/Include/EGkExtDimension.h"
|
|
#include "/EgtDev/Include/EGkVector3d.h"
|
|
#include "/EgtDev/Include/EGkGeoObjSave.h"
|
|
#include <map>
|
|
|
|
using namespace std ;
|
|
|
|
// deviazione angolare standard (in gradi)
|
|
const double ANG_TOL_STD_DEG = 15 ;
|
|
// tolleranza lineare affinata
|
|
const double LIN_TOL_FINE = 0.01 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
IImport3dm*
|
|
CreateImport3dm( void)
|
|
{
|
|
// verifico la chiave e le opzioni
|
|
if ( ! VerifyKey( KEYOPT_EEX_INPBASE))
|
|
return nullptr ;
|
|
// creo l'oggetto
|
|
return static_cast<IImport3dm*> ( new( nothrow) Import3dm) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Import3dm::Import( const string& sFile, IGeomDB* pGDB, int nIdGroup,
|
|
double dTextHeight, double dExtLine, double dArrLen, double dTextDist,
|
|
bool bLenIsMM, int nDecDig, std::string sFont)
|
|
{
|
|
// verifico il DB geometrico
|
|
if ( pGDB == nullptr) {
|
|
LOG_ERROR( GetEE3Logger(), "Import3dm : Error on GeomDB")
|
|
return false ;
|
|
}
|
|
m_pGDB = pGDB ;
|
|
|
|
// verifico l'Id di gruppo
|
|
if ( ! m_pGDB->ExistsObj( nIdGroup)) {
|
|
LOG_ERROR( GetEE3Logger(), "Import3dm : Error on IdGroup")
|
|
return false ;
|
|
}
|
|
m_nIdGroup = nIdGroup ;
|
|
|
|
ONX_Model model ;
|
|
|
|
wstring widestr( sFile.begin(), sFile.end()) ;
|
|
|
|
const wchar_t* sFileName = widestr.c_str() ;
|
|
FILE* archive_fp = ON::OpenFile( sFileName, L"rb") ;
|
|
if ( ! archive_fp) {
|
|
LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to open file.") ;
|
|
return false ;
|
|
}
|
|
|
|
// create achive object from file pointer
|
|
ON_BinaryFile archive( ON::archive_mode::read3dm, archive_fp) ;
|
|
|
|
// read the contents of the file into "model"
|
|
ON_TextLog dump ;
|
|
bool rc = model.Read( archive, &dump) ;
|
|
|
|
if ( ! rc)
|
|
LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to read file.") ;
|
|
|
|
// close the file
|
|
ON::CloseFile( archive_fp) ;
|
|
|
|
// LAYER
|
|
// creo i layer e i conto
|
|
ONX_ModelComponentIterator component_iterator_l( model, ON_ModelComponent::Type::Layer) ;
|
|
int nFirstId = 0 ;
|
|
|
|
ON_UUID ON_nil_uuid = { 0,0,0,{ 0,0,0,0,0,0,0,0}} ;
|
|
//int nLayDelCount = 0 ; //serve solo se si vogliono cancellare i layer parent. Se però questi layer contengono oggetti, che non sono in sottolayer del parent, non verranno visualizzati
|
|
for ( const ON_ModelComponent* mc = component_iterator_l.FirstComponent() ; mc != nullptr ; mc = component_iterator_l.NextComponent()) {
|
|
ON_UUID uuid = mc->Id() ;
|
|
const ON_Layer* onLayer = ON_Layer::Cast( mc) ;
|
|
ON_UUID uuidParent = onLayer->ParentId() ;
|
|
|
|
// cerco se il parent è un layer già aggiunto
|
|
auto it = std::find_if(m_mLayer.begin(), m_mLayer.end(),
|
|
[uuidParent](pair< int, tuple<const ON_Layer*, ON_UUID, int, int>> x){ return !ON_UuidCompare( get<1>(get<1>(x)), uuidParent) ;}); // ON_UuidCompare restituisce 0 se coincidono
|
|
int nParentL1 = -1 ;
|
|
// risalgo la gerarchia dei layer finché arrivo al primo layer e aggiungo tutti i nomi al nome del sottolayer
|
|
wstring ws = wstring(onLayer->Name()) ;
|
|
string sName(ws.begin(), ws.end()) ;
|
|
while ( ON_UuidCompare( uuidParent, ON_nil_uuid) ) {// ON_UuidCompare restituisce 0 se coincidono
|
|
const ON_Layer* onParentLayer = get<0>(it->second) ;
|
|
wstring wsParent = wstring( onParentLayer->Name()) ;
|
|
string sParentName( wsParent.begin(), wsParent.end()) ;
|
|
if ( get<3>(it->second) > 1)
|
|
sName = sParentName + "_" + sName ;
|
|
uuidParent = onParentLayer->ParentId() ;
|
|
// salvo l'id del parent che è al livello 1 ( che è un Part)
|
|
if ( get<3>(it->second) == 1)
|
|
nParentL1 = it->first ;
|
|
it = std::find_if(m_mLayer.begin(), m_mLayer.end(),
|
|
[uuidParent](pair< int, tuple<const ON_Layer*, ON_UUID, int, int>> x){ return !ON_UuidCompare( get<1>(get<1>(x)), uuidParent) ;});
|
|
}
|
|
|
|
|
|
// COMMENTO QUESTO TRATTO PERCHé, LASCIO I LAYER PARENT E LI CANCELLO ALLA FINE DELL'IMPORT SOLO SE RESTANO VUOTI
|
|
//
|
|
//// se era già stato aggiunto il parent e non era già indicata la presenza di sottolayer
|
|
//// devo eliminare il parent e mettere a true il flag dei sottolayer nella mappa dei layer
|
|
// if ( it_parent != m_mLayer.end() ) {
|
|
// if ( !get<3>(it_parent->second) ) {
|
|
// get<3>(it_parent->second) = true ;
|
|
// m_pGDB->Erase( it_parent->first) ;
|
|
// auto LayerDeleted = m_mLayer.extract(it_parent->first);
|
|
// LayerDeleted.key() = nLayDelCount ;
|
|
// -- nLayDelCount ;
|
|
// m_mLayer.insert(std::move(LayerDeleted));
|
|
// }
|
|
// }
|
|
int nDepth = 2 ;
|
|
if ( nParentL1 == GDB_ID_NULL) {
|
|
nParentL1 = GDB_ID_ROOT ;
|
|
nDepth = 1 ;
|
|
}
|
|
int nIdLayer = m_pGDB->AddGroup( GDB_ID_NULL, nParentL1 , GLOB_FRM) ;
|
|
if ( nFirstId == 0)
|
|
nFirstId = nIdLayer ;
|
|
int nIndex = onLayer->Index() ;
|
|
m_mLayer.insert( std::make_pair( nIdLayer, std::make_tuple(onLayer, uuid, nIndex, nDepth))) ;
|
|
m_pGDB->SetName( nIdLayer, sName) ;
|
|
}
|
|
|
|
// OGGETTI GEOMETRICI
|
|
ONX_ModelComponentIterator component_iterator( model, ON_ModelComponent::Type::ModelGeometry) ;
|
|
|
|
// se non riesco a convertire un oggetto, lo scarto e incremento il contatore del suo tipo nel dizionario error_count
|
|
int nId ;
|
|
for( const ON_ModelComponent* mc = component_iterator.FirstComponent() ; mc != nullptr ; mc = component_iterator.NextComponent()) {
|
|
const ON_ModelGeometryComponent* mgc = ON_ModelGeometryComponent::Cast( mc) ;
|
|
const ON_Object* oGeometry = mgc->Geometry( nullptr) ;
|
|
// individuo a che layer appartiene l'oggetto
|
|
const ON_3dmObjectAttributes* attributes = mgc->Attributes( nullptr) ;
|
|
int nLayer = attributes->m_layer_index ;
|
|
if ( nLayer < 0)
|
|
nLayer = 0 ;
|
|
else {
|
|
// prendo l'indice che il layer ha nel nostro GDB
|
|
auto it = std::find_if(m_mLayer.begin(), m_mLayer.end(),
|
|
[nLayer](pair< int, tuple<const ON_Layer*, ON_UUID, int, bool>> x){ return get<2>(get<1>(x)) == nLayer ;});
|
|
nLayer = it->first ;
|
|
}
|
|
// recupero il colore dell'oggetto
|
|
ON_Color onCol ;
|
|
switch ( attributes->ColorSource()) {
|
|
case ON::color_from_parent: // come se fosse from_layer
|
|
case ON::color_from_layer : {
|
|
onCol = get<0>(m_mLayer[nLayer])->Color() ;
|
|
break ;
|
|
}
|
|
case ON::color_from_object: {
|
|
onCol = attributes->m_color ;
|
|
break ;
|
|
}
|
|
case ON::color_from_material: {
|
|
// non gestito
|
|
break ;
|
|
}
|
|
}
|
|
|
|
Color cCol ;
|
|
// N.B. RHINO ha i valori di Alpha invertiti rispetto ai nostri, oltre che su una scala diversa! per loro 0 = opaco e 255 = trasparente
|
|
// per noi invece 0 = trasparente, 100 = opaco
|
|
cCol.Set( onCol.Red(), onCol.Green(), onCol.Blue(), int( abs( onCol.Alpha() - 255) / 2.55)) ;
|
|
// converto l'oggetto e lo aggiungo al GeomDB
|
|
ON::object_type type = oGeometry->ObjectType() ;
|
|
vector<PtrOwner<IGeoObj>> vpGeoObj ;
|
|
switch ( type) {
|
|
case ON::object_type::point_object : {
|
|
const ON_Point* oPoint = ON_Point::Cast( oGeometry) ;
|
|
Point3d pt( ConvertPoint( *oPoint)) ;
|
|
// lo aggiungo al GeomDB nel layer corretto
|
|
PtrOwner<IGeoPoint3d> pGeoPnt( CreateGeoPoint3d()) ;
|
|
if ( ! IsNull( pGeoPnt) && pGeoPnt->Set( pt) && pGeoPnt->IsValid())
|
|
vpGeoObj.emplace_back( Release( pGeoPnt)) ;
|
|
else
|
|
m_mError_count["point"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::pointset_object : {
|
|
const ON_PointCloud* pc = ON_PointCloud::Cast( oGeometry);
|
|
if ( pc == nullptr) {
|
|
m_mError_count["pointset"] += 1 ;
|
|
break ;
|
|
}
|
|
for ( int i = 0 ; i < pc->PointCount() ; i++) {
|
|
Point3d pt( ConvertPoint( pc->m_P[i])) ;
|
|
// lo aggiungo al GeomDB nel layer corretto
|
|
PtrOwner<IGeoPoint3d> pGeoPnt( CreateGeoPoint3d()) ;
|
|
if ( ! IsNull( pGeoPnt) && pGeoPnt->Set( pt) && pGeoPnt->IsValid())
|
|
vpGeoObj.emplace_back( Release(pGeoPnt)) ;
|
|
else
|
|
m_mError_count["point"] += 1 ;
|
|
}
|
|
break ;
|
|
}
|
|
case ON::object_type::curve_object : {
|
|
const ON_Curve* onCurve = ON_Curve::Cast( oGeometry) ;
|
|
PtrOwner<ICurve> pCurve( ConvertCurve( onCurve)) ;
|
|
if ( ! IsNull( pCurve) && pCurve->IsValid())
|
|
vpGeoObj.emplace_back( Release( pCurve)) ;
|
|
else
|
|
m_mError_count["curve"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::surface_object : {
|
|
const ON_Surface* onSurface = ON_Surface::Cast( oGeometry) ;
|
|
PtrOwner<ISurf> pSurf( ConvertSurface( onSurface)) ;
|
|
if ( ! IsNull( pSurf) && pSurf->IsValid())
|
|
vpGeoObj.emplace_back( Release( pSurf)) ;
|
|
else
|
|
m_mError_count["surface"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::brep_object : {
|
|
const ON_Brep* onBrep = ON_Brep::Cast( oGeometry) ;
|
|
ISURFPOVECTOR vpSurf = ConvertBrep( onBrep, false) ;
|
|
for ( int k = 0 ; k < int( vpSurf.size()) ; ++ k) {
|
|
PtrOwner<ISurf> pSurf( GetSurf( Release( vpSurf[k]))) ;
|
|
if ( ! IsNull( pSurf) && pSurf->IsValid())
|
|
vpGeoObj.emplace_back( Release( pSurf)) ;
|
|
else
|
|
m_mError_count["brep"] += 1 ;
|
|
}
|
|
break ;
|
|
}
|
|
case ON::object_type::extrusion_object : {
|
|
const ON_Extrusion* onExtrusion = ON_Extrusion::Cast( oGeometry) ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm( ConvertExtrusion( onExtrusion)) ;
|
|
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid())
|
|
vpGeoObj.emplace_back( Release( pSurfTm)) ;
|
|
else
|
|
m_mError_count["mesh"] += 1 ;
|
|
break ;
|
|
break ;
|
|
}
|
|
case ON::object_type::mesh_object :{
|
|
const ON_Mesh* onMesh = ON_Mesh::Cast( oGeometry) ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm( ConvertMesh( onMesh)) ;
|
|
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid())
|
|
vpGeoObj.emplace_back( Release( pSurfTm)) ;
|
|
else
|
|
m_mError_count["mesh"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::loop_object : {// some type of ON_BrepLoop
|
|
// in teoria non dovrei mai trovare questo tipo di oggetti come model geometry indipendenti, ma solo come parte di una brep
|
|
const ON_BrepLoop* onBrepLoop = ON_BrepLoop::Cast( oGeometry) ;
|
|
PtrOwner<ICurve> pCurve( ConvertBrepLoop( onBrepLoop)) ;
|
|
if ( ! IsNull( pCurve) && pCurve->IsValid())
|
|
vpGeoObj.emplace_back( Release( pCurve)) ;
|
|
else
|
|
m_mError_count["loop"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::subd_object: {
|
|
// non c'è un comando per convertire le subd in altre superfici...
|
|
m_mError_count["subd"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::object_type::annotation_object: {
|
|
const ON_Annotation* onAnnot = ON_Annotation::Cast( oGeometry) ;
|
|
// recupero il DimStyle
|
|
onAnnot->DimensionStyleId() ;
|
|
ON_UUID onStyleId = onAnnot->DimensionStyleId() ;
|
|
ON_ModelComponentReference mcr = model.ComponentFromId( ON_ModelComponent::Type::DimStyle, onStyleId) ;
|
|
const ON_ModelComponent* mc = mcr.ModelComponent() ;
|
|
const ON_DimStyle* onDimStyle = ON_DimStyle::Cast( mc) ;
|
|
// converto l'oggetto
|
|
vpGeoObj = ConvertAnnotation( onAnnot, onDimStyle, dTextHeight, dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont) ;
|
|
break ;
|
|
}
|
|
// TO DO
|
|
// oggetto che definisce la zona dell'anteprima di stampa
|
|
// degli oggetti potrebbero essere definiti rispetto a questo frame
|
|
//
|
|
//case ON::object_type::detail_object: {
|
|
// const ON_DetailView* onDetail = ON_DetailView::Cast( oGeometry) ;
|
|
// ON_NurbsCurve onBoundary = onDetail->m_boundary ;
|
|
// ICurve* pCrv = ConvertCurve( &onBoundary) ;
|
|
// ON_3dmView onView = onDetail->m_view ;
|
|
// ON::view_type onViewType = onView.m_view_type ;
|
|
// error_count["detail"] += 1 ;
|
|
//}
|
|
default: {
|
|
m_mError_count["other"] += 1 ;
|
|
break ;
|
|
}
|
|
}
|
|
int nSubLayer = nLayer ;
|
|
// se ho più oggetti da inserire creo un subLayer
|
|
if ((int) vpGeoObj.size() > 1) {
|
|
// se nLayer è un Part (depth == 1) allora creo un layer sotto il part
|
|
if ( get<3>(m_mLayer[nLayer]) == 1)
|
|
// creo un gruppo per mettere tutti gli oggetti
|
|
nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, GLOB_FRM) ;
|
|
else {
|
|
int nParent = m_pGDB->GetParentId( nLayer) ;
|
|
nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nParent, GLOB_FRM) ;
|
|
string sSubName ; m_pGDB->GetName( nSubLayer, sSubName) ;
|
|
if ( sSubName == "")
|
|
sSubName = "Layer " + ToString(nSubLayer) ;
|
|
string sName ; m_pGDB->GetName( nLayer, sName) ;
|
|
sSubName = sName + "_" + sSubName ;
|
|
m_pGDB->SetName( nSubLayer, sSubName) ;
|
|
}
|
|
}
|
|
for (int p = 0 ; p < (int) vpGeoObj.size() ; ++p) {
|
|
if ( ! IsNull( vpGeoObj[p]) && vpGeoObj[p]->IsValid() ) {
|
|
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nSubLayer, Release( vpGeoObj[p])) ;
|
|
m_pGDB->SetMaterial( nId, cCol) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// CANCELLO I LAYER RIMASTI VUOTI ??
|
|
|
|
// messaggio di errore da mettere nel log per dire quanti oggetti sono stati ignorati perché la conversione non è riuscita
|
|
map<string, int>::iterator it = m_mError_count.begin() ;
|
|
while (it != m_mError_count.end()) {
|
|
string type = it->first ;
|
|
int count = it->second ;
|
|
string sOut = "Import3dm : " + to_string( count) + type + " objects have been ignored, due to conversion errors" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
it++;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
Import3dm::ConvertCurve( const ON_Curve* onCurve)
|
|
{
|
|
ON::eCurveType curve_type = onCurve->ON_CurveType() ;
|
|
|
|
switch ( curve_type) {
|
|
case ON::eCurveType::ctArc : {
|
|
const ON_ArcCurve* onArc = ON_ArcCurve::Cast( onCurve) ;
|
|
Vector3d vStart = ConvertVector( onArc->TangentAt( 0)) ;
|
|
Point3d ptCenter( ConvertPoint( onArc->m_arc.plane.origin)) ;
|
|
Point3d ptStart( ConvertPoint( onArc->m_arc.PointAt( onArc->m_arc.Domain().Min()))) ;
|
|
Point3d ptEnd( ConvertPoint( onArc->m_arc.PointAt( onArc->m_arc.Domain().Max()))) ;
|
|
Vector3d vtN = ConvertVector( onArc->m_arc.plane.zaxis) ;
|
|
PtrOwner<ICurveArc> pCurveArc( CreateCurveArc()) ;
|
|
if ( IsNull( pCurveArc))
|
|
return nullptr ;
|
|
if ( ! AreSamePointApprox( ptStart, ptEnd)) {
|
|
if ( ! pCurveArc->Set2PVN( ptStart, ptEnd, vStart, vtN))
|
|
pCurveArc->SetC2PN( ptCenter, ptStart, ptEnd, vtN) ;
|
|
}
|
|
else {
|
|
double dRad = onArc->m_arc.Radius() ;
|
|
pCurveArc->Set( ptCenter, vtN, dRad) ;
|
|
}
|
|
return Release( pCurveArc) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctCircle : {
|
|
const ON_ArcCurve* onCircle = ON_ArcCurve::Cast( onCurve) ;
|
|
Point3d ptCenter( ConvertPoint(onCircle->m_arc.plane.origin)) ;
|
|
ON_3dVector on_vtN = onCircle->m_arc.plane.zaxis ;
|
|
Vector3d vtN = ConvertVector( on_vtN) ;
|
|
double dRad = onCircle->m_arc.Radius() ;
|
|
PtrOwner<ICurveArc> pCurveArc( CreateCurveArc()) ;
|
|
pCurveArc->Set( ptCenter, vtN, dRad) ;
|
|
return Release( pCurveArc) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctLine : {
|
|
const ON_LineCurve* onCurveLine = ON_LineCurve::Cast( onCurve) ;
|
|
Point3d ptStart( ConvertPoint( onCurveLine->m_line.from)) ;
|
|
Point3d ptEnd( ConvertPoint( onCurveLine->m_line.to)) ;
|
|
PtrOwner<ICurveLine> pCurveLine( CreateCurveLine()) ;
|
|
pCurveLine->Set( ptStart, ptEnd) ;
|
|
return Release( pCurveLine) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctNurbs : {
|
|
// da trasformare in una bezier
|
|
const ON_NurbsCurve* onNurbsCurve = ON_NurbsCurve::Cast( onCurve) ;
|
|
bool bIsRational = onNurbsCurve->IsRational() ;
|
|
CNurbsData nuCurve ;
|
|
nuCurve.bRat = bIsRational ;
|
|
nuCurve.nDeg = onNurbsCurve->Degree() ; // == onNurbsCurve->Order() - 1
|
|
int nCount = onNurbsCurve->CVCount() ;
|
|
if ( bIsRational) {
|
|
// vettore dei punti di controllo
|
|
PNTVECTOR vPtCtrl ;
|
|
// vettore dei pesi
|
|
DBLVECTOR vWeCtrl ;
|
|
for( int i = 0 ; i < nCount; ++i) {
|
|
ON_4dPoint o4dPoint ;
|
|
onNurbsCurve->GetCV( i, o4dPoint) ;
|
|
Point3d ptCtrl( ConvertPoint( o4dPoint)) ;
|
|
vPtCtrl.push_back( ptCtrl / o4dPoint.w) ;
|
|
vWeCtrl.push_back( o4dPoint.w) ;
|
|
}
|
|
nuCurve.vCP = vPtCtrl ;
|
|
nuCurve.vW = vWeCtrl ;
|
|
}
|
|
else {
|
|
// vettore dei punti di controllo
|
|
PNTVECTOR vPtCtrl ;
|
|
for( int i = 0 ; i < nCount; ++i) {
|
|
ON_3dPoint o3dPoint ;
|
|
onNurbsCurve->GetCV( i, o3dPoint) ;
|
|
Point3d ptCtrl( ConvertPoint(o3dPoint)) ;
|
|
vPtCtrl.push_back( ptCtrl) ;
|
|
}
|
|
nuCurve.vCP = vPtCtrl ;
|
|
}
|
|
|
|
// qui aggiungo un controllo se la curva è collassata in un punto restituisco nullptr
|
|
bool bCollapsed = true ;
|
|
Point3d ptFirst = nuCurve.vCP.front() ;
|
|
for( int i = 1 ; i < int( nuCurve.vCP.size()) ; ++i) {
|
|
if ( ! AreSamePointApprox( ptFirst, nuCurve.vCP[i])) {
|
|
bCollapsed = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bCollapsed)
|
|
return nullptr ;
|
|
|
|
// vettore dei nodi
|
|
DBLVECTOR vU ;
|
|
int nKnot = onNurbsCurve->KnotCount() ;
|
|
for ( int j = 0 ; j < nKnot ; ++j ) {
|
|
double dKnot = onNurbsCurve->Knot( j) ;
|
|
vU.push_back( dKnot) ;
|
|
}
|
|
nuCurve.vU = vU ;
|
|
nuCurve.bClosed = onNurbsCurve->IsClosed() ;
|
|
nuCurve.bPeriodic = onNurbsCurve->IsPeriodic() ;
|
|
nuCurve.bClamped = onNurbsCurve->IsClamped(2) ;
|
|
|
|
// controllo relazione nodi - punti di controllo
|
|
int nU = int( nuCurve.vCP.size()) + nuCurve.nDeg - 1 ;
|
|
// se ho due nodi di troppo mi basta togliere il primo e l'ultimo per rendere la curva canonica
|
|
// se la curva è periodica posso renderla non periodica senza cambiare la forma della curva
|
|
if ( nU == int( nuCurve.vU.size()) + 2 || nuCurve.bPeriodic || ! nuCurve.bClamped)
|
|
NurbsCurveCanonicalize( nuCurve) ;
|
|
|
|
// ora che ho riempito la Nurbs con tutti i dati la converto in Bezier
|
|
return NurbsToBezierCurve( nuCurve) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctOnsurface :{
|
|
const ON_CurveOnSurface* onCurveOnSurface = ON_CurveOnSurface::Cast( onCurve) ;
|
|
ON_NurbsCurve onNurbsCurve ;
|
|
onCurveOnSurface->GetNurbForm( onNurbsCurve) ;
|
|
return ConvertCurve( &onNurbsCurve) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctProxy :{
|
|
const ON_CurveProxy* onProxyCurve = ON_CurveProxy::Cast( onCurve) ;
|
|
const ON_Curve* onCurve = onProxyCurve->ProxyCurve() ;
|
|
return ConvertCurve( onCurve) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctPolycurve : {
|
|
const ON_PolyCurve* onPolycurve = ON_PolyCurve::Cast( onCurve) ;
|
|
int nCurves = onPolycurve->Count() ;
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
for ( int i = 0 ; i < nCurves; ++i) {
|
|
ICurve* pCurveToAdd = nullptr ;
|
|
ON_Curve* onCurveToAdd = onPolycurve->SegmentCurve( i) ;
|
|
pCurveToAdd = ConvertCurve( onCurveToAdd) ;
|
|
pCrvCompo->AddCurve( pCurveToAdd) ;
|
|
}
|
|
return Release( pCrvCompo) ;
|
|
break ;
|
|
}
|
|
case ON::eCurveType::ctPolyline : {
|
|
const ON_PolylineCurve* onPolyline = ON_PolylineCurve::Cast( onCurve) ;
|
|
int nPoints = onPolyline->PointCount() ;
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
Point3d ptNew , ptOld( ConvertPoint(onPolyline->m_pline[0])) ;
|
|
for ( int i = 1 ; i < nPoints ; ++i ) {
|
|
ICurveLine* pCurveLine( CreateCurveLine()) ;
|
|
ptNew = ConvertPoint( onPolyline->m_pline[i]) ;
|
|
pCurveLine->Set( ptOld, ptNew) ;
|
|
pCrvCompo->AddCurve( pCurveLine) ;
|
|
ptOld = ptNew ;
|
|
}
|
|
return Release( pCrvCompo) ;
|
|
break ;
|
|
}
|
|
default :
|
|
break ;
|
|
}
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ISurf*
|
|
Import3dm::ConvertSurface( const ON_Surface* onSurf)
|
|
{
|
|
if ( const ON_NurbsSurface* onNurbsSurface_ = ON_NurbsSurface::Cast( onSurf)) {
|
|
ON_NurbsSurface onNurbsSurface( *onNurbsSurface_) ;
|
|
SNurbsSurfData sNurbsSurf ;
|
|
sNurbsSurf.bClosedU = onNurbsSurface.IsClosed( 0) ;
|
|
sNurbsSurf.bClosedV = onNurbsSurface.IsClosed( 1) ;
|
|
sNurbsSurf.bPeriodicU = onNurbsSurface.IsPeriodic( 0) ;
|
|
sNurbsSurf.bPeriodicV = onNurbsSurface.IsPeriodic( 1) ;
|
|
sNurbsSurf.bClampedU = onNurbsSurface.IsClamped( 0, 2) ; // qui do per scontato che se la curva è clamped alla fine allora lo è anche all'inizio e viceversa
|
|
sNurbsSurf.bClampedV = onNurbsSurface.IsClamped( 1, 2) ; // qui do per scontato che se la curva è clamped alla fine allora lo è anche all'inizio e viceversa
|
|
sNurbsSurf.bRat = onNurbsSurface.IsRational() ;
|
|
sNurbsSurf.nDegU = onNurbsSurface.Degree( 0) ;
|
|
sNurbsSurf.nDegV = onNurbsSurface.Degree( 1) ;
|
|
sNurbsSurf.nCPU = onNurbsSurface.CVCount( 0) ;
|
|
sNurbsSurf.nCPV = onNurbsSurface.CVCount( 1) ;
|
|
PNTVECTOR vCPV( sNurbsSurf.nCPV) ;
|
|
sNurbsSurf.mCP.resize( sNurbsSurf.nCPU, vCPV) ;
|
|
DBLVECTOR vWV( sNurbsSurf.nCPV) ;
|
|
sNurbsSurf.mW.resize( sNurbsSurf.nCPU, vWV) ;
|
|
for ( int i = 0 ; i < sNurbsSurf.nCPU ; ++i) {
|
|
for ( int j = 0 ; j < sNurbsSurf.nCPV ; ++j) {
|
|
ON_4dPoint o4dPoint = onNurbsSurface.ControlPoint(i, j) ;
|
|
Point3d ptCP = ConvertPoint( o4dPoint) ;
|
|
sNurbsSurf.mCP[i][j] = ptCP ;
|
|
if ( sNurbsSurf.bRat)
|
|
sNurbsSurf.mCP[i][j] = ptCP / o4dPoint.w ;
|
|
else
|
|
sNurbsSurf.mCP[i][j] = ptCP ;
|
|
sNurbsSurf.mW[i][j] = o4dPoint.w ;
|
|
}
|
|
}
|
|
for ( int i = 0 ; i < onNurbsSurface.KnotCount(0) ; ++i )
|
|
sNurbsSurf.vU.push_back( onNurbsSurface.Knot( 0, i)) ;
|
|
|
|
for ( int j = 0 ; j < onNurbsSurface.KnotCount(1) ; ++j )
|
|
sNurbsSurf.vV.push_back( onNurbsSurface.Knot( 1, j)) ;
|
|
|
|
if ( sNurbsSurf.bPeriodicU || sNurbsSurf.bPeriodicV || ! sNurbsSurf.bClampedU || ! sNurbsSurf.bClampedV)
|
|
NurbsSurfaceCanonicalize( sNurbsSurf) ;
|
|
|
|
return NurbsToBezierSurface( sNurbsSurf) ;
|
|
}
|
|
else if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurf)) {
|
|
// recupero i riferimenti del piano e li converto in oggetti nostri
|
|
Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ;
|
|
Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ;
|
|
Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ;
|
|
Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ;
|
|
ON_Interval on_inX = onPlaneSurface->Extents(0) ;
|
|
ON_Interval on_inY = onPlaneSurface->Extents(1) ;
|
|
Point3d pt0( on_inX[0], on_inY[0]) ;
|
|
Point3d pt1( on_inX[1], on_inY[0]) ;
|
|
Point3d pt2( on_inX[1], on_inY[1]) ;
|
|
Point3d pt3( on_inX[0], on_inY[1]) ;
|
|
|
|
// costruisco la figura e la inserisco nel GDB
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo))
|
|
return nullptr ;
|
|
pCrvCompo->AddPoint( pt0) ;
|
|
pCrvCompo->AddLine( pt1) ;
|
|
pCrvCompo->AddLine( pt2) ;
|
|
pCrvCompo->AddLine( pt3) ;
|
|
pCrvCompo->Close() ;
|
|
// porto la figura nel frame globale
|
|
Frame3d frPlane ;
|
|
frPlane.Set( ptOrig, vtX, vtY, vtZ) ;
|
|
pCrvCompo->ToGlob( frPlane) ;
|
|
|
|
PtrOwner<ISurfFlatRegion> pSurf( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSurf) || ! pSurf->AddExtLoop( Release( pCrvCompo)))
|
|
return nullptr ;
|
|
return Release( pSurf) ;
|
|
}
|
|
else if ( const ON_RevSurface* onRevSurface = ON_RevSurface::Cast( onSurf)) {
|
|
PtrOwner<ICurve> pCurve( ConvertCurve( onRevSurface->m_curve)) ;
|
|
ON_Line onAxis = onRevSurface->m_axis ;
|
|
Point3d ptFrom = ConvertPoint( onAxis.from) ;
|
|
Point3d ptTo = ConvertPoint( onAxis.to) ;
|
|
Vector3d vtDir = ptTo - ptFrom ;
|
|
// intervallo angolare su cui si vuole la superficie di rivoluzione
|
|
ON_Interval onInter = onRevSurface->m_angle ;
|
|
double dAngRotDeg = ( onInter[1] - onInter[0]) * RADTODEG ;
|
|
double dAngStartDeg = onInter[0] * RADTODEG ;
|
|
PtrOwner<ISurfTriMesh> pSurf( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pSurf))
|
|
return nullptr ;
|
|
// se l'angolo è significativo allora effettuo la rivoluzione
|
|
if ( dAngRotDeg > EPS_SMALL * 10) {
|
|
pSurf.Set( GetSurfTriMeshByScrewing( pCurve, ptFrom, vtDir, dAngRotDeg, 0., false)) ;
|
|
// se la rivoluzione è meno di un angolo giro e la partenza non era a zero devo ruotare la superficie ottenuta
|
|
if ( dAngRotDeg < 360 - EPS_SMALL * 50 && onInter[0] * RADTODEG > EPS_SMALL * 50)
|
|
pSurf->Rotate( ptFrom, vtDir, dAngStartDeg) ;
|
|
}
|
|
return Release( pSurf) ;
|
|
}
|
|
else if ( const ON_SumSurface* onSumSurface = ON_SumSurface::Cast( onSurf)) {
|
|
// uso la nurbs form
|
|
ON_NurbsSurface onNurbsSurface ;
|
|
int nOk = onSumSurface->GetNurbForm( onNurbsSurface) ;
|
|
PtrOwner<ISurf> pSurf ;
|
|
if ( nOk != 0)
|
|
pSurf.Set( ConvertSurface( &onNurbsSurface)) ;
|
|
if ( ! IsNull( pSurf) && pSurf->IsValid())
|
|
return Release( pSurf) ;
|
|
|
|
// se non è riuscita la conversione tento di costruire la superficie con una rail
|
|
ON_Interval onIntDomain0 = onSumSurface->Domain(0) ;
|
|
ON_Interval onIntDomain1 = onSumSurface->Domain(1) ;
|
|
// Note carefully: ON_SumSurface::IsoCurve allocates memory
|
|
// for the output curve. The caller is responsible for
|
|
// freeing this memory when finished.
|
|
PtrOwner<ON_Curve> onpCrvWest( onSumSurface->IsoCurve(1, onIntDomain0[0])) ;
|
|
PtrOwner<ON_Curve> onpCrvSouth( onSumSurface->IsoCurve(0, onIntDomain1[0])) ;
|
|
PtrOwner<ICurve> pCrvWest( ConvertCurve( onpCrvWest)) ;
|
|
PtrOwner<ICurve> pCrvSouth( ConvertCurve( onpCrvSouth)) ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm ( GetSurfTriMeshSwept( pCrvSouth, pCrvWest, V_NULL, false)) ;
|
|
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid())
|
|
return Release( pSurfTm) ;
|
|
|
|
// se fallisce questo tentativo di conversione allora recupero le curve e costruisco la superficie di Bezier
|
|
// in teoria dovrei farcela con uno dei due metodi precedenti
|
|
PtrOwner<ON_Curve> onpCrvEast( onSumSurface->IsoCurve(1, onIntDomain0[1])) ;
|
|
PtrOwner<ON_Curve> onpCrvNorth( onSumSurface->IsoCurve(0, onIntDomain1[1])) ;
|
|
// da implementare ////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
return nullptr ;
|
|
}
|
|
else if ( const ON_SurfaceProxy* onSurfaceProxy = ON_SurfaceProxy::Cast( onSurf)) {
|
|
PtrOwner<ISurf> pSurf ;
|
|
// bool bTransposed = onSurfaceProxy->ProxySurfaceIsTransposed() ;
|
|
if ( const ON_BrepFace* onBrepFace = ON_BrepFace::Cast( onSurfaceProxy)) {
|
|
// uso la nurbs form
|
|
ON_NurbsSurface onNurbsSurface ;
|
|
int nOk = onBrepFace->GetNurbForm( onNurbsSurface) ;
|
|
|
|
if ( nOk != 0){
|
|
pSurf.Set( ConvertSurface( & onNurbsSurface)) ;
|
|
}
|
|
else {
|
|
// QUI PERò NON TENGO CONTO DEL TRIM!!!!!!
|
|
//
|
|
// se non è riuscita la conversione in nurbs tengo la superficie originale
|
|
const ON_Surface* onSurfFace = onBrepFace->ProxySurface() ;
|
|
// qui devo applicare a mano le trasformazioni dalla superfice originale alla proxy
|
|
// la funzione getNurbsForm lo fa in automatico
|
|
pSurf.Set( ConvertSurface( onSurfFace)) ;
|
|
}
|
|
}
|
|
else if ( const ON_OffsetSurface* onOffsetSurface = ON_OffsetSurface::Cast( onSurfaceProxy)) {
|
|
//pSurf.Set( ConvertSurface( onOffsetSurface->BaseSurface())) ;
|
|
ON_NurbsSurface onNurbsSurface ;
|
|
int nOk = onOffsetSurface->GetNurbForm( onNurbsSurface) ;
|
|
if ( nOk != 0)
|
|
pSurf.Set( ConvertSurface( &onNurbsSurface)) ;
|
|
}
|
|
else
|
|
pSurf.Set( ConvertSurface( onSurfaceProxy->ProxySurface())) ;
|
|
return Release( pSurf) ;
|
|
}
|
|
|
|
return nullptr ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
ISURFPOVECTOR
|
|
Import3dm::ConvertBrep( const ON_Brep* onBrep, const bool bForceTriMesh)
|
|
{
|
|
// se le facce della Brep sono tutte trimesh restituisco un'unica trimesh
|
|
// se le facce sono delle NURBS restituisco un vettore di superfici Bezier
|
|
// se ForceTriMesh è true allora le Bezier vengono trasformate in trimesh e aggiunte alla zuppa
|
|
|
|
ISURFPOVECTOR vSurf ;
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start())
|
|
return vSurf ;
|
|
bool bSurfTm = false ;
|
|
int nFailedBFace = 0, nFailedTm = 0, nFailedFr = 0, nFailedBz = 0, nFailedBTrim = 0 ;
|
|
|
|
for ( int i = 0 ; i < onBrep->m_F.Count() ; ++i) {
|
|
bool bOk = true ;
|
|
ON_BrepFace* onFace = onBrep->Face( i) ;
|
|
bool bRev = onFace->m_bRev ;
|
|
const ON_Surface* onSurface = onFace->SurfaceOf() ;
|
|
PtrOwner<ISurf> pSurf ;
|
|
bool bTooSmallOnlyLoop = false ;
|
|
if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurface)) {
|
|
SurfFlatRegionByContours SfrCntr ;
|
|
// ricavo il riferimento del piano
|
|
Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ;
|
|
Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ;
|
|
Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ;
|
|
Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ;
|
|
Plane3d plane ; plane.Set( ptOrig, vtZ) ;
|
|
int nLoopCount = onFace->LoopCount() ;
|
|
for ( int k = 0 ; k < nLoopCount ; ++k) {
|
|
PtrOwner<ICurveComposite> pCrvCompo( GetCurveComposite(ConvertBrepLoop( onFace->Loop( k)))) ;
|
|
PolyArc paLoopApprox ;
|
|
pCrvCompo->ApproxWithArcs(LIN_TOL_FINE, ANG_TOL_STD_DEG, paLoopApprox) ;
|
|
pCrvCompo->FromPolyArc( paLoopApprox) ;
|
|
pCrvCompo->MergeCurves(LIN_TOL_FINE, ANG_TOL_STD_DEG) ;
|
|
double dArea = 0 ; pCrvCompo->GetArea( plane, dArea) ;
|
|
if ( nLoopCount == 1 && dArea <= 0)
|
|
bTooSmallOnlyLoop = true ;
|
|
if ( ! SfrCntr.AddCurve( Release( pCrvCompo)))
|
|
++ nFailedBTrim ;
|
|
}
|
|
pSurf.Set( SfrCntr.GetSurf()) ;
|
|
if ( ! IsNull( pSurf) && pSurf->IsValid()) {
|
|
// porto le coordinate dal riferimento del piano di trim alle coordinate globali
|
|
Frame3d frPlane ;
|
|
frPlane.Set( ptOrig, vtX, vtY, vtZ) ;
|
|
pSurf->ToGlob( frPlane) ;
|
|
}
|
|
}
|
|
else
|
|
pSurf.Set( ConvertSurface( onFace)) ;
|
|
|
|
if ( IsNull( pSurf) || ! pSurf->IsValid()) {
|
|
// se la superficie aveva un solo loop e questo era troppo piccolo allora non lo segno come errore
|
|
// semplicmente la superficie non verrà disegnata perché troppo piccola
|
|
if ( ! bTooSmallOnlyLoop)
|
|
++ nFailedBFace ;
|
|
}
|
|
else {
|
|
// se ho una trimesh o una flatregion la aggiungo alla zuppa, se è una bezier la aggiungo al vettore delle superfici
|
|
int nType = pSurf->GetType() ;
|
|
if ( nType == SRF_TRIMESH) {
|
|
bSurfTm = true ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm( GetSurfTriMesh( Release( pSurf))) ;
|
|
if ( !IsNull(pSurfTm) && pSurfTm->IsValid() ) {
|
|
if ( bRev)
|
|
pSurfTm->Invert() ;
|
|
stmSoup.AddSurfTriMesh( *pSurfTm) ;
|
|
}
|
|
else
|
|
++ nFailedTm ;
|
|
}
|
|
else if ( nType == SRF_FLATRGN) {
|
|
bSurfTm = true ;
|
|
PtrOwner<ISurfFlatRegion> pSurfFr( GetSurfFlatRegion( Release( pSurf))) ;
|
|
if ( ! IsNull( pSurfFr) && pSurfFr->IsValid()) {
|
|
if ( bRev)
|
|
pSurfFr->Invert() ;
|
|
stmSoup.AddSurfTriMesh(*pSurfFr->GetAuxSurf()) ;
|
|
}
|
|
else
|
|
++ nFailedFr ;
|
|
}
|
|
else if ( nType == SRF_BEZIER) {
|
|
PtrOwner<ISurfBezier> pSurfBezNew( GetSurfBezier( Release( pSurf))) ;
|
|
if ( ! IsNull( pSurfBezNew) && pSurfBezNew->IsValid()) {
|
|
ON_BrepFace* onFace = onBrep->Face( i) ;
|
|
SurfFlatRegionByContours SfrCntr ;
|
|
const ON_Surface* onSurface = onFace->SurfaceOf() ;
|
|
// se la superficie era una superficie di rivoluzione, le eventuali curve di trim erano parametrizzate con la coordinata x in radianti,
|
|
// e non riferita allo spazio parametrico della nurbs corrispondente ( che sarebbe una nurbs razionale, dovendo approssimare un arco di circonferenza)
|
|
// devo quindi prelevare le curve di trim e cambiarne le coordinate per matcharle allo spazio parametrico della nurbs
|
|
bool bAddedLoop = false ;
|
|
if ( const ON_RevSurface* onRevSurf = ON_RevSurface::Cast( onSurface) ) {
|
|
for ( int k = 0 ; k < onFace->LoopCount(); ++k ) {
|
|
ICurve* pCrv( ConvertBrepLoop( onFace->Loop( k))) ;
|
|
if ( pCrv == nullptr || ! pCrv->IsValid()) {
|
|
++ nFailedBTrim ;
|
|
bOk = false ;
|
|
break ;
|
|
}
|
|
// qui devo spostare ogni punto della curva dallo spazio parametrico della superificie rev allo spazio della superficie nurbs
|
|
ConvertCurveParam( onRevSurf, &pCrv) ;
|
|
PtrOwner<ICurveComposite> pCrvCompo( ApproxTrim( pCrv)) ;
|
|
double dArea = 0 ;
|
|
pCrvCompo->GetAreaXY(dArea) ;
|
|
if (abs(dArea) > EPS_SMALL) {
|
|
pCrvCompo->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ;
|
|
if ( SfrCntr.AddCurve( Release(pCrvCompo)))
|
|
bAddedLoop = true ;
|
|
}
|
|
else
|
|
continue ;
|
|
}
|
|
if ( ! bOk)
|
|
continue ;
|
|
}
|
|
else {
|
|
for ( int k = 0 ; k < onFace->LoopCount() && bOk ; ++k ) {
|
|
PtrOwner<ICurve> pCrv( ConvertBrepLoop( onFace->Loop( k))) ;
|
|
if ( IsNull(pCrv) || ! pCrv->IsValid()) {
|
|
++ nFailedBTrim ;
|
|
bOk = false ;
|
|
break ;
|
|
}
|
|
PtrOwner<ICurveComposite> pCrvCompo( ApproxTrim( Release(pCrv))) ;
|
|
double dArea = 0 ;
|
|
pCrvCompo->GetAreaXY(dArea) ;
|
|
if (abs(dArea) > EPS_SMALL) {
|
|
pCrvCompo->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ;
|
|
if ( SfrCntr.AddCurve( Release( pCrvCompo)))
|
|
bAddedLoop = true ;
|
|
}
|
|
else
|
|
continue ;
|
|
}
|
|
if ( ! bOk)
|
|
continue ;
|
|
}
|
|
if ( ! bAddedLoop)
|
|
continue ;
|
|
ISurfFlatRegion* sfrTrim = SfrCntr.GetSurf() ;
|
|
|
|
// questa regione di Trim deve essere riferita al rettangolo parametrico totale ( spaz param 1x1 -> regione trim 1000x1000)
|
|
// devo anche controllare che il sistema di riferimento dello spazio di trim totale sia giusto ( con l'angolo BottomLeft in (0,0)
|
|
//posizonato nel primo quadrante del piano XY)
|
|
double u0,u1,v0,v1 ;
|
|
onFace->GetDomain(0, &u0, &u1) ;
|
|
onFace->GetDomain(1, &v0, &v1) ;
|
|
double dScaleU = (u1 - u0) * SBZ_TREG_COEFF ;
|
|
double dScaleV = (v1 - v0) * SBZ_TREG_COEFF ;
|
|
|
|
Vector3d vToOrig( -u0 * SBZ_TREG_COEFF, -v0 * SBZ_TREG_COEFF, 0) ;
|
|
if ( sfrTrim != nullptr)
|
|
sfrTrim->Translate( vToOrig) ;
|
|
else {
|
|
++ nFailedBTrim ;
|
|
continue ;
|
|
}
|
|
// se la superficie di partenza aveva vettori dei nodi non uniformi devo riscalare lo spazio parametrico in modo da renderli uniformi
|
|
// applicando così la trasformazione anche alle curve di trim.
|
|
ON_NurbsSurface onNurbsSurface ;
|
|
onFace->GetNurbForm( onNurbsSurface) ;
|
|
// rendo uniforme lo spazio parametrico nella direzione dei parametri che non lo sono
|
|
int nDegU, nDegV, nSpanU, nSpanV ;
|
|
bool bRat, bTrim ;
|
|
pSurfBezNew->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrim) ;
|
|
// devo rendere lo spazio parametrico uniforme solo se la superficie è trimmata, sennò non serve
|
|
// per capire se la superficie sia trimmata controllo che lo spazio parametrico trimmato non coincida con tutto lo spazio parametrico
|
|
double dParamX = dScaleU /* * SBZ_TREG_COEFF*/ - EPS_SMALL ;
|
|
double dParamY = dScaleV /* * SBZ_TREG_COEFF*/ - EPS_SMALL ;
|
|
PtrOwner<ISurfFlatRegion> pSurfParam(GetSurfFlatRegionRectangle( dParamX > 0 ? dParamX : 2 * EPS_SMALL, dParamY > 0 ? dParamY : 2 * EPS_SMALL)) ;
|
|
// se la sottrazione tra spazio parametrico e superficie di trim è diversa da zero, allora la superficie era trimmata
|
|
if ( sfrTrim != nullptr && pSurfParam->Subtract( *sfrTrim) && pSurfParam->IsValid()) {
|
|
bool bRescaled = false ;
|
|
DBLVECTOR vU0 , vV0 ;
|
|
for ( int i = 0 ; i < onNurbsSurface.KnotCount( 0) ; ++i)
|
|
vU0.push_back( onNurbsSurface.Knot( 0, i)) ;
|
|
for ( int j = 0 ; j < onNurbsSurface.KnotCount( 1) ; ++j)
|
|
vV0.push_back( onNurbsSurface.Knot( 1, j)) ;
|
|
if ( ! MakeUniform( sfrTrim, bRescaled, vU0, vV0, nDegU, nDegV, dScaleU, dScaleV, false)) {
|
|
// se make uniform fallisce potrei provare a farlo rigirare con gli offset ad ogni passaggio, per non avere errori nelle operazioni tra flat region/////////
|
|
if ( MakeUniform( sfrTrim, bRescaled, vU0, vV0, nDegU, nDegV, dScaleU, dScaleV, true)) {
|
|
++ nFailedBTrim ;
|
|
continue ;
|
|
}
|
|
}
|
|
if ( bRescaled) {
|
|
// per correggere eventuali crack create dal lavoro di collage sullo spazio parametrico faccio un OFFSET e controOFFSET
|
|
sfrTrim->Offset( 100*EPS_SMALL, ICurve::OFF_FILLET) ;
|
|
sfrTrim->Offset( -100*EPS_SMALL, ICurve::OFF_FILLET) ;
|
|
}
|
|
pSurfBezNew->SetTrimRegion( *sfrTrim) ;
|
|
}
|
|
else
|
|
sfrTrim->Scale( GLOB_FRM, nSpanU / dScaleU, nSpanV / dScaleV, 1) ;
|
|
|
|
if ( sfrTrim != nullptr)
|
|
delete sfrTrim ;
|
|
|
|
if ( bRev)
|
|
pSurfBezNew->Invert() ;
|
|
|
|
// calcolo i poli
|
|
//pSurfBezNew->CalcPoles() ; // da decommentare quando verrà aggiunta la funzione al master del GeomKernel
|
|
|
|
if ( ! bForceTriMesh)
|
|
vSurf.emplace_back( Release( pSurfBezNew)) ;
|
|
else
|
|
stmSoup.AddSurfTriMesh( *(Release( pSurfBezNew)->GetAuxSurf())) ;
|
|
}
|
|
else {
|
|
++nFailedBz ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( nFailedBFace != 0) {
|
|
string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBFace) + " Brep faces" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
}
|
|
if ( nFailedTm != 0) {
|
|
string sOut = "Import3dm : Failed conversion of " + to_string( nFailedTm) + " trimesh belonging to a Brep" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
}
|
|
if ( nFailedFr != 0) {
|
|
string sOut = "Import3dm : Failed conversion of " + to_string( nFailedFr) + " FlatRegion belonging to a Brep" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
}
|
|
if ( nFailedBz != 0) {
|
|
string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBz) + " NURBS belonging to a Brep" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
}
|
|
if ( nFailedBTrim != 0) {
|
|
string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBTrim) + " trims of surfaces belonging to a Brep" ;
|
|
LOG_ERROR( GetEE3Logger(), sOut.c_str()) ;
|
|
}
|
|
|
|
if ( ! stmSoup.End())
|
|
return vSurf ;
|
|
if ( bSurfTm || bForceTriMesh)
|
|
vSurf.emplace_back( stmSoup.GetSurf()) ;
|
|
|
|
return vSurf ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveComposite*
|
|
Import3dm::ApproxTrim( ICurve* pCrv)
|
|
{
|
|
PtrOwner<ICurveComposite> pCC( CreateCurveComposite()) ;
|
|
//PolyArc paLoopApprox ;
|
|
PolyLine plApprox ;
|
|
// pCrv->ApproxWithArcs(10*EPS_SMALL, ANG_TOL_STD_DEG, paLoopApprox) ;
|
|
pCrv->ApproxWithLines(10*EPS_SMALL, ANG_TOL_STD_DEG, 0, plApprox) ;
|
|
//pCrvCompo->FromPolyArc(paLoopApprox) ;
|
|
pCC->FromPolyLine(plApprox) ;
|
|
pCC->MergeCurves(10*EPS_SMALL, ANG_TOL_STD_DEG) ;
|
|
return Release( pCC) ;
|
|
}
|
|
|
|
////----------------------------------------------------------------------------
|
|
//bool
|
|
//Import3dm::MakeUniform( ISurfFlatRegion** sfr, ON_NurbsSurface onNurbsSurface, double dScaleU, double dScaleV, bool& bRescaled, bool bRetry)
|
|
//{
|
|
// // la superficie in input arriva già scalata
|
|
// bool bRescaledU = false ;
|
|
// bool bRescaledV = false ;
|
|
// int nSpanU = 1, nSpanV = 1 ;
|
|
// PtrOwner<ISurfFlatRegion> sfr_rescaled( CreateSurfFlatRegion()) ;
|
|
// for ( int nDir = 0 ; nDir <= 1 ; ++ nDir) {
|
|
// // vettore dei nodi
|
|
// DBLVECTOR vU ;
|
|
// int nExtraKnots = 0 ;
|
|
// // se la superficie è con deg > 1, periodica, clamped o unclamped devo tagliare Deg - 1 nodi all'estremo interessato
|
|
// if ( onNurbsSurface.Degree(nDir) > 1 || onNurbsSurface.IsPeriodic( nDir)) {
|
|
// nExtraKnots = onNurbsSurface.Degree( nDir) - 1 ;
|
|
// }
|
|
// for ( int i = nExtraKnots ; i < onNurbsSurface.KnotCount( nDir) - nExtraKnots ; ++i ) {
|
|
// double dKnot = onNurbsSurface.Knot( nDir, i) * SBZ_TREG_COEFF ;
|
|
// // lo aggiungo solo se è diverso dal precedente
|
|
// if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL || dKnot < vU.back() - EPS_SMALL)
|
|
// vU.push_back( dKnot) ;
|
|
// }
|
|
// nDir == 0 ? nSpanU = (int)vU.size() - 1 : nSpanV = (int)vU.size() - 1 ;
|
|
// // controllo se il vettore dei nodi è uniforme
|
|
// int a = 0, b = 1 ;
|
|
// double d0 = abs( vU[b] - vU[a]), d1 = d0 ;
|
|
// // il vettore è uniforme quando la distanza tra nodi consecutivi è sempre zero o un valore costante
|
|
// while ( b < (int)vU.size() && ( ( d1 < d0 + EPS_SMALL && d1 > d0 - EPS_SMALL) || d1 < EPS_SMALL)) {
|
|
// a = b ;
|
|
// ++b ;
|
|
// if ( b < (int)vU.size())
|
|
// d1 = abs( vU[b] - vU[a]) ;
|
|
// }
|
|
// if ( b != (int)vU.size()) {
|
|
// nDir == 0 ? bRescaledU = true : bRescaledV = true ;
|
|
// sfr_rescaled.Set( CreateSurfFlatRegion()) ;
|
|
// if ( IsNull( sfr_rescaled))
|
|
// return false ;
|
|
// for ( int p = 0 ; p < (int)vU.size() - 1 ; ++p) {
|
|
// PtrOwner<ISurfFlatRegion> pSfr_copy( (*sfr)->Clone()) ;
|
|
// if ( IsNull( pSfr_copy))
|
|
// return false ;
|
|
// double dLenStrip = abs( vU[p+1] - vU[p]) ;
|
|
// if ( dLenStrip < EPS_SMALL)
|
|
// continue ;
|
|
// // creo la maschera per tagliare la superficie originale e ottenere una striscia
|
|
// PtrOwner<ISurfFlatRegion> pSfrTrim( CreateSurfFlatRegion()) ;
|
|
//
|
|
// // ricavo la maschera del trim, con cui poi farò l'intersezione con la sfr iniziale
|
|
// Vector3d vtTrim ;
|
|
// if ( nDir == 0) {
|
|
// pSfrTrim.Set( GetSurfFlatRegionRectangle( dLenStrip, dScaleV * SBZ_TREG_COEFF + 2)) ;
|
|
// vtTrim.Set( abs(vU[p] - vU.front()), - 1, 0) ;
|
|
// }
|
|
// else{
|
|
// pSfrTrim.Set( GetSurfFlatRegionRectangle( dScaleU * SBZ_TREG_COEFF + 2, dLenStrip)) ;
|
|
// vtTrim.Set( - 1, abs(vU[p] - vU.front()), 0) ;
|
|
// }
|
|
// pSfrTrim->Translate( vtTrim) ;
|
|
//
|
|
// if ( ! pSfr_copy->Intersect( *pSfrTrim))
|
|
// return false ;
|
|
//
|
|
// // aggiungo la nuova striscia solo se è valida
|
|
// if ( pSfr_copy->IsValid() ) {
|
|
// if ( nDir == 0)
|
|
// pSfr_copy->Scale( GLOB_FRM, SBZ_TREG_COEFF / dLenStrip, 1, 1) ;
|
|
// else
|
|
// pSfr_copy->Scale( GLOB_FRM, 1, SBZ_TREG_COEFF / dLenStrip, 1) ;
|
|
//
|
|
// // prima di riunire la striscia al resto devo traslarla sul bordo destro della superificie che sto ricostruendo
|
|
//
|
|
// Point3d pt ;
|
|
// nDir == 0 ? pt.Set( abs(vU[p] - vU.front()), 0, 0) : pt.Set( 0,abs(vU[p] - vU.front()), 0) ;
|
|
// if ( nDir == 0)
|
|
// pt.Scale( GLOB_FRM, SBZ_TREG_COEFF / dLenStrip, 1, 1) ;
|
|
// else
|
|
// pt.Scale( GLOB_FRM, 1, SBZ_TREG_COEFF / dLenStrip, 1) ;
|
|
//
|
|
// Vector3d vtJoin ;
|
|
// if ( nDir == 0)
|
|
// vtJoin.Set( p * SBZ_TREG_COEFF - pt.x, 0, 0) ;
|
|
// else
|
|
// vtJoin.Set( 0, p * SBZ_TREG_COEFF - pt.y, 0) ;
|
|
// pSfr_copy->Translate( vtJoin) ;
|
|
// // se sto ritentando MakeUniform, allora faccio anche OFFSET e controOFFSET
|
|
// if ( bRetry)
|
|
// pSfr_copy->Offset( 10*EPS_SMALL,ICurve::OFF_FILLET) ; // OFFSET
|
|
// if ( sfr_rescaled->IsValid()) {
|
|
// if ( ! sfr_rescaled->Add( *pSfr_copy))
|
|
// return false ;
|
|
// }
|
|
// else
|
|
// sfr_rescaled.Set( pSfr_copy) ;
|
|
// }
|
|
// }
|
|
// if ( nDir == 0) {
|
|
// dScaleU = (int)vU.size() - 1 ;
|
|
// if ( sfr_rescaled->IsValid()) {
|
|
// if ( bRetry)
|
|
// sfr_rescaled->Offset( -10*EPS_SMALL,ICurve::OFF_FILLET) ; //contro OFFSET
|
|
// *sfr = Release( sfr_rescaled) ;
|
|
// }
|
|
// }
|
|
// else
|
|
// dScaleV = (int)vU.size() - 1 ;
|
|
// }
|
|
// }
|
|
//
|
|
// if ( ! IsNull( sfr_rescaled) && sfr_rescaled->IsValid()) {
|
|
// if ( bRetry)
|
|
// sfr_rescaled->Offset( -10*EPS_SMALL,ICurve::OFF_FILLET) ; // contro OFFSET
|
|
// *sfr = Release( sfr_rescaled) ;
|
|
// }
|
|
//
|
|
// if ( ! bRescaledU && ! bRescaledV)
|
|
// ( *sfr)->Scale( GLOB_FRM, nSpanU / dScaleU, nSpanV / dScaleV, 1) ;
|
|
// else if ( bRescaledU && ! bRescaledV)
|
|
// ( *sfr)->Scale( GLOB_FRM, 1, nSpanV / dScaleV, 1) ;
|
|
// else if ( ! bRescaledU && bRescaledV)
|
|
// ( *sfr)->Scale( GLOB_FRM, nSpanU / dScaleU, 1, 1) ;
|
|
//
|
|
// bRescaled = bRescaledU || bRescaledV ;
|
|
// return true ;
|
|
//}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
Import3dm::ConvertBrepLoop( const ON_BrepLoop* onBrepLoop)
|
|
{
|
|
int nTrim = onBrepLoop->TrimCount() ;
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo))
|
|
return nullptr ;
|
|
for ( int i = 0 ; i < nTrim ; ++i) {
|
|
ON_BrepTrim* onBrepTrim = onBrepLoop->Trim( i) ;
|
|
ON_CurveProxy* onCurveProxy = ON_CurveProxy::Cast( onBrepTrim);
|
|
PtrOwner<ICurve> pCrv( ConvertCurve( onCurveProxy)) ;
|
|
if ( IsNull(pCrv) || ! pCrv->IsValid())
|
|
continue ;
|
|
if ( ! pCrvCompo->AddCurve( pCrv->Clone())) {
|
|
Point3d ptEnd ; pCrvCompo->GetEndPoint( ptEnd) ;
|
|
pCrv->ModifyStart( ptEnd) ;
|
|
if ( ! pCrvCompo->AddCurve( pCrv->Clone()))
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
//// APPROSSIMO I BREP LOOP PER ALLEGGERIRE LE OPERAZIONI DI TRIM DELLE BEZIER
|
|
//pCrvCompo->RemoveSmallParts( 0.1, 15) ;
|
|
//pCrvCompo->MergeCurves( 0.1, 15) ;
|
|
|
|
|
|
//PolyArc paApprox ;
|
|
//pCrvCompo->ApproxWithArcs( 0.1, 15, paApprox) ;
|
|
//pCrvCompo->FromPolyArc( paApprox) ;
|
|
|
|
return Release( pCrvCompo) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
Import3dm::ConvertExtrusion( const ON_Extrusion* onExtrusion)
|
|
{
|
|
Point3d ptStart( ConvertPoint( onExtrusion->PathStart())) ;
|
|
Point3d ptEnd( ConvertPoint( onExtrusion->PathEnd())) ;
|
|
Frame3d frRail ;
|
|
frRail.Set( ptStart, Z_AX) ;
|
|
ON_SimpleArray<const ON_Curve*> onSaProfile ;
|
|
int nProfiles = onExtrusion->GetProfileCurves( onSaProfile) ;
|
|
Vector3d vDir = ptEnd - ptStart ;
|
|
int nIsCapped = onExtrusion->IsCapped() ; // 0: no or profile is open /1: bottom cap( ptEnd) /2: top cap( ptStart) /3: both ends capped.
|
|
PtrOwner<ISurfTriMesh> pSurfTm( CreateSurfTriMesh()) ;
|
|
if ( IsNull(pSurfTm))
|
|
return nullptr ;
|
|
// creo la superficie a partire dalle curve
|
|
CICURVEPVECTOR vCrvProfile ;
|
|
for (int i = 0 ; i < nProfiles ; ++i ) {
|
|
const ON_Curve* onCurve = onSaProfile[i] ;
|
|
PtrOwner<ICurve> pCurve( ConvertCurve( onCurve)) ;
|
|
if ( IsNull(pCurve) || ! pCurve->IsValid()) {
|
|
m_mError_count["extrusion"] += 1 ;
|
|
break ;
|
|
}
|
|
pCurve->ToGlob( frRail) ;
|
|
vCrvProfile.emplace_back( Release(pCurve)) ;
|
|
}
|
|
|
|
// se l'estrusione è capped sia sopra che sotto uso la funzione *byRegionExtrusion
|
|
if ( nIsCapped == 3) {
|
|
pSurfTm.Set( GetSurfTriMeshByRegionExtrusion( vCrvProfile, vDir)) ;
|
|
}
|
|
else {
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start())
|
|
return nullptr ;
|
|
for ( int i = 0 ; i < (int)vCrvProfile.size() ; ++i )
|
|
stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( vCrvProfile[i], vDir, false)) ;
|
|
|
|
// controllo se la superficie è capped solo sopra o sotto ed eventualmente aggiungo alla trimesh la superficie adeguata
|
|
if ( nIsCapped != 0) {
|
|
PtrOwner<ISurfTriMesh> pSurfTmCap( GetSurfTriMeshByRegion( vCrvProfile)) ;
|
|
if ( ! IsNull( pSurfTmCap) && pSurfTmCap->IsValid()) {
|
|
// se capped sopra traslo la trimeshregion
|
|
if ( nIsCapped == 1)
|
|
pSurfTmCap->Translate(vDir) ;
|
|
// sennò la aggiungo direttamente
|
|
stmSoup.AddSurfTriMesh( *pSurfTmCap) ;
|
|
}
|
|
}
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
pSurfTm.Set( GetSurfTriMesh( stmSoup.GetSurf())) ;
|
|
}
|
|
|
|
for ( int k = 0 ; k < (int)vCrvProfile.size() ; ++k) {
|
|
if ( vCrvProfile[k] != nullptr)
|
|
delete vCrvProfile[k] ;
|
|
}
|
|
|
|
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid())
|
|
return Release( pSurfTm) ;
|
|
else {
|
|
// se non sono riuscito a creare la superficie per qualche motivo, allora tento una conversione con gli strumenti di OPENURBS prima
|
|
// di convertire la superficie
|
|
//// CONVERSIONE DELL'EXTRUSION AD UN'ALTRA SUPERFICIE RHINO PRIMA DI ESSERE CONVERTITA
|
|
ON_Object* onObject = nullptr ;
|
|
ISurf* pSurf = nullptr ;
|
|
PtrOwner<ISurfBezier> pSurfBz( CreateSurfBezier()) ;
|
|
if ( IsNull( pSurfBz))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pSurfTm))
|
|
return nullptr ;
|
|
if ( onExtrusion->IsCapped() || onExtrusion->ProfileCount() >= 2) {
|
|
onObject = onExtrusion->BrepForm(0) ;
|
|
if ( nullptr != onObject) {
|
|
const ON_Brep* onBrep = ON_Brep::Cast( onObject) ;
|
|
ISURFPOVECTOR vpSurf ;
|
|
vpSurf = ConvertBrep( onBrep, true) ; // chiedo di ottenere un'unica superficie trimesh
|
|
pSurfTm.Set( GetSurfTriMesh( Release(vpSurf[0]))) ;
|
|
}
|
|
}
|
|
if ( onObject == nullptr) {
|
|
onObject = onExtrusion->SumSurfaceForm(0) ;
|
|
if ( onObject != nullptr) {
|
|
const ON_Surface* onSurface = ON_Surface::Cast( onObject) ;
|
|
pSurf = ConvertSurface( onSurface) ;
|
|
pSurfTm.Set( GetSurfTriMesh(pSurf)) ;
|
|
}
|
|
}
|
|
if ( onObject == nullptr) {
|
|
onObject = onExtrusion->NurbsSurface(0) ;
|
|
if ( onObject != nullptr) {
|
|
const ON_NurbsSurface* onNurbsSurface = ON_NurbsSurface::Cast( onObject) ;
|
|
pSurf = ConvertSurface( onNurbsSurface) ;
|
|
// in questo caso devo anche trasformare la superficie di bezier che ho appenta ottenuto in una trimesh
|
|
pSurfBz.Set( GetSurfBezier( pSurf)) ;
|
|
pSurfTm.Set( pSurfBz->GetAuxSurf()->Clone()) ;
|
|
}
|
|
}
|
|
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid())
|
|
return Release( pSurfTm) ;
|
|
}
|
|
|
|
m_mError_count["extrusion"] += 1 ;
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
Import3dm::ConvertMesh( const ON_Mesh* onMesh)
|
|
{
|
|
ON_Mesh* onMeshToConvert = onMesh->Duplicate() ;
|
|
PtrOwner<ISurfTriMesh> pSurfTm( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pSurfTm))
|
|
return nullptr ;
|
|
|
|
int nVertices = onMesh->VertexCount() ;
|
|
bool bDoublePrec = onMesh->HasDoublePrecisionVertices() ;
|
|
for ( int i = 0 ; i < nVertices ; ++i ) {
|
|
Point3d pt = ConvertPoint( bDoublePrec ? *( onMesh->m_dV.At( i)) : *( onMesh->m_V.At( i))) ;
|
|
pSurfTm->AddVertex( pt) ;
|
|
}
|
|
ON_MeshFaceList onFaceList( onMesh) ;
|
|
int nQuads = onMesh->QuadCount() ;
|
|
|
|
//split_method - [in]
|
|
// 0 default - Currently divides along the short diagonal.
|
|
// 1 divide along the short diagonal
|
|
// 2 divide along the long diagonal
|
|
// 3 minimize resulting area
|
|
// 4 maximize resulting area
|
|
// 5 minimize angle between triangle normals
|
|
// 6 maximize angle between triangle normals
|
|
double dLinTol = ON_UNSET_VALUE ;
|
|
double dAndTolRad = ON_UNSET_VALUE ;
|
|
unsigned int nSplitMethod = 0 ;
|
|
bool bStillQuads = false ;
|
|
if ( nQuads != 0) {
|
|
// restituisce il numero di quadrati convertiti
|
|
unsigned int nQuadsNonPlanarConv = onMeshToConvert->ConvertNonPlanarQuadsToTriangles( dLinTol, dAndTolRad, nSplitMethod) ;
|
|
bStillQuads = nQuadsNonPlanarConv == 0 ? true : false ;
|
|
}
|
|
int nFaces = onMeshToConvert->FaceCount() ;
|
|
for (int j = 0 ; j < nFaces ; ++j) {
|
|
const ON_MeshFace* onMeshFace = onMeshToConvert->m_F.At( j) ;
|
|
if ( ! bStillQuads ) {
|
|
int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[2]} ;
|
|
pSurfTm->AddTriangle( nIdVert) ;
|
|
}
|
|
else if ( onFaceList.IsQuad( j)) {
|
|
// la divisione automatica non è riuscita.
|
|
// divido lungo la diagonale più corta
|
|
Point3d pt0 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[0])) ;
|
|
Point3d pt1 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[1])) ;
|
|
Point3d pt2 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[2])) ;
|
|
Point3d pt3 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[3])) ;
|
|
if ( Dist( pt0, pt2) < Dist( pt1, pt3)) {
|
|
int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[2]} ;
|
|
pSurfTm->AddTriangle( nIdVert) ;
|
|
int nIdVert2[3] = {onMeshFace->vi[0], onMeshFace->vi[2],onMeshFace->vi[3]} ;
|
|
pSurfTm->AddTriangle( nIdVert2) ;
|
|
}
|
|
else {
|
|
int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[3]} ;
|
|
pSurfTm->AddTriangle( nIdVert) ;
|
|
int nIdVert2[3] = {onMeshFace->vi[1], onMeshFace->vi[2],onMeshFace->vi[3]} ;
|
|
pSurfTm->AddTriangle( nIdVert2) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete onMeshToConvert ;
|
|
|
|
pSurfTm->AdjustTopology() ;
|
|
return Release( pSurfTm) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::vector<PtrOwner<IGeoObj>>
|
|
Import3dm::ConvertAnnotation( const ON_Annotation* onAnnot, const ON_DimStyle* onDimStyle, double dTextHeight, double dExtLine, double dArrLen, double dTextDist,
|
|
bool bLenIsMM, int nDecDig, std::string sFont)
|
|
{
|
|
// TO DO
|
|
// la posizione è da correggere se le annotazioni sono presenti nell'anteprima di stampa
|
|
// ( dovrebbe esserci nel modello un oggetto detail che ne definisce l'impaginazione)
|
|
vector<PtrOwner<IGeoObj>> vpObj ;
|
|
ON::AnnotationType onAnnType = onAnnot->Type() ;
|
|
switch( onAnnType) {
|
|
case ON::AnnotationType::Text : {
|
|
const ON_Text* onText = ON_Text::Cast( onAnnot) ;
|
|
ON_wString wsText = onText->PlainText() ;
|
|
std::wstring ws( wsText) ;
|
|
std::string str( ws.begin(), ws.end()) ;
|
|
ON_Plane onPlane = onText->Plane() ;
|
|
Point3d ptOrig = ConvertPoint( onPlane.origin) ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Vector3d vtDir = ConvertVector( onText->HorizontalDirection()) ;
|
|
PtrOwner<IExtText> tText( CreateExtText()) ;
|
|
|
|
tText->Set( ptOrig, vtN, vtDir, str, sFont, false, dTextHeight) ;
|
|
if ( ! IsNull( tText) && tText->IsValid()) {
|
|
vpObj.emplace_back( Release( tText)) ;
|
|
return vpObj ;
|
|
}
|
|
else
|
|
m_mError_count["annotation"] += 1 ;
|
|
break ;
|
|
}
|
|
case ON::AnnotationType::Leader : {
|
|
const ON_Leader* onLeader = ON_Leader::Cast( onAnnot) ;
|
|
ON_wString wsText = onLeader->PlainText() ;
|
|
std::wstring ws( wsText) ;
|
|
std::string str( ws.begin(), ws.end()) ;
|
|
ON_Plane onPlane = onAnnot->Plane() ;
|
|
Point3d ptOrig = ConvertPoint( onPlane.origin) ;
|
|
Vector3d vtX = ConvertVector( onPlane.xaxis) ;
|
|
Vector3d vtY = ConvertVector( onPlane.yaxis) ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Vector3d vtDir = ConvertVector( onAnnot->HorizontalDirection()) ;
|
|
ON_2dPoint on2dPoint ;
|
|
double dScale = onLeader->DimScale( onDimStyle) ;
|
|
onLeader->GetTextPoint2d( onDimStyle, dScale, on2dPoint) ;
|
|
Point3d ptTextPoint( on2dPoint.x, on2dPoint.y) ;
|
|
Frame3d frPlane ;
|
|
frPlane.Set( ptOrig, vtX, vtY,vtN) ;
|
|
ptTextPoint.ToGlob( frPlane) ;
|
|
PtrOwner<IExtText> tText( CreateExtText()) ;
|
|
tText->Set( ptTextPoint, vtN, vtDir, str, sFont, false, dTextHeight) ;
|
|
//aggiungo al gruppo: testo, linea e landing
|
|
if ( ! IsNull( tText) && tText->IsValid())
|
|
vpObj.emplace_back( Release( tText)) ;
|
|
else
|
|
break ;
|
|
const ON_Curve* onCurve = onLeader->Curve( onDimStyle) ;
|
|
PtrOwner<ICurve> pCurve( ConvertCurve( onCurve)) ;
|
|
if ( ! IsNull( pCurve) && pCurve->IsValid()) {
|
|
vpObj.emplace_back( Release( pCurve)) ;
|
|
}
|
|
else {
|
|
vpObj.clear() ;
|
|
break ;
|
|
}
|
|
if ( onLeader->LeaderHasLanding( onDimStyle)) {
|
|
ON_Line onLine ;
|
|
onLeader->LandingLine2d( onDimStyle, dScale, onLine) ;
|
|
Point3d ptStart = ConvertPoint(onLine.from) ;
|
|
Point3d ptEnd = ConvertPoint(onLine.to) ;
|
|
PtrOwner<ICurveLine> pCrvL( CreateCurveLine()) ;
|
|
pCrvL->Set( ptStart, ptEnd) ;
|
|
if ( ! IsNull( pCrvL) && pCrvL->IsValid()) {
|
|
pCrvL->ToGlob( frPlane) ;
|
|
vpObj.emplace_back( Release( pCrvL)) ;
|
|
}
|
|
else {
|
|
vpObj.clear() ;
|
|
break ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
case ON::AnnotationType::Aligned :
|
|
case ON::AnnotationType::Rotated : {
|
|
const ON_DimLinear* onDimLin = ON_DimLinear::Cast( onAnnot) ;
|
|
// recupero tutti i dati della quota
|
|
ON_3dPoint onPt1, onPt2, onPtAr1, onPtAr2, onPtDimLine, onPtText ;
|
|
onDimLin->Get3dPoints( &onPt1, &onPt2, &onPtAr1, &onPtAr2, &onPtDimLine, &onPtText) ;
|
|
double dAngDeg = onDimLin->TextRotationRadians() * RADTODEG ; // rotazione del testo rispetto alla direzione orizzontale
|
|
ON_Plane onPlane = onDimLin->Plane() ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Vector3d vtDir = ConvertPoint(onPt2) - ConvertPoint(onPt1) ;
|
|
if ( ! vtDir.Normalize() ||
|
|
! vtDir.Rotate( vtN, dAngDeg))
|
|
break ;
|
|
Point3d ptP1( ConvertPoint( onPt1)) ;
|
|
Point3d ptP2( ConvertPoint( onPt2)) ;
|
|
Point3d ptPDimL( ConvertPoint( onPtDimLine)) ;
|
|
|
|
// creo la quota
|
|
PtrOwner<IExtDimension> pDim( CreateExtDimension()) ;
|
|
if ( onAnnType == ON::AnnotationType::Aligned) {
|
|
if ( IsNull( pDim ) ||
|
|
! pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) ||
|
|
! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, V_NULL, "<>"))
|
|
break ;
|
|
}
|
|
else if ( onAnnType == ON::AnnotationType::Rotated){
|
|
if ( IsNull( pDim ) ||
|
|
! pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) ||
|
|
! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, vtDir, "<>"))
|
|
break ;
|
|
}
|
|
|
|
// inserisco la quota nel DB
|
|
if ( ! IsNull( pDim) && pDim->IsValid()) {
|
|
vpObj.emplace_back( Release( pDim)) ;
|
|
return vpObj ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
case ON::AnnotationType::Angular :
|
|
case ON::AnnotationType::Angular3pt : {
|
|
// recupero tutti i dati della quota
|
|
const ON_DimAngular* onDimAng = ON_DimAngular::Cast( onAnnot) ;
|
|
ON_3dPoint onPtCen, onPt1, onPt2, onPtAr1, onPtAr2, onPtDimLine, onPtText ;
|
|
onDimAng->Get3dPoints( &onPtCen, &onPt1, &onPt2, &onPtAr1, &onPtAr2, &onPtDimLine, &onPtText) ;
|
|
ON_Plane onPlane = onDimAng->Plane() ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Point3d ptCen( ConvertPoint( onPtCen)) ;
|
|
Point3d ptP1( ConvertPoint( onPt1)) ;
|
|
Point3d ptP2( ConvertPoint( onPt2)) ;
|
|
Point3d ptPDimL( ConvertPoint( onPtDimLine)) ;
|
|
|
|
// creo la quota
|
|
PtrOwner<IExtDimension> pDim( CreateExtDimension()) ;
|
|
if ( ! IsNull( pDim) &&
|
|
pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) &&
|
|
pDim->SetAngular( ptP1, ptCen, ptP2, ptPDimL, vtN, "<>") &&
|
|
pDim->IsValid()) {
|
|
vpObj.emplace_back( Release( pDim)) ;
|
|
return vpObj ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
case ON::AnnotationType::Radius : {
|
|
const ON_DimRadial* onDimRad = ON_DimRadial::Cast( onAnnot) ;
|
|
ON_3dPoint onPtCen, onPt1, onPt2, onPtDim ;
|
|
onDimRad->Get3dPoints( &onPtCen, &onPtDim, &onPt1, &onPt2) ;
|
|
ON_Plane onPlane = onDimRad->Plane() ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Point3d ptCen( ConvertPoint( onPtCen)) ;
|
|
Point3d ptDim( ConvertPoint( onPtDim)) ;
|
|
|
|
// creo la quota
|
|
PtrOwner<IExtDimension> pDim( CreateExtDimension()) ;
|
|
if ( ! IsNull( pDim ) &&
|
|
pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) &&
|
|
pDim->SetRadial( ptCen, ptDim, vtN, "<>")) {
|
|
vpObj.emplace_back( Release( pDim)) ;
|
|
return vpObj ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
case ON::AnnotationType::Diameter : {
|
|
const ON_DimRadial* onDimRad = ON_DimRadial::Cast( onAnnot) ;
|
|
ON_3dPoint onPtCen, onPt1, onPt2, onPtDim ;
|
|
onDimRad->Get3dPoints( &onPtCen, &onPtDim, &onPt1, &onPt2) ;
|
|
ON_Plane onPlane = onDimRad->Plane() ;
|
|
Vector3d vtN = ConvertVector( onPlane.Normal()) ;
|
|
Point3d ptCen( ConvertPoint( onPtCen)) ;
|
|
Point3d ptDim( ConvertPoint( onPtDim)) ;
|
|
// creo la quota
|
|
PtrOwner<IExtDimension> pDim( CreateExtDimension()) ;
|
|
if ( ! IsNull( pDim ) ||
|
|
pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) ||
|
|
pDim->SetDiametral( ptCen, ptDim, vtN, "<>")) {
|
|
vpObj.emplace_back( Release( pDim)) ;
|
|
return vpObj ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
default :
|
|
break ;
|
|
}
|
|
|
|
m_mError_count["annotation"] += 1 ;
|
|
return vpObj ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Import3dm::ConvertCurveParam( const ON_RevSurface* onRevSurf, ICurve** pCrv)
|
|
{
|
|
PtrOwner<ICurve> pCrvNew ;
|
|
if ( (*pCrv)->GetType() == CRV_LINE) {
|
|
PtrOwner<ICurveLine> pCrvLine( CreateCurveLine()) ;
|
|
double dnurbsU ;
|
|
double dnurbsV ;
|
|
Point3d ptStart ; (*pCrv)->GetStartPoint( ptStart) ;
|
|
onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptStart.x, ptStart.y, &dnurbsU, &dnurbsV) ;
|
|
ptStart.Set( dnurbsU, dnurbsV, 0) ;
|
|
Point3d ptEnd ; (*pCrv)->GetEndPoint( ptEnd) ;
|
|
onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptEnd.x, ptEnd.y, &dnurbsU, &dnurbsV) ;
|
|
ptEnd.Set( dnurbsU, dnurbsV, 0) ;
|
|
pCrvLine->Set( ptStart, ptEnd) ;
|
|
pCrvNew.Set( Release( pCrvLine)) ;
|
|
}
|
|
else if ( (*pCrv)->GetType() == CRV_ARC) {
|
|
double dnurbsU ;
|
|
double dnurbsV ;
|
|
Point3d ptStart ; (*pCrv)->GetStartPoint( ptStart) ;
|
|
onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptStart.x, ptStart.y, &dnurbsU, &dnurbsV) ;
|
|
ptStart.Set( dnurbsU, dnurbsV, 0) ;
|
|
Point3d ptEnd ; (*pCrv)->GetEndPoint( ptEnd) ;
|
|
onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptEnd.x, ptEnd.y, &dnurbsU, &dnurbsV) ;
|
|
ptEnd.Set( dnurbsU, dnurbsV, 0) ;
|
|
Vector3d vtDir, vtN ;
|
|
(*pCrv)->GetStartDir( vtDir) ;
|
|
ICurveArc* pCrvArcOrig = GetCurveArc( (*pCrv)) ;
|
|
vtN = pCrvArcOrig->GetNormVersor( ) ;
|
|
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
|
|
pCrvArc->Set2PVN( ptStart, ptEnd, vtDir, vtN) ;
|
|
pCrvNew.Set( Release( pCrvArc)) ;
|
|
}
|
|
else if ( (*pCrv)->GetType() == CRV_BEZIER) {
|
|
double dnurbsU ;
|
|
double dnurbsV ;
|
|
PtrOwner<ICurveBezier> pCrvBez( GetCurveBezier( (*pCrv))) ;
|
|
int nDeg = pCrvBez->GetDegree() ;
|
|
int nCV = nDeg + 1 ;
|
|
for ( int i = 0 ; i < nCV ; ++i) {
|
|
Point3d ptNew = pCrvBez->GetControlPoint( i) ;
|
|
onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptNew.x, ptNew.y, &dnurbsU, &dnurbsV) ;
|
|
ptNew.Set( dnurbsU, dnurbsV, 0) ;
|
|
// sto cambiando le coordinate dei CP nella curva, mentre i pesi non sono da modificare
|
|
pCrvBez->SetControlPoint( i, ptNew) ;
|
|
}
|
|
pCrvNew.Set( pCrvBez) ;
|
|
}
|
|
else if ( (*pCrv)->GetType() == CRV_COMPO) {
|
|
PtrOwner<ICurveComposite> pCrvCompo( GetCurveComposite( (*pCrv))) ;
|
|
PtrOwner<ICurveComposite> pCrvCompoNew( CreateCurveComposite()) ;
|
|
for ( const ICurve* pCrvSimpleOrig = pCrvCompo->GetFirstCurve() ; pCrvSimpleOrig != nullptr ; pCrvSimpleOrig = pCrvCompo->GetNextCurve()) {
|
|
ICurve* pCrvSimple( pCrvSimpleOrig->Clone()) ;
|
|
ConvertCurveParam( onRevSurf, &pCrvSimple) ;
|
|
pCrvCompoNew->AddCurve( pCrvSimple) ;
|
|
}
|
|
pCrvNew.Set( pCrvCompoNew) ;
|
|
}
|
|
|
|
(*pCrv) = Release( pCrvNew) ;
|
|
|
|
return true ;
|
|
}
|