//---------------------------------------------------------------------------- // 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 ( 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 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 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 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 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 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 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 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 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 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 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 pCurveToAdd( vCrvProfile[i]) ; if ( IsNull( pCurveToAdd) || ! pCurveToAdd->IsValid()) { error_count["extrusion"] += 1 ; break ; } stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( Release( pCurveToAdd), vDir, false)) ; } if ( nIsCapped == 1) { PtrOwner 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 pSurfBz( CreateSurfBezier()) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) return false ; PtrOwner 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 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 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 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 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 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 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 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 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 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 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 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::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 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 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 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 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 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 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 pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return nullptr ; pCrvCompo->FromPolyLine( PL) ; PtrOwner 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 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 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 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 onpCrvEast( onSumSurface->IsoCurve(1, onIntDomain0[1])) ; PtrOwner onpCrvNorth( onSumSurface->IsoCurve(0, onIntDomain1[1])) ; // da implementare //////////////////////////////////////////////////////////////////////////////////////////////////////////// } else if ( const ON_SurfaceProxy* onSurfaceProxy = ON_SurfaceProxy::Cast( onSurf)) { PtrOwner 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 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 pSurfTm ( GetSurfTriMesh( Release( pSurf))) ; if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) stmSoup.AddSurfTriMesh( *Release( pSurfTm)) ; else { ++nFailedTm ; } } else if ( nType == SRF_FLATRGN) { bSurfTm = true ; PtrOwner pSurfFr ( GetSurfFlatRegion(pSurf)) ; if ( ! IsNull( pSurfFr) && pSurfFr->IsValid()) stmSoup.AddSurfTriMesh( *Release( pSurfFr)->GetAuxSurf()) ; else { ++nFailedFr ; } } else if ( nType == SRF_BEZIER ) { PtrOwner 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 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 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 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 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 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) ; }