Files
EgtExchange/Import3dm.cpp
Daniele Bariletti f50d5b7612 EgtExchange :
- correzione al trim delle Bezier importate da NURBS.
2023-11-07 17:37:58 +01:00

1402 lines
60 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 "map"
#include "/EgtDev/Include/EExDllMain.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/EGkSurfFlatRegion.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
#include "/EgtDev/Include/EGkSurf.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/Extern/opennurbs/Include/opennurbs.h"
#include "/EgtDev/Include/EGkGeoObjSave.h"
using namespace std ;
//----------------------------------------------------------------------------
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 dScaleFactor,
double dTextHeight, double dExtLine, double dArrLen, double dTextDist,
bool bLenIsMM, int nDecDig, std::string sFont)
{
// verifico il DB geometrico
if ( pGDB == nullptr) {
LOG_ERROR( GetEExLogger(), "Import3dm : Error on GeomDB")
return false ;
}
m_pGDB = pGDB ;
// verifico l'Id di gruppo
if ( ! m_pGDB->ExistsObj( nIdGroup)) {
LOG_ERROR( GetEExLogger(), "Import3dm : Error on IdGroup")
return false ;
}
m_nIdGroup = nIdGroup ;
// verifico il fattore di scala
if ( dScaleFactor < EPS_SMALL) {
LOG_ERROR( GetEExLogger(), "Import3dm : Error on ScaleFactor too small (minimum 0.001).")
return false ;
}
m_dScaleFactor = dScaleFactor ;
ONX_Model model;
std::wstring widestr = std::wstring(sFile.begin(), sFile.end()) ;
const wchar_t* sFileName = widestr.c_str() ;
FILE* archive_fp = ON::OpenFile( sFileName, L"rb") ;
if ( !archive_fp )
{
LOG_ERROR( GetEExLogger(), "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( GetEExLogger(), "Unable to read file." ) ;
// close the file
ON::CloseFile( archive_fp ) ;
// LAYER//////////////////////////////
// li conto e li creo
ONX_ModelComponentIterator component_iterator_l ( model, ON_ModelComponent::Type::Layer) ;
int nIdLayer ;
m_pGDB->Erase( 2) ;
std::vector<const ON_Layer*> vLayer ;
for( const ON_ModelComponent* mc = component_iterator_l.FirstComponent() ; nullptr != mc ; mc = component_iterator_l.NextComponent()) {
nIdLayer = m_pGDB->AddGroup( GDB_ID_NULL, 1, GLOB_FRM) ;
const ON_Layer* onLayer = ON_Layer::Cast( mc) ;
vLayer.push_back( onLayer) ;
if ( onLayer->NameIsSet()) {
const ON_wString onStr = onLayer->Name() ;
std::wstring ws( onStr) ;
std::string str( ws.begin(), ws.end()) ;
m_pGDB->SetName( nIdLayer, str) ;
}
}
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
map< string, int> error_count ;
int nId ;
for( const ON_ModelComponent* mc = component_iterator.FirstComponent() ; nullptr != mc ; 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 ;
// 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 = vLayer[nLayer]->Color() ;
break ;
}
case ON::color_from_object: {
onCol = attributes->m_color ;
break ;
}
case ON::color_from_material: {
// non gestito
break ;
}
}
// i nostri layer partono da 2 e non da 0
nLayer = nLayer + 2 ;
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() ;
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()) ;
pGeoPnt->Set( pt) ;
if ( ! IsNull( pGeoPnt) && pGeoPnt->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release(pGeoPnt)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["point"] += 1 ;
break ;
}
case ON::object_type::pointset_object : {
const ON_PointCloud* pc = ON_PointCloud::Cast( oGeometry);
if ( nullptr == pc ) {
error_count["pointset"] += 1 ;
break ;
}
int count = pc->PointCount() ;
Frame3d frLayer = m_pGDB->GetGroupFrame( nLayer) ;
int nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, frLayer) ;
for ( int i = 0; i < count ; i++ ) {
Point3d pt( ConvertPoint( pc->m_P[i])) ;
// lo aggiungo al GeomDB nel layer corretto
PtrOwner<IGeoPoint3d> pGeoPnt( CreateGeoPoint3d()) ;
pGeoPnt->Set( pt) ;
if ( ! IsNull( pGeoPnt) && pGeoPnt->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nSubLayer, Release(pGeoPnt)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_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()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pCurve)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_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() ) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pSurf)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["surface"] += 1 ;
break ;
}
case ON::object_type::brep_object : {
const ON_Brep* onBrep = ON_Brep::Cast( oGeometry) ;
ISURFPVECTOR vpSurf = ConvertBrep( onBrep, false) ;
int nGroup = nLayer ;
if ( int(vpSurf.size()) > 1)
nGroup = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, GLOB_FRM) ;
for (int k = 0 ; k < int( vpSurf.size()) ; ++k) {
if ( vpSurf[k]->GetType() == SRF_TRIMESH) {
PtrOwner<ISurfTriMesh> pSurfTm( GetSurfTriMesh( vpSurf[k])) ;
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nGroup, Release(pSurfTm)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["brep"] += 1 ;
}
else if ( vpSurf[k]->GetType() == SRF_BEZIER ) {
PtrOwner<ISurfBezier> pSurfBz( GetSurfBezier( vpSurf[k])) ;
if ( ! IsNull( pSurfBz) && pSurfBz->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nGroup, Release(pSurfBz)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["brep"] += 1 ;
}
}
break ;
}
case ON::object_type::extrusion_object : {
const ON_Extrusion* onExtrusion = ON_Extrusion::Cast( oGeometry) ;
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) ) {
error_count["memory"] += 1 ;
break ;
}
StmFromTriangleSoup stmSoup ;
if ( ! stmSoup.Start())
return false ;
// creo la superficie a partire dalle curve
if ( nIsCapped == 0) {
for (int i = 0 ; i < nProfiles ; ++i ) {
const ON_Curve* onCurve = onSaProfile[i] ;
ICurve* pCurve = nullptr ;
pCurve = ConvertCurve( onCurve) ;
pCurve->ToGlob( frRail) ;
stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( pCurve, vDir, false)) ;
}
}
// se capped
else {
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() ) {
error_count["extrusion"] += 1 ;
break ;
}
pCurve->ToGlob( frRail) ;
vCrvProfile.push_back( Release(pCurve)) ;
}
// se l'estrusione è capped sia sopra che sotto uso la funzione *byRegionExtrusion
if ( nIsCapped == 3) {
pSurfTm.Set( GetSurfTriMeshByRegionExtrusion( vCrvProfile, vDir)) ;
}
// controllo se la superficie è capped solo sopra o sotto ed eventualmente aggiungo alla trimesh la superficie adeguata
else {
for (int i = 0 ; i < nProfiles ; ++i ) {
PtrOwner<const ICurve> pCurveToAdd( vCrvProfile[i]) ;
if ( IsNull( pCurveToAdd) || ! pCurveToAdd->IsValid()) {
error_count["extrusion"] += 1 ;
break ;
}
stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( Release( pCurveToAdd), vDir, false)) ;
}
if ( nIsCapped == 1) {
PtrOwner<ISurfTriMesh> pSurfTmCap( GetSurfTriMeshByRegion( vCrvProfile)) ;
if ( IsNull( pSurfTmCap) || ! pSurfTmCap->IsValid()) {
error_count["extrusion"] += 1 ;
break ;
}
pSurfTmCap->Translate(vDir) ;
stmSoup.AddSurfTriMesh( *Release(pSurfTmCap)) ;
}
else if ( nIsCapped == 2 ) {
stmSoup.AddSurfTriMesh( *GetSurfTriMeshByRegion( vCrvProfile)) ;
}
}
}
if ( ! stmSoup.End())
return false ;
if ( nIsCapped != 3)
pSurfTm.Set( GetSurfTriMesh( stmSoup.GetSurf())) ;
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pSurfTm)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
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<const ISurfBezier> pSurfBz( CreateSurfBezier()) ;
if ( IsNull( pSurfBz) || ! pSurfBz->IsValid())
return false ;
PtrOwner<const ISurfTriMesh> pSurfTm( CreateSurfTriMesh()) ;
if ( IsNull( pSurfTm) || ! pSurfTm->IsValid())
return false ;
if ( onExtrusion->IsCapped() || onExtrusion->ProfileCount() >= 2) {
onObject = onExtrusion->BrepForm(0) ;
if ( nullptr != onObject) {
const ON_Brep* onBrep = ON_Brep::Cast( onObject) ;
ISURFPVECTOR vpSurf ;
vpSurf = ConvertBrep( onBrep, true) ; // chiedo di ottenere un'unica superficie trimesh
pSurfTm.Set( GetSurfTriMesh( vpSurf[0])) ;
}
}
if ( nullptr == onObject) {
onObject = onExtrusion->SumSurfaceForm(0) ;
if ( nullptr != onObject) {
const ON_Surface* onSurface = ON_Surface::Cast( onObject) ;
pSurf = ConvertSurface( onSurface) ;
pSurfTm.Set( GetSurfTriMesh(pSurf)) ;
}
}
if ( nullptr == onObject) {
onObject = onExtrusion->NurbsSurface(0) ;
if ( nullptr != onObject) {
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()) ;
}
}
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, pSurfTm->Clone()) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["extrusion"] += 1 ;
}
break ;
}
case ON::object_type::mesh_object :{
const ON_Mesh* onMesh = ON_Mesh::Cast( oGeometry) ;
ON_Mesh* onMeshToConvert = onMesh->Duplicate() ;
PtrOwner<ISurfTriMesh> pSurfTm( CreateSurfTriMesh()) ;
if ( IsNull( pSurfTm))
return false ;
if ( IsNull( pSurfTm)) {
error_count["memory"] += 1 ;
break ;
}
int nVertices = onMesh->VertexCount() ;
bool bDoublePrec = onMesh->HasDoublePrecisionVertices() ;
if ( bDoublePrec) {
for ( int i = 0 ; i < nVertices ; ++i ) {
Point3d pt = ConvertPoint( *(onMesh->m_dV.At(i)));
pSurfTm->AddVertex( pt) ;
}
}
else {
for ( int i = 0 ; i < nVertices ; ++i ) {
Point3d pt = ConvertPoint( *(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_dV.At(onMeshFace->vi[0])) ;
Point3d pt1 = ConvertPoint( *onMesh->m_dV.At(onMeshFace->vi[1])) ;
Point3d pt2 = ConvertPoint( *onMesh->m_dV.At(onMeshFace->vi[2])) ;
Point3d pt3 = ConvertPoint( *onMesh->m_dV.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) ;
}
}
}
pSurfTm->AdjustTopology() ;
if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) {
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nLayer, Release( pSurfTm)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_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()) {
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nLayer, Release( pCurve)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["loop"] += 1 ;
break ;
}
case ON::object_type::subd_object: {
// non c'è un comando per convertire le subd in altre superfici...
//
//const ON_SubD* onSubD = ON_SubD::Cast( oGeometry) ;
//ON_Surface* onSurface ; //= ON_Surface::Cast() ;
//PtrOwner<ISurf> pSurf( ConvertSurface( onSurface)) ;
//if ( ! IsNull( pSurf) && pSurf->IsValid())
// m_pGDB->AddGeoObj(GDB_ID_NULL, nLayer, Release( pSurf)) ;
//else
// error_count["subd"] += 1 ;
error_count["subd"] += 1 ;
break ;
}
case ON::object_type::annotation_object: {
// funziona ma crea un avviso di possibile perdita dati
const ON_Annotation* onAnnot = ON_Annotation::Cast( oGeometry) ;
ON::AnnotationType onAnnType = onAnnot->Type() ;
// 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) ;
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()) ;
// la posizione non è corretta!! devo capire dove piazzarla//////////////////////////////////////////////////////////
//onAnnot->location // non esiste
tText->Set( ptOrig, vtN, vtDir, str, sFont, false, dTextHeight) ;
if ( ! IsNull( tText) && tText->IsValid()) {
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nLayer, Release( tText)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_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()) ;
//????????????????????????????????????????????????????
///// posizione del testo 1
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) ;
////// posizione del testo 2
//ON_2dPoint onBasePoint, onWidthPoint ;
//onLeader->GetTextGripPoints( onBasePoint, onWidthPoint, onDimStyle, dScale) ;
//ptTextPoint.Set( onWidthPoint.x, onWidthPoint.y , 0.0) ;
//ptTextPoint.ToGlob( frPlane) ;
//tText->Set( ptTextPoint, vtN, vtDir, str, "ModernPropS.Nfe", false, 2.56) ;
// creo un gruppo per mettere tutti gli oggetti del leader
int nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, GLOB_FRM) ;
//aggiungo al gruppo: testo, linea e landing
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nSubLayer, Release( tText)) ;
m_pGDB->SetMaterial( nId, cCol) ;
const ON_Curve* onCurve = onLeader->Curve( onDimStyle) ;
PtrOwner<ICurve> pCurve( ConvertCurve( onCurve)) ;
//pCurve->ToGlob( frPlane) ;
//pCurve->ToLoc( GLOB_FRM) ;
//pCurve->ToLoc( frPlane) ;
if ( ! IsNull( pCurve) && pCurve->IsValid()) {
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nSubLayer, Release( pCurve)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else {
error_count["annotation"] += 1 ;
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) ;
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nSubLayer, Release( pCrvL)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["annotation"] += 1 ;
}
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)) {
error_count["annotation"] += 1 ;
break ;
}
Point3d ptP1( ConvertPoint( onPt1)) ;
Point3d ptP2( ConvertPoint( onPt2)) ;
//Point3d ptPAr1( ConvertPoint( onPtAr1)) ;
//Point3d ptPAr2( ConvertPoint( onPtAr2)) ;
Point3d ptPDimL( ConvertPoint( onPtDimLine)) ;
//Point3d ptPText( ConvertPoint( onPtText)) ;
// 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, "<>")) {
error_count["annotation"] += 1 ;
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, "<>")){
error_count["annotation"] += 1 ;
break ;
}
}
// inserisco la quota nel DB
if ( ! IsNull( pDim) && pDim->IsValid()) {
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pDim)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["annotation"] += 1 ;
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 ptPAr1( ConvertPoint( onPtAr1)) ;
//Point3d ptPAr2( ConvertPoint( onPtAr2)) ;
Point3d ptPDimL( ConvertPoint( onPtDimLine)) ;
//Point3d ptPText( ConvertPoint( onPtText)) ;
// 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()) {
// inserisco la quota nel DB
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pDim)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["annotation"] += 1 ;
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, "<>")) {
// inserisco la quota nel DB
nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nLayer, Release( pDim)) ;
m_pGDB->SetMaterial( nId, cCol) ;
}
else
error_count["annotation"] += 1 ;
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, "<>")) {
// inserisco la quota nel DB
nId = m_pGDB->AddGeoObj(GDB_ID_NULL, nLayer, Release(pDim)) ;
m_pGDB->SetMaterial(nId, cCol) ;
}
else
error_count["annotation"] += 1 ;
break ;
}
default :
break ;
}
break ;
}
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: {
error_count["other"] += 1 ;
break ;
}
}
}
// messaggio di errore da mettere nel log per dire quanti oggetti sono stati ignorati perché la conversione non è riuscita
map<string, int>::iterator it = error_count.begin() ;
while (it != error_count.end()) {
string type = it->first ;
int count = it->second ;
if ( type != "memory" ) {
string sOut = "Sono stati ignorati " + to_string( count) + " oggetti di tipo " + type ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
else {
string sOut = "Sono stati ignorati " + to_string( count) + " oggetti perché è finita la memoria" ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
it++;
}
return true ;
}
//----------------------------------------------------------------------------
Point3d
Import3dm::ConvertPoint( const ON_Point& onPoint)
{
double x = onPoint.point.x ;
double y = onPoint.point.y ;
double z = onPoint.point.z ;
// creo il punto nel nostro kernel
Point3d pt( x, y, z) ;
return pt ;
}
//----------------------------------------------------------------------------
Point3d
Import3dm::ConvertPoint( const ON_3dPoint& on3dPoint)
{
double x = on3dPoint.x ;
double y = on3dPoint.y ;
double z = on3dPoint.z ;
// creo il punto nel nostro kernel
Point3d pt( x, y, z) ;
return pt ;
}
//----------------------------------------------------------------------------
Point3d
Import3dm::ConvertPoint( const ON_4dPoint& on4dPoint)
{
double x = on4dPoint.x ;
double y = on4dPoint.y ;
double z = on4dPoint.z ;
// creo il punto nel nostro kernel
Point3d pt( x, y, z) ;
return pt ;
}
//----------------------------------------------------------------------------
Point3d
Import3dm::ConvertPoint( const ON_3fPoint& on3fPoint)
{
double x = on3fPoint.x ;
double y = on3fPoint.y ;
double z = on3fPoint.z ;
// creo il punto nel nostro kernel
Point3d pt( x, y, z) ;
return pt ;
}
//----------------------------------------------------------------------------
Vector3d
Import3dm::ConvertVector( const ON_3dVector& onVector)
{
Vector3d vt ;
vt.x = onVector.x ;
vt.y = onVector.y ;
vt.z = onVector.z ;
return vt ;
}
//----------------------------------------------------------------------------
Vector3d
Import3dm::ConvertVector( const ON_2dVector& onVector)
{
Vector3d vt ;
vt.x = onVector.x ;
vt.y = onVector.y ;
vt.z = 0 ;
return vt ;
}
//----------------------------------------------------------------------------
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()))) ;
ON_3dVector on_vtN = onArc->m_arc.plane.zaxis ;
Vector3d vtN = ConvertVector( on_vtN) ;
PtrOwner<ICurveArc> pCurveArc( CreateCurveArc()) ;
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 ;
}
// 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) ;
ON_Curve* onCurve = onProxyCurve->DuplicateCurve() ;
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_) ;
int nSpanU = onNurbsSurface.SpanCount(0);
int nSpanV = onNurbsSurface.SpanCount(1);
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) ;
sNurbsSurf.bClampedV = onNurbsSurface.IsClamped( 1, 2) ;
sNurbsSurf.bRat = onNurbsSurface.IsRational() ;
sNurbsSurf.nDegU = onNurbsSurface.Degree( 0) ;
sNurbsSurf.nDegV = onNurbsSurface.Degree( 1) ;
sNurbsSurf.nCPU = onNurbsSurface.CVCount( 0) ;
sNurbsSurf.nCPV = onNurbsSurface.CVCount( 1) ;
vector<Point3d> 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]) ;
Frame3d frPlane ;
frPlane.Set( ptOrig, vtX, vtY, vtZ) ;
pt0.ToGlob( frPlane) ;
pt1.ToGlob( frPlane) ;
pt2.ToGlob( frPlane) ;
pt3.ToGlob( frPlane) ;
// costruisco la figura e la inserisco nel GDB
PolyLine PL ;
PL.AddUPoint( 0, pt0) ;
PL.AddUPoint( 1, pt1) ;
PL.AddUPoint( 2, pt2) ;
PL.AddUPoint( 3, pt3) ;
PL.AddUPoint( 4, pt0) ;
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return nullptr ;
pCrvCompo->FromPolyLine( PL) ;
PtrOwner<ISurfTriMesh> pSurf ( GetSurfTriMeshByFlatContour( Release(pCrvCompo))) ;
if ( IsNull( pSurf) || ! pSurf->IsValid())
return nullptr ;
return Release( pSurf) ;
}
else if ( const ON_RevSurface* onRevSurface = ON_RevSurface::Cast( onSurf)) {
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( ConvertSurface( &onNurbsSurface)) ;
if ( ! IsNull( pSurf) && pSurf->IsValid() && nOk != 0)
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) ;
ON_Curve* onpCrvWest( onSumSurface->IsoCurve(1, onIntDomain0[0])) ;
ON_Curve* onpCrvSouth( onSumSurface->IsoCurve(0, onIntDomain1[0])) ;
ICurve* pCrvWest = ConvertCurve( onpCrvWest) ;
ICurve* pCrvSouth = ConvertCurve( onpCrvSouth) ;
PtrOwner<ISurfTriMesh> pSurfTm ( GetSurfTriMeshSwept( pCrvSouth, pCrvWest, 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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
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 {
// se non è riuscita la conversione in nurbs tengo la superficie originale
const ON_Surface* onSurfFace = onBrepFace->ProxySurface() ;
ISurf* pSurfBrep = ConvertSurface( onSurfFace) ;
pSurf.Set( pSurfBrep) ;
}
}
else if ( const ON_OffsetSurface* onOffsetSurface = ON_OffsetSurface::Cast( onSurfaceProxy)) {
//pSurf.Set( ConvertSurface( onOffsetSurface->BaseSurface())) ;
ON_NurbsSurface onNurbsSurface ;
onOffsetSurface->GetNurbForm( onNurbsSurface) ;
pSurf.Set( ConvertSurface( &onNurbsSurface)) ;
}
else
pSurf.Set( ConvertSurface( onSurfaceProxy->DuplicateSurface())) ;
return Release( pSurf) ;
}
return nullptr ;
}
//----------------------------------------------------------------------------
ISURFPVECTOR
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
ISURFPVECTOR vSurf ;
int nFaces = onBrep->m_F.Count() ;
StmFromTriangleSoup stmSoup ;
if ( ! stmSoup.Start())
return vSurf ;
bool bSurfTm = false ;
int nFailedBFace = 0, nFailedTm = 0, nFailedFr = 0, nFailedBz = 0 ;
for ( int i = 0 ; i < nFaces ; ++i) {
ON_BrepFace* onFace = onBrep->Face( i) ;
const ON_Surface* onSurface = onFace->SurfaceOf() ;
PtrOwner<ISurf> pSurf ;
if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurface) ) {
SurfFlatRegionByContours SfrCntr ;
int nLoops = onFace->LoopCount() ;
for ( int k = 0 ; k < nLoops ; ++k) {
ICurve* pCurve = ConvertBrepLoop( onFace->Loop( k)) ;
SfrCntr.AddCurve( pCurve) ;
}
ISurfFlatRegion* sfrTrim = SfrCntr.GetSurf() ;
// porto le coordinate dal riferimento del piano di trim alle coordinate globali
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()) ;
Frame3d frPlane ;
frPlane.Set( ptOrig, vtX, vtY, vtZ) ;
sfrTrim->ToGlob( frPlane) ;
pSurf.Set( sfrTrim) ;
}
else {
pSurf.Set( ConvertSurface( onFace)) ;
}
if ( IsNull(pSurf) || ! pSurf->IsValid()) {
++nFailedBFace ;
return vSurf ;
}
// 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())
stmSoup.AddSurfTriMesh( *Release( pSurfTm)) ;
else {
++nFailedTm ;
}
}
else if ( nType == SRF_FLATRGN)
{
bSurfTm = true ;
PtrOwner<ISurfFlatRegion> pSurfFr ( GetSurfFlatRegion(pSurf)) ;
if ( ! IsNull( pSurfFr) && pSurfFr->IsValid())
stmSoup.AddSurfTriMesh( *Release( pSurfFr)->GetAuxSurf()) ;
else {
++nFailedFr ;
}
}
else if ( nType == SRF_BEZIER ) {
PtrOwner<ISurfBezier> pSurfBezNew ( GetSurfBezier( Release( pSurf))) ;
// se ho più di un loop vuol dire che ho dei trim sulla faccia e quindi li aggiungo alla superficie di bezier
// prima della triangolazione
if ( ! IsNull( pSurfBezNew) && pSurfBezNew->IsValid()) {
if ( onFace->LoopCount() > 1 || 1) {
ON_BrepFace* onFace = onBrep->Face( i) ;
SurfFlatRegionByContours SfrCntr ;
for ( int k = 0 ; k < onFace->LoopCount() ; ++k ) {
ICurve* pCurve = ConvertBrepLoop( onFace->Loop( k)) ;
SfrCntr.AddCurve( pCurve) ;
}
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 ;
double dScaleV = v1 - v0 ;
Vector3d vToOrig( -u0, -v0, 0) ;
sfrTrim->Translate( vToOrig) ;
// 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
PtrOwner<ISurfFlatRegion> pSurfParam( GetSurfFlatRegionRectangle( dScaleU - EPS_SMALL, dScaleV - EPS_SMALL)) ;
pSurfParam->Subtract( *sfrTrim) ;
if ( pSurfParam->IsValid())
MakeUniform( &sfrTrim, onNurbsSurface, dScaleU, dScaleV) ;
else
sfrTrim->Scale( GLOB_FRM, nSpanU * SBZ_TREG_COEFF / dScaleU, nSpanV * SBZ_TREG_COEFF / dScaleV, 1) ;
pSurfBezNew->SetTrimRegion( *sfrTrim) ;
}
if ( ! bForceTriMesh)
vSurf.push_back( Release( pSurfBezNew)) ;
else
stmSoup.AddSurfTriMesh( *(Release( pSurfBezNew)->GetAuxSurf())) ;
}
else {
++nFailedBz ;
}
}
}
if ( nFailedBFace != 0 ) {
string sOut = "Non è riuscita la conversione di " + to_string( nFailedBFace) + " superfici appartenenti ad una Brep" ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
if ( nFailedTm != 0 ) {
string sOut = "Non è riuscita la conversione di " + to_string( nFailedTm) + " superfici trimesh appartenenti ad una Brep" ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
if ( nFailedFr != 0 ) {
string sOut = "Non è riuscita la conversione di " + to_string( nFailedFr) + " superfici FlatRegion appartenenti ad una Brep" ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
if ( nFailedBz != 0 ) {
string sOut = "Non è riuscita la conversione di " + to_string( nFailedBz) + " superfici NURBS appartenenti ad una Brep" ;
LOG_ERROR( GetEExLogger(), sOut.c_str()) ;
}
if ( ! stmSoup.End())
return vSurf ;
if ( bSurfTm || bForceTriMesh)
vSurf.push_back( GetSurfTriMesh( stmSoup.GetSurf())) ;
return vSurf ;
}
//----------------------------------------------------------------------------
bool
Import3dm::MakeUniform( ISurfFlatRegion** sfr, ON_NurbsSurface onNurbsSurface, double& dScaleU, double& dScaleV)
{
// riscalo le superfici prima di effettuare una serie di operazioni di collage
(*sfr)->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ;
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) ;
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())
*sfr = Release( sfr_rescaled) ;
}
else
dScaleV = (int)vU.size() - 1 ;
}
}
if ( ! IsNull( sfr_rescaled) && sfr_rescaled->IsValid())
*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) ;
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);
pCrvCompo->AddCurve( ConvertCurve( onCurveProxy)) ;
}
return Release( pCrvCompo) ;
}