//---------------------------------------------------------------------------- // EgalTech 2023 //---------------------------------------------------------------------------- // File : Import3dm.cpp Data : 23.06.23 Versione : 2.5f1 // Contenuto : Implementazione della classe per l'importazione di 3dm. // // // // Modifiche : 23.06.23 DB Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "Import3dm.h" #include "DllMain.h" #include "/EgtDev/Include/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/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EGkSurfBezier.h" #include "/EgtDev/Include/EGkSurfAux.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkExtDimension.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EgtStringConverter.h" #include "/EgtDev/Include/EgtKeyCodes.h" #include "/EgtDev/Include/EGkSbzFromCurves.h" //#include "/EgtDev/Include/EgtPerfCounter.h" #define SAVEREVOLVECURVE 0 #define SAVEREVOLVESURF 0 #define SAVEREVOLVETRIM 0 #define SAVETRIMLOOP 0 #if SAVEREVOLVECURVE || SAVEREVOLVESURF || SAVEREVOLVETRIM || SAVETRIMLOOP #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EGkGeoObjSave.h" #endif using namespace std ; ////---------------------------------------------------------------------------- // deviazione angolare standard (in gradi) const double ANG_TOL_FINE = 1 ; // tolleranza lineare affinata const double LIN_TOL_FINE = 0.002 ; const double LIN_TOL_STD = 0.05 ; //---------------------------------------------------------------------------- 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) ; } //---------------------------------------------------------------------------- string Import3dm::ConvertONwStringToString( ON_wString ON_wString) { return wstringtoA( wstring( ON_wString)) ; } int ON_nEntity = 0 ; //---------------------------------------------------------------------------- bool Import3dm::Import( const string& sFile, IGeomDB* pGDB, int nIdGroup, double dTextHeight, double dExtLine, double dArrLen, double dTextDist, bool bLenIsMM, int nDecDig, std::string sFont) { // verifico il DB geometrico if ( pGDB == nullptr) { LOG_ERROR( GetEE3Logger(), "Import3dm : Error on GeomDB") return false ; } m_pGDB = pGDB ; m_dTextHeight = dTextHeight ; m_dExtLine = dExtLine ; m_dArrLen = dArrLen ; m_dTextDist = dTextDist ; m_bLenIsMM = bLenIsMM ; m_nDecDig = nDecDig ; m_sFont = sFont ; // verifico l'Id di gruppo if ( ! m_pGDB->ExistsObj( nIdGroup)) { LOG_ERROR( GetEE3Logger(), "Import3dm : Error on IdGroup") return false ; } m_nIdGroup = nIdGroup ; wstring widestr( sFile.begin(), sFile.end()) ; const wchar_t* sFileName = widestr.c_str() ; FILE* archive_fp = ON::OpenFile( sFileName, L"rb") ; if ( ! archive_fp) { LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to open file.") ; return false ; } // create achive object from file pointer ON_BinaryFile archive( ON::archive_mode::read3dm, archive_fp) ; // read the contents of the file into "model" ON_TextLog dump ; bool rc = m_model.Read( archive, &dump) ; if ( ! rc) LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to read file.") ; // close the file ON::CloseFile( archive_fp) ; // LAYER // creo i layer e i conto ONX_ModelComponentIterator component_iterator_l( m_model, ON_ModelComponent::Type::Layer) ; int nFirstId = 0 ; ON_UUID ON_nil_uuid = { 0,0,0,{ 0,0,0,0,0,0,0,0}} ; //int nLayDelCount = 0 ; //serve solo se si vogliono cancellare i layer parent. Se però questi layer contengono oggetti, che non sono in sottolayer del parent, non verranno visualizzati for ( const ON_ModelComponent* mc = component_iterator_l.FirstComponent() ; mc != nullptr ; mc = component_iterator_l.NextComponent()) { ON_UUID uuid = mc->Id() ; const ON_Layer* onLayer = ON_Layer::Cast( mc) ; ON_UUID uuidParent = onLayer->ParentId() ; // cerco se il parent è un layer già aggiunto auto it = std::find_if( m_mLayer.begin(), m_mLayer.end(), [uuidParent](pair< int, tuple> x){ return !ON_UuidCompare( get<1>(get<1>(x)), uuidParent) ;}); // ON_UuidCompare restituisce 0 se coincidono int nParentL1 = -1 ; // risalgo la gerarchia dei layer finché arrivo al primo layer e aggiungo tutti i nomi al nome del sottolayer string sName = ConvertONwStringToString( onLayer->Name()) ; bool bIsVisible = onLayer->IsVisible() ; while ( ON_UuidCompare( uuidParent, ON_nil_uuid) ) {// ON_UuidCompare restituisce 0 se coincidono const ON_Layer* onParentLayer = get<0>(it->second) ; string sParentName = ConvertONwStringToString( onParentLayer->Name()) ; // se sono ad una profondità maggiore di 1 aggiungo il nome del parent if ( get<3>(it->second) > 1) sName = sParentName + "_" + sName ; uuidParent = onParentLayer->ParentId() ; // salvo l'id del parent che è al livello 1 ( che è un Part) if ( get<3>( it->second) == 1) nParentL1 = it->first ; it = std::find_if( m_mLayer.begin(), m_mLayer.end(), [uuidParent](pair< int, tuple> x){ return !ON_UuidCompare( get<1>(get<1>(x)), uuidParent) ;}); } // COMMENTO QUESTO TRATTO PERCHé, LASCIO I LAYER PARENT E LI CANCELLO ALLA FINE DELL'IMPORT SOLO SE RESTANO VUOTI // //// se era già stato aggiunto il parent e non era già indicata la presenza di sottolayer //// devo eliminare il parent e mettere a true il flag dei sottolayer nella mappa dei layer // if ( it_parent != m_mLayer.end() ) { // if ( !get<3>(it_parent->second) ) { // get<3>(it_parent->second) = true ; // m_pGDB->Erase( it_parent->first) ; // auto LayerDeleted = m_mLayer.extract(it_parent->first); // LayerDeleted.key() = nLayDelCount ; // -- nLayDelCount ; // m_mLayer.insert(std::move(LayerDeleted)); // } // } int nDepth = 2 ; if ( nParentL1 == GDB_ID_NULL) { nParentL1 = GDB_ID_ROOT ; nDepth = 1 ; } int nIdLayer = m_pGDB->AddGroup( GDB_ID_NULL, nParentL1 , GLOB_FRM) ; if ( nFirstId == 0) nFirstId = nIdLayer ; int nIndex = onLayer->Index() ; m_mLayer.insert( std::make_pair( nIdLayer, std::make_tuple(onLayer, uuid, nIndex, nDepth, -1))) ; m_pGDB->SetName( nIdLayer, sName) ; if( ! bIsVisible) m_pGDB->SetStatus( nIdLayer, GDB_ST_OFF) ; } // OGGETTI GEOMETRICI ONX_ModelComponentIterator component_iterator( m_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 ON_nEntity = 0 ; int nId ; for( const ON_ModelComponent* mc = component_iterator.FirstComponent() ; mc != nullptr ; mc = component_iterator.NextComponent()) { const ON_ModelGeometryComponent* mgc = ON_ModelGeometryComponent::Cast( mc) ; ON_wString onwStrName ; mgc->GetName( onwStrName) ; string sObjName = ConvertONwStringToString( onwStrName) ; 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 ; bool bIsObjectVisibile = attributes->IsVisible() ; ON::object_mode onMode = attributes->Mode() ; if ( onMode == ON::object_mode::idef_object) { ++ ON_nEntity ; continue ; } // verifico se un oggetto è una instance definition bool bIsInstanceDefinitionObject = attributes->IsInstanceDefinitionObject() ; if ( bIsInstanceDefinitionObject){ ++ ON_nEntity ; continue ; } if ( nLayer < 0) nLayer = m_pGDB->GetFirstInGroup( 0) ; else { // prendo l'indice che il layer ha nel nostro GDB auto it = std::find_if(m_mLayer.begin(), m_mLayer.end(), [nLayer](pair< int, tuple> x){ return get<2>(get<1>(x)) == nLayer ;}); nLayer = it->first ; } // recupero il colore dell'oggetto ON_Color onCol ; switch ( attributes->ColorSource()) { case ON::color_from_parent: // come se fosse from_layer case ON::color_from_layer : { onCol = get<0>(m_mLayer[nLayer])->Color() ; break ; } case ON::color_from_object: { onCol = attributes->m_color ; break ; } case ON::color_from_material: { // non gestito break ; } } Color cCol ; // N.B. RHINO ha i valori di Alpha invertiti rispetto ai nostri, oltre che su una scala diversa! per loro 0 = opaco e 255 = trasparente // per noi invece 0 = trasparente, 100 = opaco cCol.Set( onCol.Red(), onCol.Green(), onCol.Blue(), lround( ( 255 - onCol.Alpha()) / 2.55)) ; // converto l'oggetto e lo aggiungo al GeomDB vector> vpGeoObj ; ConvertGeometry( oGeometry, vpGeoObj) ; int nSubLayer = -1 ; // se il layer in cui dovrei mettere l'oggetto è in realtà un part allora creo un layer ausiliario in cui metter gli oggetti che dovrebbero stare in questo part if ( get<3>(m_mLayer[nLayer]) == 1) { if ( get<4>(m_mLayer[nLayer]) == -1) { int nAuxLayer = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, GLOB_FRM) ; get<4>(m_mLayer[nLayer]) = nAuxLayer ; } // recupero l'id del layer ausiliario nLayer = get<4>(m_mLayer[nLayer]) ; } // se ho più oggetti da inserire creo un subLayer if ( ssize( vpGeoObj) > 1) { int nParent = m_pGDB->GetParentId( nLayer) ; nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nParent, GLOB_FRM) ; string sSubName ; m_pGDB->GetName( nSubLayer, sSubName) ; if ( sSubName == "") sSubName = "Layer " + ToString(nSubLayer) ; string sName ; m_pGDB->GetName( nLayer, sName) ; if ( sName == "") sName = "Layer " + ToString(nLayer) ; sSubName = sName + "_" + sSubName ; m_pGDB->SetName( nSubLayer, sSubName) ; } else nSubLayer = nLayer ; // recupero eventuali informazioni dell'oggetto ON_ClassArray onvUserString ; const ON_3dmObjectAttributes* model_geometry_attributes = mgc->Attributes( nullptr) ; int nInfo = model_geometry_attributes->GetUserStrings( onvUserString) ; for ( int p = 0 ; p < ssize( vpGeoObj) ; ++p) { if ( ! IsNull( vpGeoObj[p]) && vpGeoObj[p]->IsValid()) { nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nSubLayer, Release( vpGeoObj[p])) ; m_pGDB->SetMaterial( nId, cCol) ; for ( int i = 0 ; i < nInfo ; ++i) { m_pGDB->SetInfo( nId, ConvertONwStringToString( onvUserString[i].m_key), ConvertONwStringToString( onvUserString[i].m_string_value)) ; } m_pGDB->SetName( nId, sObjName) ; GdbStatus status = bIsObjectVisibile ? GDB_ST_ON : GDB_ST_OFF ; m_pGDB->SetStatus( nId, status) ; ////debug //m_pGDB->SetInfo( nId, "3dmId", ToString(ON_nEntity)) ; } } ++ ON_nEntity ; } // CANCELLO I LAYER RIMASTI VUOTI ?? // messaggio di errore da mettere nel log per dire quanti oggetti sono stati ignorati perché la conversione non è riuscita map::iterator it = m_mError_count.begin() ; while (it != m_mError_count.end()) { string type = it->first ; int count = it->second ; string sOut = "Import3dm : " + to_string( count) + " " + type + " objects have been ignored, due to conversion errors" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; it++; } return true ; } //---------------------------------------------------------------------------- bool Import3dm::ConvertGeometry( const ON_Object* oGeometry, vector>& vpGeoObj) { 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()) ; if ( ! IsNull( pGeoPnt) && pGeoPnt->Set( pt) && pGeoPnt->IsValid()) vpGeoObj.emplace_back( Release( pGeoPnt)) ; else m_mError_count["point"] += 1 ; break ; } case ON::object_type::pointset_object : { const ON_PointCloud* pc = ON_PointCloud::Cast( oGeometry); if ( pc == nullptr) { m_mError_count["pointset"] += 1 ; break ; } for ( int i = 0 ; i < pc->PointCount() ; i++) { Point3d pt( ConvertPoint( pc->m_P[i])) ; // lo aggiungo al GeomDB nel layer corretto PtrOwner pGeoPnt( CreateGeoPoint3d()) ; if ( ! IsNull( pGeoPnt) && pGeoPnt->Set( pt) && pGeoPnt->IsValid()) vpGeoObj.emplace_back( Release(pGeoPnt)) ; else m_mError_count["point"] += 1 ; } break ; } case ON::object_type::curve_object : { const ON_Curve* onCurve = ON_Curve::Cast( oGeometry) ; PtrOwner pCurve( ConvertCurve( onCurve)) ; if ( ! IsNull( pCurve) && pCurve->IsValid()) vpGeoObj.emplace_back( Release( pCurve)) ; else m_mError_count["curve"] += 1 ; break ; } case ON::object_type::surface_object : { const ON_Surface* onSurface = ON_Surface::Cast( oGeometry) ; PtrOwner pSurf( ConvertSurface( onSurface)) ; if ( ! IsNull( pSurf) && pSurf->IsValid()) vpGeoObj.emplace_back( Release( pSurf)) ; else m_mError_count["surface"] += 1 ; break ; } case ON::object_type::brep_object : { const ON_Brep* onBrep = ON_Brep::Cast( oGeometry) ; ISURFPOVECTOR vpSurf = ConvertBrep( onBrep, false) ; for ( int k = 0 ; k < int( vpSurf.size()) ; ++ k) { PtrOwner pSurf( GetSurf( Release( vpSurf[k]))) ; if ( ! IsNull( pSurf) && pSurf->IsValid()) vpGeoObj.emplace_back( Release( pSurf)) ; else m_mError_count["brep"] += 1 ; } break ; } case ON::object_type::extrusion_object : { const ON_Extrusion* onExtrusion = ON_Extrusion::Cast( oGeometry) ; ISURFPOVECTOR vpSurf = ConvertExtrusion( onExtrusion) ; for ( int k = 0 ; k < int( vpSurf.size()) ; ++ k) { PtrOwner pSurf( GetSurf( Release( vpSurf[k]))) ; if ( ! IsNull( pSurf) && pSurf->IsValid()) vpGeoObj.emplace_back( Release( pSurf)) ; else m_mError_count["extrusion"] += 1 ; } break ; } case ON::object_type::mesh_object :{ const ON_Mesh* onMesh = ON_Mesh::Cast( oGeometry) ; PtrOwner pSurfTm( ConvertMesh( onMesh)) ; if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) vpGeoObj.emplace_back( Release( pSurfTm)) ; else m_mError_count["mesh"] += 1 ; break ; } case ON::object_type::loop_object : {// some type of ON_BrepLoop // in teoria non dovrei mai trovare questo tipo di oggetti come model geometry indipendenti, ma solo come parte di una brep const ON_BrepLoop* onBrepLoop = ON_BrepLoop::Cast( oGeometry) ; PtrOwner pCurve( ConvertBrepLoop( onBrepLoop)) ; if ( ! IsNull( pCurve) && pCurve->IsValid()) vpGeoObj.emplace_back( Release( pCurve)) ; else m_mError_count["loop"] += 1 ; break ; } case ON::object_type::subd_object: { // non c'è un comando per convertire le subd in altre superfici... m_mError_count["subd"] += 1 ; break ; } case ON::object_type::annotation_object: { const ON_Annotation* onAnnot = ON_Annotation::Cast( oGeometry) ; // recupero il DimStyle onAnnot->DimensionStyleId() ; ON_UUID onStyleId = onAnnot->DimensionStyleId() ; ON_ModelComponentReference mcr = m_model.ComponentFromId( ON_ModelComponent::Type::DimStyle, onStyleId) ; const ON_ModelComponent* mc = mcr.ModelComponent() ; const ON_DimStyle* onDimStyle = ON_DimStyle::Cast( mc) ; // converto l'oggetto vpGeoObj = ConvertAnnotation( onAnnot, onDimStyle) ; break ; } // TO DO // oggetto che definisce la zona dell'anteprima di stampa // degli oggetti potrebbero essere definiti rispetto a questo frame // //case ON::object_type::detail_object: { // const ON_DetailView* onDetail = ON_DetailView::Cast( oGeometry) ; // ON_NurbsCurve onBoundary = onDetail->m_boundary ; // ICurve* pCrv = ConvertCurve( &onBoundary) ; // ON_3dmView onView = onDetail->m_view ; // ON::view_type onViewType = onView.m_view_type ; // error_count["detail"] += 1 ; //} case ON::object_type::instance_definition: { string sOut = "instance_definition: object " + ToString( ON_nEntity) ; LOG_INFO( GetEE3Logger(), sOut.c_str()) ; break ; } case ON::object_type::instance_reference : { string sOut = "instance_reference: object " + ToString( ON_nEntity) ; LOG_INFO( GetEE3Logger(), sOut.c_str()) ; const ON_InstanceRef* onInstRef = ON_InstanceRef::Cast( oGeometry) ; ON_Xform xform = ON_Xform::DiagonalTransformation( 1) ; // trasformazione identità ConvertInstanceReference( onInstRef, xform, vpGeoObj) ; break ; } default: { m_mError_count["other"] += 1 ; break ; } } return true ; } //---------------------------------------------------------------------------- bool Import3dm::ConvertInstanceReference( const ON_InstanceRef* onInstRef, const ON_Xform& onXForm, vector>& vpGeoObj) { const ON_ModelComponentReference& idef_component_ref = m_model.ComponentFromId( ON_ModelComponent::Type::InstanceDefinition, onInstRef->m_instance_definition_uuid) ; const ON_InstanceDefinition* onInstDef = ON_InstanceDefinition::Cast( idef_component_ref.ModelComponent()) ; if ( onInstDef) { ON_Xform xform = onXForm * onInstRef->m_xform ; bool bApplyTransform = ( xform.IsValid() && ! xform.IsZero() && ! xform.IsIdentity()) ; const ON_SimpleArray& geometry_id_list = onInstDef->InstanceGeometryIdList() ; const int geometry_id_count = geometry_id_list.Count() ; if ( geometry_id_count > 0) { for ( int i = 0; i < geometry_id_count; i++) { string sOut = "Importing instRef: GeoC = " + ToString( geometry_id_count) + " i = " + ToString( i) ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; const ON_ModelComponentReference& model_component_ref = m_model.ComponentFromId(ON_ModelComponent::Type::ModelGeometry, geometry_id_list[i]) ; const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component_ref.ModelComponent()) ; if ( nullptr != model_geometry) { const ON_Geometry* onGeometry = model_geometry->Geometry(nullptr) ; if ( nullptr != onGeometry) { const ON_InstanceRef* onInstRefNested = ON_InstanceRef::Cast( onGeometry) ; if ( onInstRefNested) { ConvertInstanceReference( onInstRefNested, xform, vpGeoObj) ; } else { // Copy the geometry. Note, we are responsible for the memory allocated here. // So make to dispose of it, otherwise you'll leak memory. ON_Geometry* onGeometryCopy = onGeometry->Duplicate() ; if ( nullptr != onGeometryCopy) { if ( bApplyTransform) onGeometryCopy->Transform( xform) ; if ( ! ConvertGeometry( onGeometryCopy, vpGeoObj)) m_mError_count["instance reference"] += 1 ; delete onGeometryCopy ; } else m_mError_count["instance reference"] += 1 ; //if ( ! ConvertGeometry( onGeometry, vpGeoObj)) // m_mError_count["instance reference"] += 1 ; //if ( bApplyTransform) { // ON_Xform xformInv( xform.m_xform) ; // xformInv.Transpose() ; // Frame3d frLoc ; // Point3d ptOrig (xformInv[0][3], xformInv[1][3], xformInv[2][3]) ; // Vector3d vtX( xformInv[0][0], xformInv[1][0], xformInv[2][0]) ; // Vector3d vtY( xformInv[0][1], xformInv[1][1], xformInv[2][1]) ; // Vector3d vtZ( xformInv[0][2], xformInv[1][2], xformInv[2][2]) ; // frLoc.Set( ptOrig, vtX, vtY, vtZ) ; // frLoc.Invert() ; // for ( IGeoObj* pGeo : vpGeoObj) // pGeo->ToLoc( frLoc) ; //} } } } } } } return true ; } //---------------------------------------------------------------------------- ICurve* Import3dm::ConvertCurve( const ON_Curve* onCurve) { ON::eCurveType curve_type = onCurve->ON_CurveType() ; switch ( curve_type) { case ON::eCurveType::ctArc : { const ON_ArcCurve* onArc = ON_ArcCurve::Cast( onCurve) ; Vector3d vStart = ConvertVector( onArc->TangentAt( 0)) ; Point3d ptCenter( ConvertPoint( onArc->m_arc.plane.origin)) ; Point3d ptStart( ConvertPoint( onArc->m_arc.PointAt( onArc->m_arc.Domain().Min()))) ; Point3d ptEnd( ConvertPoint( onArc->m_arc.PointAt( onArc->m_arc.Domain().Max()))) ; Vector3d vtN = ConvertVector( onArc->m_arc.plane.zaxis) ; PtrOwner pCurveArc( CreateCurveArc()) ; if ( IsNull( pCurveArc)) return nullptr ; if ( ! AreSamePointApprox( ptStart, ptEnd)) { if ( ! pCurveArc->Set2PVN( ptStart, ptEnd, vStart, vtN)) pCurveArc->SetC2PN( ptCenter, ptStart, ptEnd, vtN) ; } else { double dRad = onArc->m_arc.Radius() ; pCurveArc->Set( ptCenter, vtN, dRad) ; } return Release( pCurveArc) ; break ; } case ON::eCurveType::ctCircle : { const ON_ArcCurve* onCircle = ON_ArcCurve::Cast( onCurve) ; Point3d ptCenter( ConvertPoint(onCircle->m_arc.plane.origin)) ; ON_3dVector on_vtN = onCircle->m_arc.plane.zaxis ; Vector3d vtN = ConvertVector( on_vtN) ; double dRad = onCircle->m_arc.Radius() ; PtrOwner 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 ; } // qui aggiungo un controllo se la curva è collassata in un punto restituisco nullptr bool bCollapsed = true ; Point3d ptFirst = nuCurve.vCP.front() ; for( int i = 1 ; i < int( nuCurve.vCP.size()) ; ++i) { if ( ! AreSamePointApprox( ptFirst, nuCurve.vCP[i])) { bCollapsed = false ; break ; } } if ( bCollapsed) return nullptr ; // vettore dei nodi DBLVECTOR vU ; int nKnot = onNurbsCurve->KnotCount() ; for ( int j = 0 ; j < nKnot ; ++j ) { double dKnot = onNurbsCurve->Knot( j) ; vU.push_back( dKnot) ; } nuCurve.vU = vU ; nuCurve.bClosed = onNurbsCurve->IsClosed() ; nuCurve.bPeriodic = onNurbsCurve->IsPeriodic() ; nuCurve.bClamped = onNurbsCurve->IsClamped(2) ; // controllo relazione nodi - punti di controllo int nU = int( nuCurve.vCP.size()) + nuCurve.nDeg - 1 ; // se ho due nodi di troppo mi basta togliere il primo e l'ultimo per rendere la curva canonica // se la curva è periodica posso renderla non periodica senza cambiare la forma della curva if ( nU == int( nuCurve.vU.size()) + 2 || nuCurve.bPeriodic || ! nuCurve.bClamped) NurbsCurveCanonicalize( nuCurve) ; // ora che ho riempito la Nurbs con tutti i dati la converto in Bezier return NurbsToBezierCurve( nuCurve) ; break ; } case ON::eCurveType::ctOnsurface :{ const ON_CurveOnSurface* onCurveOnSurface = ON_CurveOnSurface::Cast( onCurve) ; ON_NurbsCurve onNurbsCurve ; onCurveOnSurface->GetNurbForm( onNurbsCurve) ; return ConvertCurve( &onNurbsCurve) ; break ; } case ON::eCurveType::ctProxy :{ const ON_CurveProxy* onProxyCurve = ON_CurveProxy::Cast( onCurve) ; const ON_Curve* onCurve = onProxyCurve->ProxyCurve() ; return ConvertCurve( onCurve) ; break ; } case ON::eCurveType::ctPolycurve : { const ON_PolyCurve* onPolycurve = ON_PolyCurve::Cast( onCurve) ; int nCurves = onPolycurve->Count() ; PtrOwner 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, DBLVECTOR* vU, DBLVECTOR* vV) { if ( const ON_NurbsSurface* onNurbsSurface_ = ON_NurbsSurface::Cast( onSurf)) { ON_NurbsSurface onNurbsSurface( *onNurbsSurface_) ; SNurbsSurfData sNurbsSurf ; sNurbsSurf.bClosedU = onNurbsSurface.IsClosed( 0) ; sNurbsSurf.bClosedV = onNurbsSurface.IsClosed( 1) ; sNurbsSurf.bPeriodicU = onNurbsSurface.IsPeriodic( 0) ; sNurbsSurf.bPeriodicV = onNurbsSurface.IsPeriodic( 1) ; sNurbsSurf.bClampedU = onNurbsSurface.IsClamped( 0, 2) ; // qui do per scontato che se la curva è clamped alla fine allora lo è anche all'inizio e viceversa sNurbsSurf.bClampedV = onNurbsSurface.IsClamped( 1, 2) ; // qui do per scontato che se la curva è clamped alla fine allora lo è anche all'inizio e viceversa sNurbsSurf.bRat = onNurbsSurface.IsRational() ; sNurbsSurf.nDegU = onNurbsSurface.Degree( 0) ; sNurbsSurf.nDegV = onNurbsSurface.Degree( 1) ; sNurbsSurf.nCPU = onNurbsSurface.CVCount( 0) ; sNurbsSurf.nCPV = onNurbsSurface.CVCount( 1) ; PNTVECTOR vCPV( sNurbsSurf.nCPV) ; sNurbsSurf.mCP.resize( sNurbsSurf.nCPU, vCPV) ; DBLVECTOR vWV( sNurbsSurf.nCPV) ; sNurbsSurf.mW.resize( sNurbsSurf.nCPU, vWV) ; for ( int i = 0 ; i < sNurbsSurf.nCPU ; ++i) { for ( int j = 0 ; j < sNurbsSurf.nCPV ; ++j) { ON_4dPoint o4dPoint = onNurbsSurface.ControlPoint(i, j) ; Point3d ptCP = ConvertPoint( o4dPoint) ; sNurbsSurf.mCP[i][j] = ptCP ; if ( sNurbsSurf.bRat) sNurbsSurf.mCP[i][j] = ptCP / o4dPoint.w ; else sNurbsSurf.mCP[i][j] = ptCP ; sNurbsSurf.mW[i][j] = o4dPoint.w ; } } for ( int i = 0 ; i < onNurbsSurface.KnotCount(0) ; ++i ) sNurbsSurf.vU.push_back( onNurbsSurface.Knot( 0, i)) ; for ( int j = 0 ; j < onNurbsSurface.KnotCount(1) ; ++j ) sNurbsSurf.vV.push_back( onNurbsSurface.Knot( 1, j)) ; if ( sNurbsSurf.bPeriodicU || sNurbsSurf.bPeriodicV || ! sNurbsSurf.bClampedU || ! sNurbsSurf.bClampedV) NurbsSurfaceCanonicalize( sNurbsSurf) ; if ( vU != nullptr) { *vU = sNurbsSurf.vU ; *vV = sNurbsSurf.vV ; } return NurbsToBezierSurface( sNurbsSurf) ; } else if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurf)) { // recupero i riferimenti del piano e li converto in oggetti nostri Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ; Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ; Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ; Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ; ON_Interval on_inX = onPlaneSurface->Extents(0) ; ON_Interval on_inY = onPlaneSurface->Extents(1) ; Point3d pt0( on_inX[0], on_inY[0]) ; Point3d pt1( on_inX[1], on_inY[0]) ; Point3d pt2( on_inX[1], on_inY[1]) ; Point3d pt3( on_inX[0], on_inY[1]) ; // costruisco la figura e la inserisco nel GDB PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return nullptr ; pCrvCompo->AddPoint( pt0) ; pCrvCompo->AddLine( pt1) ; pCrvCompo->AddLine( pt2) ; pCrvCompo->AddLine( pt3) ; pCrvCompo->Close() ; // porto la figura nel frame globale Frame3d frPlane ; frPlane.Set( ptOrig, vtX, vtY, vtZ) ; pCrvCompo->ToGlob( frPlane) ; PtrOwner pSurf( CreateSurfFlatRegion()) ; if ( IsNull( pSurf) || ! pSurf->AddExtLoop( Release( pCrvCompo))) return nullptr ; return Release( pSurf) ; } else if ( const ON_RevSurface* onRevSurface = ON_RevSurface::Cast( onSurf)) { PtrOwner 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 ; // uso la nurbs form per ottenere i vettori ON_NurbsSurface onNurbsSurface ; int nOk = onRevSurface->GetNurbForm( onNurbsSurface) ; if ( nOk != 0) return nullptr ; ConvertSurface( &onNurbsSurface, vU, vV) ; // provo a convertire usando una bezier #if SAVEREVOLVECURVE vector vGeo ; vGeo.push_back( pCurve->Clone()) ; IGeoVector3d* pVec = CreateGeoVector3d() ; pVec->Set( vtDir, ptTo) ; vGeo.push_back( pCurve->Clone()) ; vGeo.push_back( pVec) ; SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\revolve_surf\\crv.nge") ; #endif PtrOwner pSurfBez( GetSurfBezierByRevolve( pCurve, ptFrom, vtDir, false, 0.01)) ; #if SAVEREVOLVECURVE if ( ! IsNull(pSurfBez)) SaveGeoObj( pSurfBez->Clone(), "D:\\Temp\\bezier\\import3dm\\revolve_surf\\srf.nge") ; #endif if ( ! IsNull( pSurfBez) && pSurfBez->IsValid()) return Release( pSurfBez) ; // sennò uso una trimesh 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 ; if ( nOk != 0) pSurf.Set( ConvertSurface( &onNurbsSurface, vU, vV)) ; if ( ! IsNull( pSurf) && pSurf->IsValid()) return Release( pSurf) ; // se non è riuscita la conversione tento di costruire la superficie con una rail ON_Interval onIntDomain0 = onSumSurface->Domain(0) ; ON_Interval onIntDomain1 = onSumSurface->Domain(1) ; // Note carefully: ON_SumSurface::IsoCurve allocates memory // for the output curve. The caller is responsible for // freeing this memory when finished. PtrOwner onpCrvWest( onSumSurface->IsoCurve(1, onIntDomain0[0])) ; PtrOwner onpCrvSouth( onSumSurface->IsoCurve(0, onIntDomain1[0])) ; PtrOwner pCrvWest( ConvertCurve( onpCrvWest)) ; PtrOwner pCrvSouth( ConvertCurve( onpCrvSouth)) ; PtrOwner pSurfTm ( GetSurfTriMeshSwept( pCrvSouth, pCrvWest, V_NULL, false)) ; if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) return Release( pSurfTm) ; // se fallisce questo tentativo di conversione allora recupero le curve e costruisco la superficie di Bezier // in teoria dovrei farcela con uno dei due metodi precedenti PtrOwner onpCrvEast( onSumSurface->IsoCurve(1, onIntDomain0[1])) ; PtrOwner onpCrvNorth( onSumSurface->IsoCurve(0, onIntDomain1[1])) ; // da implementare //////////////////////////////////////////////////////////////////////////////////////////////////////////// return nullptr ; } 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, vU, vV)) ; #if SAVEREVOLVECURVE SaveGeoObj( pSurf->Clone(), "D:\\Temp\\bezier\\import3dm\\revolve_surf\\srf_nurbs.nge") ; #endif } else { // QUI PERò NON TENGO CONTO DEL TRIM!!!!!! // // se non è riuscita la conversione in nurbs tengo la superficie originale const ON_Surface* onSurfFace = onBrepFace->ProxySurface() ; // qui devo applicare a mano le trasformazioni dalla superfice originale alla proxy // la funzione getNurbsForm lo fa in automatico pSurf.Set( ConvertSurface( onSurfFace, vU, vV)) ; LOG_ERROR( GetEE3Logger(), "Import3dm : Importing a surface without its trim, because of conversione errors") ; } ////// questa versione è da usare per usare le superfici proxy anziché la versione nurbs //pSurf.Set( ConvertSurface( onBrepFace->ProxySurface(), vU, vV)) ; } else if ( const ON_OffsetSurface* onOffsetSurface = ON_OffsetSurface::Cast( onSurfaceProxy)) { //pSurf.Set( ConvertSurface( onOffsetSurface->BaseSurface())) ; ON_NurbsSurface onNurbsSurface ; int nOk = onOffsetSurface->GetNurbForm( onNurbsSurface) ; if ( nOk != 0) pSurf.Set( ConvertSurface( &onNurbsSurface, vU, vV)) ; } else pSurf.Set( ConvertSurface( onSurfaceProxy->ProxySurface(), vU, vV)) ; return Release( pSurf) ; } return nullptr ; } #if SAVETRIMLOOP int nLoop = 0 ; #endif //---------------------------------------------------------------------------- ISURFPOVECTOR Import3dm::ConvertBrep( const ON_Brep* onBrep, const bool bForceTriMesh) { // se le facce della Brep sono tutte trimesh restituisco un'unica trimesh // se le facce sono delle NURBS restituisco un vettore di superfici Bezier // se ForceTriMesh è true allora le Bezier vengono trasformate in trimesh e aggiunte alla zuppa int nFailedBFace = 0, nFailedTm = 0, nFailedFr = 0, nFailedBz = 0, nFailedBTrim = 0 ; ISURFPOVECTOR vSurf ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) return vSurf ; int nFaceTot = onBrep->m_F.Count() ; for ( int i = 0 ; i < nFaceTot ; ++i) { ON_BrepFace* onFace = onBrep->Face( i) ; bool bOk = true ; bool bRev = onFace->m_bRev ; const ON_Surface* onSurface = onFace->SurfaceOf() ; PtrOwner pSurf ; bool bTooSmallOnlyLoop = false ; DBLVECTOR vU, vV ; if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurface)) { SurfFlatRegionByContours SfrCntr ; // ricavo il riferimento del piano Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ; Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ; Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ; Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ; Plane3d plane ; plane.Set( ptOrig, vtZ) ; int nLoopCount = onFace->LoopCount() ; for ( int k = 0 ; k < nLoopCount ; ++k) { PtrOwner pCrvCompo( GetCurveComposite(ConvertBrepLoop( onFace->Loop( k)))) ; PolyArc paLoopApprox ; //pCrvCompo->ApproxWithArcs(LIN_TOL_FINE, ANG_TOL_FINE, paLoopApprox) ; // pCrvCompo->Clear() ; // Da provare, senza questa riga non viene modificata la crvCompo //pCrvCompo->FromPolyArc( paLoopApprox) ; pCrvCompo->MergeCurves(LIN_TOL_FINE, ANG_TOL_FINE) ; #if SAVETRIMLOOP SaveGeoObj( pCrvCompo->Clone(), "D:\\Temp\\bezier\\import3dm\\import_trim\\loop" + ToString(k) + ".nge") ; #endif double dArea = 0 ; pCrvCompo->GetArea( plane, dArea) ; if ( nLoopCount == 1 && dArea <= 10 * EPS_SMALL) bTooSmallOnlyLoop = true ; if ( ! SfrCntr.AddCurve( Release( pCrvCompo))) ++ nFailedBTrim ; } pSurf.Set( SfrCntr.GetSurf()) ; if ( ! IsNull( pSurf) && pSurf->IsValid()) { // porto le coordinate dal riferimento del piano di trim alle coordinate globali Frame3d frPlane ; frPlane.Set( ptOrig, vtX, vtY, vtZ) ; pSurf->ToGlob( frPlane) ; } } else pSurf.Set( ConvertSurface( onFace, &vU, &vV)) ; if ( IsNull( pSurf) || ! pSurf->IsValid()) { // se la superficie aveva un solo loop e questo era troppo piccolo allora NON lo segno come errore // semplicmente la superficie non verrà disegnata perché troppo piccola if ( ! bTooSmallOnlyLoop) { ++ nFailedBFace ; } } else { // se ho una trimesh o una flatregion la aggiungo alla zuppa, se è una bezier la aggiungo al vettore delle superfici int nType = pSurf->GetType() ; if ( nType == SRF_TRIMESH) { PtrOwner pSurfTm( GetSurfTriMesh( Release( pSurf))) ; if ( !IsNull(pSurfTm) && pSurfTm->IsValid() ) { if ( bRev) pSurfTm->Invert() ; stmSoup.AddSurfTriMesh( *pSurfTm) ; } else ++ nFailedTm ; } else if ( nType == SRF_FLATRGN) { PtrOwner pSurfFr( GetSurfFlatRegion( Release( pSurf))) ; if ( ! IsNull( pSurfFr) && pSurfFr->IsValid()) { if ( bRev) pSurfFr->Invert() ; stmSoup.AddSurfTriMesh(*pSurfFr->GetAuxSurf()) ; } else ++ nFailedFr ; } else if ( nType == SRF_BEZIER) { PtrOwner pSurfBezNew( GetSurfBezier( Release( pSurf))) ; if ( ! IsNull( pSurfBezNew) && pSurfBezNew->IsValid()) { SurfFlatRegionByContours SfrCntr ; const ON_Surface* onSurface = onFace->SurfaceOf() ; // se la superficie era una superficie di rivoluzione, le eventuali curve di trim erano parametrizzate con la coordinata x in radianti, // e non riferita allo spazio parametrico della nurbs corrispondente ( che sarebbe una nurbs razionale, dovendo approssimare un arco di circonferenza) // devo quindi prelevare le curve di trim e cambiarne le coordinate per matcharle allo spazio parametrico della nurbs bool bAddedLoop = false ; bool bTrimTooSmall = false ; if ( const ON_RevSurface* onRevSurf = ON_RevSurface::Cast( onSurface) ) { for ( int k = 0 ; k < onFace->LoopCount(); ++k ) { ICurve* pCrv( ConvertBrepLoop( onFace->Loop( k))) ; if ( pCrv == nullptr || ! pCrv->IsValid()) { ++ nFailedBTrim ; bOk = false ; break ; } // qui devo spostare ogni punto della curva dallo spazio parametrico della superificie rev allo spazio della superficie nurbs ConvertCurveParam( onRevSurf, &pCrv) ; PtrOwner pCrvCompo( ApproxTrim( pCrv)) ; double dArea = 0 ; pCrvCompo->GetAreaXY(dArea) ; if (abs(dArea) > EPS_SMALL) { pCrvCompo->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ; if ( SfrCntr.AddCurve( Release(pCrvCompo))) bAddedLoop = true ; } else bTrimTooSmall = true ; } if ( ! bOk) continue ; } else { for ( int k = 0 ; k < onFace->LoopCount() && bOk ; ++k ) { PtrOwner pCrv( ConvertBrepLoop( onFace->Loop( k))) ; #if SAVETRIMLOOP SaveGeoObj( pCrv->Clone(), "D:\\Temp\\bezier\\import3dm\\import_trim\\loop" + ToString(nLoop) + ".nge") ; ++nLoop ; #endif if ( IsNull( pCrv) || ! pCrv->IsValid()) { ++ nFailedBTrim ; bOk = false ; break ; } PtrOwner pCrvCompo( ApproxTrim( pCrv)) ; double dArea = 0 ; pCrvCompo->GetAreaXY(dArea) ; if (abs(dArea) > EPS_SMALL) { // qui non sarebbe meglio mettere SQ_EPS_SMALL oppure addirittura EPS_ZERO o 0 ? pCrvCompo->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ; if ( SfrCntr.AddCurve( Release( pCrvCompo))) bAddedLoop = true ; } else { bTrimTooSmall = true ; continue ; } } if ( ! bOk) continue ; } if ( ! bAddedLoop) { if ( ! bTrimTooSmall) ++ nFailedBTrim ; continue ; } ISurfFlatRegion* pSfrTrim = 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) ; vToOrig *= SBZ_TREG_COEFF ; if ( pSfrTrim != nullptr) pSfrTrim->Translate( vToOrig) ; else { ++ nFailedBTrim ; continue ; } int nDegU, nDegV, nSpanU, nSpanV ; bool bRat, bTrim ; pSurfBezNew->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrim) ; pSfrTrim->Scale( GLOB_FRM, nSpanU / dScaleU, nSpanV / dScaleV, 1.) ; // 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 // devo rendere lo spazio parametrico uniforme solo se la superficie è trimmata, sennò non serve // per capire se la superficie sia trimmata controllo che lo spazio parametrico trimmato non coincida con tutto lo spazio parametrico double dParamX = nSpanU * SBZ_TREG_COEFF ; double dParamY = nSpanV * SBZ_TREG_COEFF ; double dAreaTot = dParamX * dParamY ; double dAreaTrim = 0 ; pSfrTrim->GetArea( dAreaTrim) ; if ( dAreaTrim / dAreaTot < 1 - EPS_SMALL) { bool bRescaled = false ; DBLVECTOR vU0 , vV0 ; for ( int i = 0 ; i < ssize(vU) ; ++i) vU0.push_back( vU[i] * nSpanU / dScaleU) ; for ( int j = 0 ; j < ssize(vV) ; ++j) vV0.push_back( vV[j] * nSpanV / dScaleV) ; dScaleU = dParamX ; dScaleV = dParamY ; //if ( ssize( vU0) == 0 || ssize(vV0) == 0 ) { // vU0.clear() ; // vV0.clear() ; // int nU = onFace->SpanCount(0) ; // int nV = onFace->SpanCount(1) ; // double* vdU = new double[nU] ; // double* vdV = new double[nV] ; // onFace->GetSpanVector(0,vdU) ; // onFace->GetSpanVector(1,vdV) ; // for ( int i = 0 ; i < nU ; ++i) // vU0.push_back( vdU[i] * nSpanU / dScaleU) ; // for ( int j = 0 ; j < nV ; ++j) // vV0.push_back( vdV[j] * nSpanU / dScaleU) ; // delete[] vdU ; // delete[] vdV ; // ///////// PER FAR FUNZIONARE LA CANONICALIZE SERVONO ANCHE I PUNTI // // devo solo togliere i nodi di troppo passando il vettore alla nurbsCanonicalize // if ( onFace->IsPeriodic(0)) { // CNurbsData cnU ; // cnU.bPeriodic = true ; // cnU.vU = vU0 ; // NurbsCurveCanonicalize( cnU) ; // vU0 = cnU.vU ; // } // if ( onFace->IsPeriodic(1)) { // CNurbsData cnV ; // cnV.bPeriodic = true ; // cnV.vU = vV0 ; // NurbsCurveCanonicalize( cnV) ; // vV0 = cnV.vU ; // } //} #if SAVEREVOLVETRIM SaveGeoObj( pSfrTrim->Clone(), "D:\\Temp\\bezier\\import3dm\\trim_error\\non_uniform_trim.nge") ; #endif if ( ! MakeUniform( pSfrTrim, bRescaled, vU0, vV0, nDegU, nDegV, dScaleU, dScaleV, false)) { ++ nFailedBTrim ; continue ; } pSurfBezNew->SetTrimRegion( *pSfrTrim) ; } else pSfrTrim->Scale( GLOB_FRM, nSpanU / dScaleU, nSpanV / dScaleV, 1) ; if ( pSfrTrim != nullptr) delete pSfrTrim ; if ( bRev) pSurfBezNew->Invert() ; pSurfBezNew->RemoveCollapsedSpans() ; pSurfBezNew->LimitSurfToTrimmedRegion() ; #if SAVEREVOLVESURF SaveGeoObj( pSurfBezNew->Clone(), "D:\\Temp\\bezier\\import3dm\\revolve_surf\\surf_ok.nge") ; #endif if ( ! bForceTriMesh) vSurf.emplace_back( Release( pSurfBezNew)) ; else stmSoup.AddSurfTriMesh( *(pSurfBezNew->GetAuxSurf())) ; } else { ++nFailedBz ; } } } } if ( nFailedBFace != 0) { string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBFace) + " Brep faces" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; } if ( nFailedTm != 0) { string sOut = "Import3dm : Failed conversion of " + to_string( nFailedTm) + " trimesh belonging to a Brep" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; } if ( nFailedFr != 0) { string sOut = "Import3dm : Failed conversion of " + to_string( nFailedFr) + " FlatRegion belonging to a Brep" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; } if ( nFailedBz != 0) { string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBz) + " NURBS belonging to a Brep" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; } if ( nFailedBTrim != 0) { string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBTrim) + " trims of surfaces belonging to a Brep" ; LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; } if ( ! stmSoup.End()) return vSurf ; PtrOwner pSTM( stmSoup.GetSurf()) ; if ( ! IsNull( pSTM) && pSTM->IsValid()) vSurf.emplace_back( Release( pSTM)) ; return vSurf ; } //---------------------------------------------------------------------------- ICurveComposite* Import3dm::ApproxTrim( ICurve* pCrv) { PtrOwner pCC( CreateCurveComposite()) ; PolyLine plApprox ; pCrv->ApproxWithLines(LIN_TOL_FINE, ANG_TOL_FINE, 0, plApprox) ; pCC->FromPolyLine(plApprox) ; pCC->MergeCurves(LIN_TOL_FINE, ANG_TOL_FINE) ; return Release( pCC) ; } //---------------------------------------------------------------------------- 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); PtrOwner pCrv( ConvertCurve( onCurveProxy)) ; if ( IsNull(pCrv) || ! pCrv->IsValid()) continue ; if ( ! pCrvCompo->AddCurve( pCrv->Clone())) { Point3d ptEnd ; pCrvCompo->GetEndPoint( ptEnd) ; pCrv->ModifyStart( ptEnd) ; if ( ! pCrvCompo->AddCurve( pCrv->Clone())) return nullptr ; } } //// APPROSSIMO I BREP LOOP PER ALLEGGERIRE LE OPERAZIONI DI TRIM DELLE BEZIER //pCrvCompo->RemoveSmallParts( 0.1, 15) ; //pCrvCompo->MergeCurves( 0.1, 15) ; //PolyArc paApprox ; //pCrvCompo->ApproxWithArcs( 0.1, 15, paApprox) ; //pCrvCompo->FromPolyArc( paApprox) ; return Release( pCrvCompo) ; } //---------------------------------------------------------------------------- ISURFPOVECTOR Import3dm::ConvertExtrusion( const ON_Extrusion* onExtrusion) { ISURFPOVECTOR vpSurf ; Point3d ptStart( ConvertPoint( onExtrusion->PathStart())) ; Point3d ptEnd( ConvertPoint( onExtrusion->PathEnd())) ; Vector3d vtDir = ptEnd - ptStart ; int nIsCapped = onExtrusion->IsCapped() ; // 0: no or profile is open /1: bottom cap( ptEnd) /2: top cap( ptStart) /3: both ends capped. // creo la superficie a partire dalle curve CICURVEPVECTOR vCrvProfile ; int nProfiles = onExtrusion->ProfileCount() ; ////////// versione con le curve 2d da trasformare in 3d ( a volte manca un pezzo di trasformazione) //ON_SimpleArray onSaProfile ; //int nProfiles = onExtrusion->GetProfileCurves( onSaProfile) ; for ( int i = 0 ; i < nProfiles ; ++i ) { //const ON_Curve* onCurve = onSaProfile[i] ; //ON_Xform onProfileFrame ; onExtrusion->GetProfileTransformation( 0, onProfileFrame) ; //ON_Curve* onCurveCopy = onCurve->DuplicateCurve() ; //onCurveCopy->Transform( onProfileFrame) ; //PtrOwner pCurve( ConvertCurve( onCurveCopy)) ; //delete onCurveCopy ; ON_Curve* onCurve = onExtrusion->Profile3d( i, 0) ; // do per scontato che il profilo resti uguale dall'inizio alla fine del path PtrOwner pCurve( ConvertCurve( onCurve)) ; delete onCurve ; if ( IsNull( pCurve) || ! pCurve->IsValid()) { m_mError_count["extrusion"] += 1 ; break ; } vCrvProfile.emplace_back( Release(pCurve)) ; } // uso l'estrusione con le bezier for ( int i = 0 ; i < ssize( vCrvProfile); ++i) { PtrOwner pSurfBez( CreateSurfBezier()) ; pSurfBez->CreateByExtrusion( vCrvProfile[i], vtDir) ; vpSurf.emplace_back() ; vpSurf.back().Set( Release( pSurfBez)) ; } ///// quando ci saranno le surf compo allora la superficie con cap dovrà essere un'unica surfcompo if ( nIsCapped != 0) { // aggiungo anche le due superfici di cap PtrOwner pSurfBezCap( CreateSurfBezier()) ; POLYLINEVECTOR vPL ; for ( int i = 0 ; i < ssize( vCrvProfile) ; ++i) { vPL.emplace_back() ; vCrvProfile[i]->ApproxWithLines( LIN_TOL_STD, ANG_TOL_FINE, ICurve::ApprLineType::APL_STD, vPL.back()) ; } if ( nIsCapped == 2 || nIsCapped == 3) { // top o entrambe if ( ! pSurfBezCap->CreateByRegion( vPL) || ! pSurfBezCap->Invert()) { m_mError_count["extrusion"] += 1 ; goto exit ; } vpSurf.emplace_back() ; vpSurf.back().Set( Release( pSurfBezCap)) ; } if ( nIsCapped == 1 || nIsCapped == 3) { // bottom o entrambe if ( nIsCapped == 3) { vpSurf.emplace_back( vpSurf.back()->Clone()) ; vpSurf.back()->Invert() ; } else { pSurfBezCap.Set( CreateSurfBezier()) ; if( ! pSurfBezCap->CreateByRegion( vPL)) { m_mError_count["extrusion"] += 1 ; goto exit ; } vpSurf.emplace_back() ; vpSurf.back().Set( Release( pSurfBezCap)) ; } vpSurf.back()->Translate( vtDir) ; } } // se ho fallito con le bezier procedo con le trimesh if( ssize( vpSurf) == 0) { if ( nIsCapped == 3) { vpSurf.emplace_back( GetSurfTriMeshByRegionExtrusion( vCrvProfile, vtDir)) ; } else { StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) { m_mError_count["extrusion"] += 1 ; goto exit ; } for ( int i = 0 ; i < (int)vCrvProfile.size() ; ++i ) stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( vCrvProfile[i], vtDir, false)) ; // controllo se la superficie è capped solo sopra o sotto ed eventualmente aggiungo alla trimesh la superficie adeguata if ( nIsCapped != 0) { PtrOwner pSurfTmCap( GetSurfTriMeshByRegion( vCrvProfile)) ; if ( ! IsNull( pSurfTmCap) && pSurfTmCap->IsValid()) { // se capped sopra traslo la trimeshregion if ( nIsCapped == 1) pSurfTmCap->Translate(vtDir) ; // sennò la aggiungo direttamente stmSoup.AddSurfTriMesh( *pSurfTmCap) ; } } if ( ! stmSoup.End()){ m_mError_count["extrusion"] += 1 ; goto exit ; } vpSurf.emplace_back( GetSurfTriMesh( stmSoup.GetSurf())) ; } } exit : for ( int k = 0 ; k < (int)vCrvProfile.size() ; ++k) { if ( vCrvProfile[k] != nullptr) delete vCrvProfile[k] ; } return vpSurf ; ////////////////// VERSIONE CON BREP - RIDONDANTE //if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) // return Release( pSurfTm) ; //else { // // se non sono riuscito a creare la superficie per qualche motivo, allora tento una conversione con gli strumenti di OPENURBS prima // // di convertire la superficie // //// CONVERSIONE DELL'EXTRUSION AD UN'ALTRA SUPERFICIE RHINO PRIMA DI ESSERE CONVERTITA // ON_Object* onObject = nullptr ; // ISurf* pSurf = nullptr ; // PtrOwner pSurfBz( CreateSurfBezier()) ; // if ( IsNull( pSurfBz)) // return nullptr ; // PtrOwner pSurfTm( CreateSurfTriMesh()) ; // if ( IsNull( pSurfTm)) // return nullptr ; // if ( onExtrusion->IsCapped() || onExtrusion->ProfileCount() >= 2) { // onObject = onExtrusion->BrepForm(0) ; // if ( nullptr != onObject) { // const ON_Brep* onBrep = ON_Brep::Cast( onObject) ; // ISURFPOVECTOR vpSurf ; // vpSurf = ConvertBrep( onBrep, true) ; // chiedo di ottenere un'unica superficie trimesh // pSurfTm.Set( GetSurfTriMesh( Release(vpSurf[0]))) ; // } // } // if ( onObject == nullptr) { // onObject = onExtrusion->SumSurfaceForm(0) ; // if ( onObject != nullptr) { // const ON_Surface* onSurface = ON_Surface::Cast( onObject) ; // pSurf = ConvertSurface( onSurface) ; // pSurfTm.Set( GetSurfTriMesh(pSurf)) ; // } // } // if ( onObject == nullptr) { // onObject = onExtrusion->NurbsSurface(0) ; // if ( onObject != nullptr) { // const ON_NurbsSurface* onNurbsSurface = ON_NurbsSurface::Cast( onObject) ; // pSurf = ConvertSurface( onNurbsSurface) ; // // in questo caso devo anche trasformare la superficie di bezier che ho appenta ottenuto in una trimesh // pSurfBz.Set( GetSurfBezier( pSurf)) ; // pSurfTm.Set( pSurfBz->GetAuxSurf()->Clone()) ; // } // } // if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) // return Release( pSurfTm) ; //} //m_mError_count["extrusion"] += 1 ; //return nullptr ; } //---------------------------------------------------------------------------- ISurfTriMesh* Import3dm::ConvertMesh( const ON_Mesh* onMesh) { ON_Mesh* onMeshToConvert = onMesh->Duplicate() ; PtrOwner pSurfTm( CreateSurfTriMesh()) ; if ( IsNull( pSurfTm)) return nullptr ; int nVertices = onMesh->VertexCount() ; bool bDoublePrec = onMesh->HasDoublePrecisionVertices() ; for ( int i = 0 ; i < nVertices ; ++i ) { Point3d pt = ConvertPoint( bDoublePrec ? *( onMesh->m_dV.At( i)) : *( onMesh->m_V.At( i))) ; pSurfTm->AddVertex( pt) ; } ON_MeshFaceList onFaceList( onMesh) ; int nQuads = onMesh->QuadCount() ; //split_method - [in] // 0 default - Currently divides along the short diagonal. // 1 divide along the short diagonal // 2 divide along the long diagonal // 3 minimize resulting area // 4 maximize resulting area // 5 minimize angle between triangle normals // 6 maximize angle between triangle normals double dLinTol = ON_UNSET_VALUE ; double dAndTolRad = ON_UNSET_VALUE ; unsigned int nSplitMethod = 0 ; bool bStillQuads = false ; if ( nQuads != 0) { // restituisce il numero di quadrati convertiti unsigned int nQuadsNonPlanarConv = onMeshToConvert->ConvertNonPlanarQuadsToTriangles( dLinTol, dAndTolRad, nSplitMethod) ; bStillQuads = nQuadsNonPlanarConv == 0 ? true : false ; } int nFaces = onMeshToConvert->FaceCount() ; for (int j = 0 ; j < nFaces ; ++j) { const ON_MeshFace* onMeshFace = onMeshToConvert->m_F.At( j) ; if ( ! bStillQuads ) { int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[2]} ; pSurfTm->AddTriangle( nIdVert) ; } else if ( onFaceList.IsQuad( j)) { // la divisione automatica non è riuscita. // divido lungo la diagonale più corta Point3d pt0 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[0])) ; Point3d pt1 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[1])) ; Point3d pt2 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[2])) ; Point3d pt3 = ConvertPoint( *onMesh->m_V.At(onMeshFace->vi[3])) ; if ( Dist( pt0, pt2) < Dist( pt1, pt3)) { int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[2]} ; pSurfTm->AddTriangle( nIdVert) ; int nIdVert2[3] = {onMeshFace->vi[0], onMeshFace->vi[2],onMeshFace->vi[3]} ; pSurfTm->AddTriangle( nIdVert2) ; } else { int nIdVert[3] = {onMeshFace->vi[0], onMeshFace->vi[1],onMeshFace->vi[3]} ; pSurfTm->AddTriangle( nIdVert) ; int nIdVert2[3] = {onMeshFace->vi[1], onMeshFace->vi[2],onMeshFace->vi[3]} ; pSurfTm->AddTriangle( nIdVert2) ; } } } delete onMeshToConvert ; pSurfTm->AdjustTopology() ; return Release( pSurfTm) ; } //---------------------------------------------------------------------------- std::vector> Import3dm::ConvertAnnotation( const ON_Annotation* onAnnot, const ON_DimStyle* onDimStyle) { // TO DO // la posizione è da correggere se le annotazioni sono presenti nell'anteprima di stampa // ( dovrebbe esserci nel modello un oggetto detail che ne definisce l'impaginazione) vector> vpObj ; ON::AnnotationType onAnnType = onAnnot->Type() ; switch( onAnnType) { case ON::AnnotationType::Text : { const ON_Text* onText = ON_Text::Cast( onAnnot) ; string str = ConvertONwStringToString( onText->PlainText()) ; ON_Plane onPlane = onText->Plane() ; Point3d ptOrig = ConvertPoint( onPlane.origin) ; Vector3d vtN = ConvertVector( onPlane.Normal()) ; Vector3d vtDir = ConvertVector( onText->HorizontalDirection()) ; PtrOwner tText( CreateExtText()) ; tText->Set( ptOrig, vtN, vtDir, str, m_sFont, false, m_dTextHeight) ; if ( ! IsNull( tText) && tText->IsValid()) { vpObj.emplace_back( Release( tText)) ; return vpObj ; } else m_mError_count["annotation"] += 1 ; break ; } case ON::AnnotationType::Leader : { const ON_Leader* onLeader = ON_Leader::Cast( onAnnot) ; string str = ConvertONwStringToString( onLeader->PlainText()) ; ON_Plane onPlane = onAnnot->Plane() ; Point3d ptOrig = ConvertPoint( onPlane.origin) ; Vector3d vtX = ConvertVector( onPlane.xaxis) ; Vector3d vtY = ConvertVector( onPlane.yaxis) ; Vector3d vtN = ConvertVector( onPlane.Normal()) ; Vector3d vtDir = ConvertVector( onAnnot->HorizontalDirection()) ; ON_2dPoint on2dPoint ; double dScale = onLeader->DimScale( onDimStyle) ; onLeader->GetTextPoint2d( onDimStyle, dScale, on2dPoint) ; Point3d ptTextPoint( on2dPoint.x, on2dPoint.y) ; Frame3d frPlane ; frPlane.Set( ptOrig, vtX, vtY,vtN) ; ptTextPoint.ToGlob( frPlane) ; PtrOwner tText( CreateExtText()) ; tText->Set( ptTextPoint, vtN, vtDir, str, m_sFont, false, m_dTextHeight) ; //aggiungo al gruppo: testo, linea e landing if ( ! IsNull( tText) && tText->IsValid()) vpObj.emplace_back( Release( tText)) ; else{ m_mError_count["annotation"] += 1 ; break ; } const ON_Curve* onCurve = onLeader->Curve( onDimStyle) ; PtrOwner pCurve( ConvertCurve( onCurve)) ; if ( ! IsNull( pCurve) && pCurve->IsValid()) { vpObj.emplace_back( Release( pCurve)) ; } else { m_mError_count["annotation"] += 1 ; vpObj.clear() ; break ; } if ( onLeader->LeaderHasLanding( onDimStyle)) { ON_Line onLine ; onLeader->LandingLine2d( onDimStyle, dScale, onLine) ; Point3d ptStart = ConvertPoint(onLine.from) ; Point3d ptEnd = ConvertPoint(onLine.to) ; PtrOwner pCrvL( CreateCurveLine()) ; pCrvL->Set( ptStart, ptEnd) ; if ( ! IsNull( pCrvL) && pCrvL->IsValid()) { pCrvL->ToGlob( frPlane) ; vpObj.emplace_back( Release( pCrvL)) ; } else { m_mError_count["annotation"] += 1 ; vpObj.clear() ; break ; } } break ; } case ON::AnnotationType::Aligned : case ON::AnnotationType::Rotated : { const ON_DimLinear* onDimLin = ON_DimLinear::Cast( onAnnot) ; // recupero tutti i dati della quota ON_3dPoint onPt1, onPt2, onPtAr1, onPtAr2, onPtDimLine, onPtText ; onDimLin->Get3dPoints( &onPt1, &onPt2, &onPtAr1, &onPtAr2, &onPtDimLine, &onPtText) ; double dAngDeg = onDimLin->TextRotationRadians() * RADTODEG ; // rotazione del testo rispetto alla direzione orizzontale ON_Plane onPlane = onDimLin->Plane() ; Vector3d vtN = ConvertVector( onPlane.Normal()) ; Vector3d vtDir = ConvertPoint(onPt2) - ConvertPoint(onPt1) ; if ( ! vtDir.Normalize() || ! vtDir.Rotate( vtN, dAngDeg)) { m_mError_count["annotation"] += 1 ; break ; } Point3d ptP1( ConvertPoint( onPt1)) ; Point3d ptP2( ConvertPoint( onPt2)) ; Point3d ptPDimL( ConvertPoint( onPtDimLine)) ; // creo la quota PtrOwner pDim( CreateExtDimension()) ; if ( onAnnType == ON::AnnotationType::Aligned) { if ( IsNull( pDim ) || ! pDim->SetStyle( m_dExtLine, m_dArrLen, m_dTextDist, m_bLenIsMM, m_nDecDig, m_sFont, m_dTextHeight) || ! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, V_NULL, "<>")) { m_mError_count["annotation"] += 1 ; break ; } } else if ( onAnnType == ON::AnnotationType::Rotated){ if ( IsNull( pDim ) || ! pDim->SetStyle( m_dExtLine, m_dArrLen, m_dTextDist, m_bLenIsMM, m_nDecDig, m_sFont, m_dTextHeight) || ! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, vtDir, "<>")) { m_mError_count["annotation"] += 1 ; break ; } } // inserisco la quota nel DB if ( ! IsNull( pDim) && pDim->IsValid()) { vpObj.emplace_back( Release( pDim)) ; return vpObj ; } else { m_mError_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 ptPDimL( ConvertPoint( onPtDimLine)) ; // creo la quota PtrOwner pDim( CreateExtDimension()) ; if ( ! IsNull( pDim) && pDim->SetStyle( m_dExtLine, m_dArrLen, m_dTextDist, m_bLenIsMM, m_nDecDig, m_sFont, m_dTextHeight) && pDim->SetAngular( ptCen, ptP1, ptP2, ptPDimL, vtN, "<>") && pDim->IsValid()) { vpObj.emplace_back( Release( pDim)) ; return vpObj ; } else { m_mError_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( m_dExtLine, m_dArrLen, m_dTextDist, m_bLenIsMM, m_nDecDig, m_sFont, m_dTextHeight) && pDim->SetRadial( ptCen, ptDim, vtN, "<>")) { vpObj.emplace_back( Release( pDim)) ; return vpObj ; } else { m_mError_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( m_dExtLine, m_dArrLen, m_dTextDist, m_bLenIsMM, m_nDecDig, m_sFont, m_dTextHeight) || pDim->SetDiametral( ptCen, ptDim, vtN, "<>")) { vpObj.emplace_back( Release( pDim)) ; return vpObj ; } else { m_mError_count["annotation"] += 1 ; break ; } } default : m_mError_count["annotation"] += 1 ; break ; } return vpObj ; } //---------------------------------------------------------------------------- bool Import3dm::ConvertCurveParam( const ON_RevSurface* onRevSurf, ICurve** pCrv) { PtrOwner pCrvNew ; if ( (*pCrv)->GetType() == CRV_LINE) { PtrOwner pCrvLine( CreateCurveLine()) ; double dnurbsU ; double dnurbsV ; Point3d ptStart ; (*pCrv)->GetStartPoint( ptStart) ; onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptStart.x, ptStart.y, &dnurbsU, &dnurbsV) ; ptStart.Set( dnurbsU, dnurbsV, 0) ; Point3d ptEnd ; (*pCrv)->GetEndPoint( ptEnd) ; onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptEnd.x, ptEnd.y, &dnurbsU, &dnurbsV) ; ptEnd.Set( dnurbsU, dnurbsV, 0) ; pCrvLine->Set( ptStart, ptEnd) ; pCrvNew.Set( Release( pCrvLine)) ; } else if ( (*pCrv)->GetType() == CRV_ARC) { double dnurbsU ; double dnurbsV ; Point3d ptStart ; (*pCrv)->GetStartPoint( ptStart) ; onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptStart.x, ptStart.y, &dnurbsU, &dnurbsV) ; ptStart.Set( dnurbsU, dnurbsV, 0) ; Point3d ptEnd ; (*pCrv)->GetEndPoint( ptEnd) ; onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptEnd.x, ptEnd.y, &dnurbsU, &dnurbsV) ; ptEnd.Set( dnurbsU, dnurbsV, 0) ; Vector3d vtDir, vtN ; (*pCrv)->GetStartDir( vtDir) ; ICurveArc* pCrvArcOrig = GetCurveArc( (*pCrv)) ; vtN = pCrvArcOrig->GetNormVersor( ) ; PtrOwner pCrvArc( CreateCurveArc()) ; pCrvArc->Set2PVN( ptStart, ptEnd, vtDir, vtN) ; pCrvNew.Set( Release( pCrvArc)) ; } else if ( (*pCrv)->GetType() == CRV_BEZIER) { double dnurbsU ; double dnurbsV ; PtrOwner pCrvBez( GetCurveBezier( (*pCrv))) ; int nDeg = pCrvBez->GetDegree() ; int nCV = nDeg + 1 ; for ( int i = 0 ; i < nCV ; ++i) { Point3d ptNew = pCrvBez->GetControlPoint( i) ; onRevSurf->GetNurbFormParameterFromSurfaceParameter( ptNew.x, ptNew.y, &dnurbsU, &dnurbsV) ; ptNew.Set( dnurbsU, dnurbsV, 0) ; // sto cambiando le coordinate dei CP nella curva, mentre i pesi non sono da modificare pCrvBez->SetControlPoint( i, ptNew) ; } pCrvNew.Set( pCrvBez) ; } else if ( (*pCrv)->GetType() == CRV_COMPO) { PtrOwner pCrvCompo( GetCurveComposite( (*pCrv))) ; PtrOwner pCrvCompoNew( CreateCurveComposite()) ; for ( const ICurve* pCrvSimpleOrig = pCrvCompo->GetFirstCurve() ; pCrvSimpleOrig != nullptr ; pCrvSimpleOrig = pCrvCompo->GetNextCurve()) { ICurve* pCrvSimple( pCrvSimpleOrig->Clone()) ; ConvertCurveParam( onRevSurf, &pCrvSimple) ; pCrvCompoNew->AddCurve( pCrvSimple) ; } pCrvNew.Set( pCrvCompoNew) ; } (*pCrv) = Release( pCrvNew) ; return true ; }