//---------------------------------------------------------------------------- // 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 "C:/EgtDev/opennurbs/opennurbs.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) { // 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 ; // scorro l'archivio fino ad arrivare agli elementi geometrici //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V6\\my_points.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V6\\my_curves.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_my_surfaces.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V6\\my_surfaces.3dm" ; // file vuoto!!!!!!!!!!!!!! //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_rhino_logo_subd.3dm" ; // non si convertono e non le gestiamo //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_my_mesh.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_my_mesh_with_material.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_my_brep.3dm" ; // ok //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V5\\v5_example_file.3dm" ; //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V5\\v5_rhino_logo.3dm" ; //std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V7\\v7_rhino_logo_nurbs.3dm" ; std::string sFile = "C:\\EgtDev\\opennurbs\\example_files\\V5\\v5_my_trimmed_surface.3dm" ; 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 ) ; // conto il numero di layer e li creo //model.Internal_ComponentListConst(ON_ModelComponent::Type::Layer).m_count ON_ModelComponent::Type component_type_l = ON_ModelComponent::Type::Layer ; ONX_ModelComponentIterator component_iterator_l ( model, ON_ModelComponent::Type::Layer) ; int nLayer = 0 ; m_pGDB->Erase( 2) ; for( const ON_ModelComponent* mc = component_iterator_l.FirstComponent() ; nullptr != mc ; mc = component_iterator_l.NextComponent()) { ++nLayer ; m_pGDB->AddGroup( GDB_ID_NULL, 1, GLOB_FRM) ; } ON_ModelComponent::Type component_type = ON_ModelComponent::Type::ModelGeometry ; 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, nCount = 0 ; 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 = 2 ; else nLayer = nLayer + 2 ; // recupero il colore dell'oggetto Color cCol ; ON_Color onCol = attributes->m_color ; //cCol.Set( onCol.Red(), onCol.Green(), onCol.Blue(), int(onCol.Alpha()/2.55)) ; cCol.Set( onCol.Red(), onCol.Green(), onCol.Blue(), 100) ; // converto l'oggetto e lo aggiungo al GeomDB ON::object_type type = oGeometry->ObjectType() ; ++nCount ; 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) ; 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, nLayer, 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, nLayer, 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())) ; //int nProfiles = onExtrusion->ProfileCount() ; 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 /2: top cap /3: both ends capped. PtrOwner pSurfTm( CreateSurfTriMesh()) ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) return nullptr ; if ( IsNull(pSurfTm) ) { error_count["memory"] += 1 ; break ; } // 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) ; 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)) ; 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]) ; stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( Release( pCurveToAdd), vDir, false)) ; } if ( nIsCapped == 1) { stmSoup.AddSurfTriMesh( *GetSurfTriMeshByRegion( vCrvProfile)) ; } else if ( nIsCapped == 2 ) { PtrOwner pSurfTmCap( GetSurfTriMeshByRegion( vCrvProfile)) ; pSurfTmCap->Translate(vDir) ; stmSoup.AddSurfTriMesh( *Release(pSurfTmCap)) ; } } } if ( ! stmSoup.End()) return nullptr ; if ( nIsCapped == 1 || nIsCapped == 2) 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()) ; PtrOwner pSurfTm( CreateSurfTriMesh()) ; 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( static_cast( 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( static_cast(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( static_cast( 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()) ; double x = onMesh->m_V.At( 0)->x ; 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 nFaces = onMesh->FaceCount() ; int nQuads = onMesh->QuadCount() ; //int nTrias = onMesh->TriangleCount(); //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() ; //nQuads = onMeshToConvert->QuadCount() ; int nTrias = onMeshToConvert->TriangleCount(); 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: { const ON_SubD* onSubD = ON_SubD::Cast( oGeometry) ; // non c'è un comando per convertire le subd in altre superfici... //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: { const ON_Annotation* onAnnot = ON_Annotation::Cast( oGeometry) ; ON_wString wsText = onAnnot->PlainText() ; const wchar_t* wchar = wsText ; std::wstring ws( wchar) ; std::string str( ws.begin(), ws.end()) ; LOG_ERROR( GetEExLogger(), str.c_str()) ; break ; } default : break ; } //if ( nCount > 19) // 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 ConvertVector( const ON_3dVector& onVector) { Vector3d vt ; vt.x = onVector.x ; vt.y = onVector.y ; vt.z = onVector.z ; 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) ; 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 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() ; ICurveArc* pCurveArc( CreateCurveArc()) ; pCurveArc->Set( ptCenter, vtN, dRad) ; return 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)) ; ICurveLine* pCurveLine ( CreateCurveLine()) ; pCurveLine->Set( ptStart, ptEnd) ; return 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) ; 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 nKnot = onNurbsCurve->Knot( j) ; vU.push_back( nKnot) ; } nuCurve.vU = vU ; nuCurve.bClosed = onNurbsCurve->IsClosed() ; // dovrei aggiungere la gestione delle curve periodiche ( unclamped) in modo da poter importare anche le curve chiuse nuCurve.bPeriodic = onNurbsCurve->IsPeriodic() ; // 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 if ( nU == int( nuCurve.vU.size()) + 2) 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* onPolyline = ON_PolyCurve::Cast( onCurve) ; int nCurves = onPolyline->Count() ; ICurveComposite* pCrvCompo( CreateCurveComposite()) ; for ( int i = 0 ; i < nCurves; ++i) { ICurve* pCurveToAdd = nullptr ; ON_Curve* onCurveToAdd = onPolyline->SegmentCurve( i) ; pCurveToAdd = ConvertCurve( onCurveToAdd) ; pCrvCompo->AddCurve( pCurveToAdd) ; } return pCrvCompo ; break ; } case ON::eCurveType::ctPolyline : { const ON_PolylineCurve* onPolyline = ON_PolylineCurve::Cast( onCurve) ; int nPoints = onPolyline->PointCount() ; 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) ; ptNew = ptOld ; } return pCrvCompo ; break ; } default : break ; } return nullptr ; } //---------------------------------------------------------------------------- ISurf* Import3dm::ConvertSurface( const ON_Surface* onSurf) { if ( const ON_NurbsSurface* onNurbsSurface = ON_NurbsSurface::Cast( onSurf)) { CNurbsSurfData cNurbsSurf ; cNurbsSurf.bClosedU = onNurbsSurface->IsClosed( 0) ; cNurbsSurf.bClosedV = onNurbsSurface->IsClosed( 1) ; cNurbsSurf.bPeriodicU = onNurbsSurface->IsPeriodic( 0) ; cNurbsSurf.bPeriodicV = onNurbsSurface->IsPeriodic( 1) ; cNurbsSurf.bRat = onNurbsSurface->IsRational() ; cNurbsSurf.nDegU = onNurbsSurface->Degree( 0) ; cNurbsSurf.nDegV = onNurbsSurface->Degree( 1) ; cNurbsSurf.nCPU = onNurbsSurface->CVCount( 0) ; cNurbsSurf.nCPV = onNurbsSurface->CVCount( 1) ; vector vCPV( cNurbsSurf.nCPV) ; cNurbsSurf.mCP.resize( cNurbsSurf.nCPU, vCPV) ; DBLVECTOR vWV( cNurbsSurf.nCPV) ; cNurbsSurf.mW.resize( cNurbsSurf.nCPU, vWV) ; for ( int i = 0 ; i < cNurbsSurf.nCPU ; ++i) { for ( int j = 0 ; j < cNurbsSurf.nCPV ; ++j) { ON_4dPoint o4dPoint = onNurbsSurface->ControlPoint(i, j) ; cNurbsSurf.mCP[i][j] = ConvertPoint( o4dPoint) ; cNurbsSurf.mW[i][j] = o4dPoint.w ; } } for ( int i = 0 ; i < onNurbsSurface->KnotCount(0) ; ++i ) { cNurbsSurf.vU.push_back( onNurbsSurface->Knot( 0, i)) ; } for ( int j = 0 ; j < onNurbsSurface->KnotCount(1) ; ++j ) { cNurbsSurf.vV.push_back( onNurbsSurface->Knot( 1, j)) ; } return NurbsToBezierSurface( cNurbsSurf) ; } 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 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, 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()) ; pCrvCompo->FromPolyLine( PL) ; PtrOwner pSurf ( GetSurfTriMeshByFlatContour( Release(pCrvCompo))) ; 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()) ; // 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)) { ON_NurbsSurface onNurbsSurface ; // prima di usare la nurbs form tento di costruire la superficie con una rail ( funzione seguente) //GetSurfTriMeshSwept int bOk = onSumSurface->GetNurbForm( onNurbsSurface) ; PtrOwner pSurf( ConvertSurface( &onNurbsSurface)) ; if ( bOk != 0) return Release( pSurf) ; else { // se fallisce questo tentativo di conversione allora recupero le curve e costruisco la superficie di Bezier ON_Interval onIntDomain0 = onSumSurface->Domain(0) ; ON_Interval onIntDomain1 = onSumSurface->Domain(1) ; PtrOwner pCrvWest( onSumSurface->IsoCurve(1, onIntDomain0[0])) ; PtrOwner pCrvEast( onSumSurface->IsoCurve(1, onIntDomain0[1])) ; PtrOwner pCrvNorth( onSumSurface->IsoCurve(0, onIntDomain1[1])) ; PtrOwner pCrvSouth( onSumSurface->IsoCurve(0, onIntDomain1[0])) ; } } else if ( const ON_SurfaceProxy* onSurfaceProxy = ON_SurfaceProxy::Cast( onSurf)) { PtrOwner pSurf ; if ( const ON_BrepFace* onBrepFace = ON_BrepFace::Cast( onSurfaceProxy)) { ON_NurbsSurface onNurbsSurface ; int nOk = onBrepFace->GetNurbForm( onNurbsSurface) ; if ( nOk != 0) pSurf.Set( ConvertSurface( & onNurbsSurface)) ; else return nullptr ; } else if ( const ON_OffsetSurface* onOffsetSurface = ON_OffsetSurface::Cast( onSurfaceProxy)) { pSurf.Set( ConvertSurface( onOffsetSurface->BaseSurface())) ; } 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 ISURFPVECTOR vSurf ; //surfaces int nSurf = onBrep->m_S.Count() ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) return vSurf ; bool bSurfTm = false ; for ( int i = 0 ; i < nSurf ; ++i) { //ON_BrepFace* onBrepFace = onBrep->Face( i) ; //onBrepFace->LoopCount() ; ON_Surface* onSurface = onBrep->m_S[i] ; ON_BrepFace* onFace = onBrep->Face( i) ; int nLoop = onFace->LoopCount() ; static bool bDone = false ; //// da attivare per il debug del file V5/V5_example_file.3dm //if ( ! bDone ) { // // provo a replicare la nurbs a mano per vedere se esce il cerchio // ON_BrepLoop* onLoop0 = onFace->Loop( 0) ; // ON_BrepTrim* onBrepTrim = onLoop0->Trim( 0) ; // ON_CurveProxy* onCurveProxy = ON_CurveProxy::Cast( onBrepTrim); // ON_Curve* onCurve = onCurveProxy->DuplicateCurve() ; // const ON_NurbsCurve* onNurbs = ON_NurbsCurve::Cast( onCurve) ; // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // int nMax = 4 ; // for ( int k = 0 ; k < nMax; ++k) { // ICurveBezier* crvBz( CreateCurveBezier()) ; // crvBz->Init( onNurbs->Degree(), onNurbs->IsRational()); // int nCount = onNurbs->CVCount() ; // if ( onNurbs->IsRational()) { // for( int i = 0 ; i < 3; ++i) { // ON_4dPoint o4dPoint ; // onNurbs->GetCV( i + 2*k, o4dPoint) ; // Point3d ptCtrl( ConvertPoint( o4dPoint)) ; // crvBz->SetControlPoint( i, ptCtrl, o4dPoint.w) ; // } // } // m_pGDB->AddGeoObj(GDB_ID_NULL, 0, crvBz) ; // } // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ICurve* pCurve0 = ConvertBrepLoop( onLoop0) ; // // m_pGDB->AddGeoObj(GDB_ID_NULL, 0, pCurve0) ; // ON_BrepLoop* onLoop1 = onFace->Loop( 1) ; // ICurve* pCurve1 = ConvertBrepLoop( onLoop1) ; // m_pGDB->AddGeoObj(GDB_ID_NULL, 0, pCurve1) ; // bDone = true ; //} PtrOwner pSurf( ConvertSurface( onSurface)) ; if ( IsNull(pSurf)) { string sOut = "Non è riuscita la conversione di " + to_string( nSurf - i) + " superfici appartenenti ad una Brep" ; LOG_ERROR( GetEExLogger(), sOut.c_str()) ; return vSurf ; } // se ho una trimesh la aggiungo, se è una bezier ricavo la trimesh prima di aggiungerla int nType = pSurf->GetType() ; if ( nType == SRF_TRIMESH ) { bSurfTm = true ; PtrOwner pSurfTm ( GetSurfTriMesh( Release( pSurf))) ; if ( ! IsNull( pSurfTm) ) stmSoup.AddSurfTriMesh( *Release( pSurfTm)) ; else { string sOut = "Non è riuscita la conversione di " + to_string( nSurf - i) + " superfici trimesh appartenenti ad una Brep" ; LOG_ERROR( GetEExLogger(), sOut.c_str()) ; return vSurf ; } } 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 ON_BrepFace* onFace = onBrep->Face( i) ; SurfFlatRegionByContours SfrCntr ; if ( onFace->LoopCount() > 1) { for ( int k = 0 ; k < onFace->LoopCount() ; ++k) SfrCntr.AddCurve( ConvertBrepLoop( onFace->Loop( k))) ; } ISurfFlatRegion* sfrTrim = SfrCntr.GetSurf() ; if ( ! IsNull( pSurfBezNew) ) { // 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) if ( onFace->LoopCount() > 1) pSurfBezNew->SetTrimRegion( *sfrTrim) ; if ( ! bForceTriMesh) vSurf.push_back( Release( pSurfBezNew)) ; else stmSoup.AddSurfTriMesh( *(Release( pSurfBezNew)->GetAuxSurf())) ; } else { string sOut = "Non è riuscita la conversione di " + to_string( nSurf - i) + " superfici NURBS appartenenti ad una Brep" ; LOG_ERROR( GetEExLogger(), sOut.c_str()) ; return vSurf ; } } } if ( ! stmSoup.End()) return vSurf ; if ( bSurfTm || bForceTriMesh) vSurf.push_back( GetSurfTriMesh( stmSoup.GetSurf())) ; return vSurf ; } ICurve* Import3dm::ConvertBrepLoop( const ON_BrepLoop* onBrepLoop) { int nTrim = onBrepLoop->TrimCount() ; PtrOwner pCrvCompo( CreateCurveComposite()) ; 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) ; }