commit 9ebdf4a8b362c511e52607e295cab84ebf2fcc75 Author: Dario Sassi Date: Tue Nov 14 19:04:19 2023 +0100 EgtExch3dm 2.5k2 : - primo rilascio. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fce4515 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ + +# / +/revision.h +/*.aps +/*.ncb +/*.suo +/*.user +/*.sdf +/*.opensdf +/Debug32 +/Release32 +/Trial32 +/Debug64 +/Release64 +/ipch +/bin +/obj +/.vs diff --git a/DllMain.h b/DllMain.h new file mode 100644 index 0000000..56b27dd --- /dev/null +++ b/DllMain.h @@ -0,0 +1,23 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023-2023 +//---------------------------------------------------------------------------- +// File : DllMain.h Data : 14.11.23 Versione : 2.5k2 +// Contenuto : Prototipi funzioni per uso locale della DLL. +// +// +// +// Modifiche : 14.11.23 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EgtILogger.h" +#include + +//----------------------------------------------------------------------------- +ILogger* GetEE3Logger( void) ; +const std::string& GetEE3Key( void) ; +bool GetEE3NetHwKey( void) ; +bool VerifyKey( int nKeyOpt) ; diff --git a/EE3DllMain.cpp b/EE3DllMain.cpp new file mode 100644 index 0000000..8671285 --- /dev/null +++ b/EE3DllMain.cpp @@ -0,0 +1,150 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023-2023 +//---------------------------------------------------------------------------- +// File : EE3DllMain.cpp Data : 14.11.23 Versione : 2.5k2 +// Contenuto : Inizializzazione della DLL. +// +// +// +// Modifiche : 14.11.23 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "DllMain.h" +#include "/EgtDev/Include/EE3DllMain.h" +#include "/EgtDev/Include/EGnGetModuleVer.h" +#include "/EgtDev/Include/EGnGetKeyData.h" +#include "/EgtDev/Include/EgtTrace.h" + +//--------------------------- Costanti ---------------------------------------- +#if defined( _WIN64) && defined( _DEBUG) + const char* EE3_STR = "EgtExch3dmD64.dll ver. " ; +#elif defined( _WIN64) + const char* EE3_STR = "EgtExch3dmR64.dll ver. " ; +#elif defined( _WIN32) && defined( _DEBUG) + const char* EE3_STR = "EgtExch3dmD32.dll ver. " ; +#else + const char* EE3_STR = "EgtExch3dmR32.dll ver. " ; +#endif +const int STR_DIM = 40 ; + +//----------------------------------------------------------------------------- +static HINSTANCE s_hModule = NULL ; +static char s_szEE3NameVer[STR_DIM] ; + +//----------------------------------------------------------------------------- +BOOL APIENTRY +DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved) +{ + + if ( dwReason == DLL_PROCESS_ATTACH) { + // Controllo commentato per problemi con VB.NET + //#if defined( NDEBUG) + // BOOL IsDbgPresent = FALSE ; + // CheckRemoteDebuggerPresent( GetCurrentProcess(), &IsDbgPresent) ; + // if ( IsDbgPresent) + // return 0 ; + //#endif + s_hModule = hModule ; + EGT_TRACE( "EgtExch3dm.dll Initializing!\n") ; + } + else if ( dwReason == DLL_PROCESS_DETACH) { + s_hModule = NULL ; + EGT_TRACE( "EgtExch3dm.dll Terminating!\n") ; + } + + return 1 ; +} + +//----------------------------------------------------------------------------- +const char* +GetEE3Version( void) +{ + std::string sVer ; + + GetModuleVersion( s_hModule, sVer) ; + sprintf_s( s_szEE3NameVer, STR_DIM, "%s%s", EE3_STR, sVer.c_str()) ; + + return s_szEE3NameVer ; +} + +//----------------------------------------------------------------------------- +static ILogger* s_pLogger = nullptr ; + +//----------------------------------------------------------------------------- +void +SetEE3Logger( ILogger* pLogger) +{ + s_pLogger = pLogger ; +} + +//----------------------------------------------------------------------------- +ILogger* +GetEE3Logger( void) +{ + return s_pLogger ; +} + +//----------------------------------------------------------------------------- +static std::string s_sKey ; +static bool s_bNetHwKey = false ; + +//----------------------------------------------------------------------------- +void +SetEE3Key( const std::string& sKey) +{ + s_sKey = sKey ; +} + +//----------------------------------------------------------------------------- +void +SetEE3NetHwKey( bool bNetHwKey) +{ + s_bNetHwKey = bNetHwKey ; +} + +//----------------------------------------------------------------------------- +const std::string& +GetEE3Key( void) +{ + return s_sKey ; +} + +//----------------------------------------------------------------------------- +bool +GetEE3NetHwKey( void) +{ + return s_bNetHwKey ; +} + +//----------------------------------------------------------------------------- +bool +VerifyKey( int nKeyOpt) +{ + // Controllo della licenza + unsigned int nOpt1, nOpt2 ; + int nOptExpDays ; + int nRet = GetEGnKeyOptions( KEY_BASELIB_PROD, KEY_BASELIB_VER, KEY_BASELIB_LEV, + nOpt1, nOpt2, nOptExpDays) ; + if ( ! GetEE3NetHwKey()) + nRet = GetKeyOptions( GetEE3Key(), KEY_BASELIB_PROD, KEY_BASELIB_VER, KEY_BASELIB_LEV, + nOpt1, nOpt2, nOptExpDays) ; + if ( nRet != KEY_OK && ! EqualNoCase( GetEE3Key(), "EE3Base")) { + if ( nRet != KEY_OK) { + std::string sErr = "Error on Key (EE3/" + ToString( nRet) + ")" ; + LOG_ERROR( GetEE3Logger(), sErr.c_str()) ; + return false ; + } + if ( ( nOpt1 & ( KEYOPT_EEX_INPBASE|KEYOPT_EEX_EXPBASE)) == 0 || + ( nKeyOpt != 0 && ( nOpt1 & nKeyOpt) == 0) || + nOptExpDays < GetCurrDay()) { + std::string sErr = "Warning on Key (EE3/OPT)" ; + LOG_ERROR( GetEE3Logger(), sErr.c_str()) ; + return false ; + } + } + return true ; +} diff --git a/EgtExch3dm.rc b/EgtExch3dm.rc new file mode 100644 index 0000000..5983d91 Binary files /dev/null and b/EgtExch3dm.rc differ diff --git a/EgtExch3dm.sln b/EgtExch3dm.sln new file mode 100644 index 0000000..dfe3522 --- /dev/null +++ b/EgtExch3dm.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34221.43 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EgtExch3dm", "EgtExch3dm.vcxproj", "{D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Debug|x64.ActiveCfg = Debug|x64 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Debug|x64.Build.0 = Debug|x64 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Debug|x86.ActiveCfg = Debug|Win32 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Debug|x86.Build.0 = Debug|Win32 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Release|x64.ActiveCfg = Release|x64 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Release|x64.Build.0 = Release|x64 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Release|x86.ActiveCfg = Release|Win32 + {D1A76918-1E81-4851-9B6F-2B1DB0EFB2A4}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2667F08C-F801-4E10-BB21-2A7F501982D9} + EndGlobalSection +EndGlobal diff --git a/EgtExch3dm.vcxproj b/EgtExch3dm.vcxproj new file mode 100644 index 0000000..8cf5482 --- /dev/null +++ b/EgtExch3dm.vcxproj @@ -0,0 +1,240 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {d1a76918-1e81-4851-9b6f-2b1db0efb2a4} + EgtExch3dm + 10.0.20348.0 + + + + DynamicLibrary + true + v141_xp + Unicode + + + DynamicLibrary + false + v141_xp + true + Unicode + + + DynamicLibrary + true + ClangCL + Unicode + + + DynamicLibrary + false + ClangCL + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Configuration)$(PlatformArchitecture)\ + $(Configuration)$(PlatformArchitecture)\ + $(ProjectName)D$(PlatformArchitecture) + C:\;$(IncludePath) + + + $(SolutionDir)$(Configuration)$(PlatformArchitecture)\ + $(Configuration)$(PlatformArchitecture)\ + $(ProjectName)R$(PlatformArchitecture) + C:\;$(IncludePath) + false + + + $(SolutionDir)$(Configuration)$(PlatformArchitecture)\ + $(Configuration)$(PlatformArchitecture)\ + $(ProjectName)D$(PlatformArchitecture) + C:\;$(IncludePath) + + + $(SolutionDir)$(Configuration)$(PlatformArchitecture)\ + $(Configuration)$(PlatformArchitecture)\ + $(ProjectName)R$(PlatformArchitecture) + C:\;$(IncludePath) + + + + Level3 + WIN32;I_AM_EE3;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + false + Use + stdafx.h + ProgramDatabase + false + stdcpp17 + + + Windows + true + false + C:\EgtDev\Extern\OxySec\Lib\x32\xnodus32.obj;%(AdditionalDependencies) + + + _DEB32;%(PreprocessorDefinitions) + + + copy $(TargetDir)$(TargetName).pdb \EgtDev\Lib\ +copy $(TargetDir)$(TargetName).lib \EgtDev\Lib\ +copy $(TargetPath) \EgtProg\DllD32 + + + + + Level3 + true + true + WIN32;I_AM_EE3;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + false + Use + stdafx.h + true + StreamingSIMDExtensions2 + false + stdcpp17 + Speed + AnySuitable + false + true + true + + + Windows + false + true + false + true + C:\EgtDev\Extern\OxySec\Lib\x32\xnodus32.obj;%(AdditionalDependencies) + Default + + + NDEB32;%(PreprocessorDefinitions) + + + copy $(TargetDir)$(TargetName).lib \EgtDev\Lib\ +copy $(TargetPath) \EgtProg\Dll32 + + + + + Level3 + true + WIN32;I_AM_EE3;_DEBUG;EGTEXCH3DM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + stdafx.h + stdcpp17 + + + Windows + true + false + C:\EgtDev\Extern\OxySec\Lib\x64\xnodus.obj;%(AdditionalDependencies) + + + _DEB64;%(PreprocessorDefinitions) + + + copy $(TargetDir)$(TargetName).pdb \EgtDev\Lib\ +copy $(TargetDir)$(TargetName).lib \EgtDev\Lib\ +copy $(TargetPath) \EgtProg\DllD64 + + + + + Level3 + true + true + true + WIN32;I_AM_EE3;NDEBUG;EGTEXCH3DM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + stdafx.h + stdcpp17 + + + Windows + true + true + true + false + C:\EgtDev\Extern\OxySec\Lib\x64\xnodus.obj;%(AdditionalDependencies) + + + NDEB64;%(PreprocessorDefinitions) + + + copy $(TargetDir)$(TargetName).lib \EgtDev\Lib\ +copy $(TargetPath) \EgtProg\Dll64 + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + \ No newline at end of file diff --git a/EgtExch3dm.vcxproj.filters b/EgtExch3dm.vcxproj.filters new file mode 100644 index 0000000..1fd29c6 --- /dev/null +++ b/EgtExch3dm.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {11088a38-0d50-4722-b177-1b9a9474d5db} + + + + + Header Files + + + Header Files + + + Header Files\Include + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Include + + + Header Files\Include + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/Export3dm.cpp b/Export3dm.cpp new file mode 100644 index 0000000..ec0c7d9 --- /dev/null +++ b/Export3dm.cpp @@ -0,0 +1,708 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Export3dm.cpp Data : 21.09.23 Versione : +// Contenuto : Implementazione della classe per l'esportazione in formato 3dm. +// +// +// +// Modifiche : 21.09.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "Export3dm.h" +#include "DllMain.h" +#include "/EgtDev/Include/EE3DllMain.h" +#include "/EgtDev/Include/EGkGeomDB.h" +#include "/EgtDev/Include/EGkSurfFlatRegion.h" +#include "/EgtDev/Include/EGkSurfTriMesh.h" +#include "/EgtDev/Include/EGkSurfBezier.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkCurveArc.h" +#include "/EgtDev/Include/EGkCurveBezier.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkGdbIterator.h" +#include "/EgtDev/Include/EGkGeoObjType.h" +#include "/EgtDev/Include/EGkGeoPoint3d.h" +#include "/EgtDev/Include/EGnStringUtils.h" +#include "/EgtDev/Include/SELkKeyProc.h" +#include "/EgtDev/Include/EgtKeyCodes.h" +#include "/EgtDev/Include/EgtStringConverter.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Include/EGnStringUtils.h" +#include "/EgtDev/Extern/opennurbs/Include/opennurbs.h" +#include +#include + + +using namespace std ; +//N.B.: +// se si vuole richiamare qualche variabile di default definita in una classe come statica e a cui viene assegnato un valore +// nel file opennurbs_statics.cpp bisogna richiamarla in questo elenco per evitare problemi di compilazione ( errore di LINK) + +//---------------------------------------------------------------------------- +IExport3dm* +CreateExport3dm( void) +{ + // verifico la chiave e le opzioni + if ( ! VerifyKey( KEYOPT_EEX_EXPBASE)) + return nullptr ; + // creo l'oggetto + return static_cast ( new( nothrow) Export3dm) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::SetOptions( int nFilter) +{ + m_nFilter = nFilter ; + CalcGroupFilter() ; + return true ; +} + +//---------------------------------------------------------------------------- +static void +Internal_SetExampleModelProperties( ONX_Model& model, const char* source_file_name) +{ + const bool bHaveFileName = ( nullptr != source_file_name && 0 != source_file_name[0]) ; + if ( ! bHaveFileName) + source_file_name = "" ; + + model.m_sStartSectionComments = "This file was created using openNURBS to convert an .nge into .3dm" ; + + // set application information + const ON_wString wide_source_file_name( source_file_name) ; + + model.m_properties.m_Application.m_application_URL = L"http://www.opennurbs.org" ; + + // set revision history information + model.m_properties.m_RevisionHistory.NewRevision() ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::Export( IGeomDB* pGDB, int nId, const string& sFile) +{ + Internal_SetExampleModelProperties( m_model, sFile.c_str()) ; + ON::Begin() ; + // verifico il DB geometrico + if ( pGDB == nullptr) { + LOG_ERROR( GetEE3Logger(), "Export3dm : Error on GeomDB") + return false ; + } + + // verifico l'Id dell'oggetto da esportare + if ( ! pGDB->ExistsObj( nId)) { + LOG_ERROR( GetEE3Logger(), "Export3dm : Error on Id") + return false ; + } + + //// file settings ( units, tolerances, views, ...) + //// OPTIONAL - change values from defaults + m_model.m_settings.m_ModelUnitsAndTolerances.m_unit_system = ON::LengthUnitSystem::Millimeters ; + m_model.m_settings.m_ModelUnitsAndTolerances.m_absolute_tolerance = 0.01 ; + m_model.m_settings.m_ModelUnitsAndTolerances.m_angle_tolerance = ON_PI/180.0 ;// radians + m_model.m_settings.m_ModelUnitsAndTolerances.m_relative_tolerance = 0.01 ;// 1% + m_model.m_settings.m_current_material_source = ON::object_material_source::material_from_object ; + m_model.m_settings.m_RenderSettings.m_bFlatShade = true ; + + // creo un iteratore + PtrOwner pIter( CreateGdbIterator( pGDB)) ; + if ( IsNull( pIter)) + return false ; + pIter->GoTo( nId) ; + // esporto l'oggetto e i suoi eventuali figli + bool bOk = ExportObject( *pIter, 0) ; + + // stampo il file + int version = 7 ; + // errors printed to stdout + ON_TextLog error_log ; + // writes model to archive + bOk = bOk && m_model.Write( ConvertString( sFile).c_str(), version, &error_log) ; + + ON::End() ; + + return bOk ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportObject( const IGdbIterator& iIter, const int& nLayer) +{ + // recupero il livello dell'oggetto + int nLev = GDB_LV_USER ; + iIter.GetCalcLevel( nLev) ; + // recupero il modo dell'oggetto + int nMode = GDB_MD_STD ; + iIter.GetCalcMode( nMode) ; + // recupero lo stato dell'oggetto + int nStat = GDB_ST_ON ; + iIter.GetCalcStatus( nStat) ; + int nType = iIter.GetGdbType() ; + // se il filtro lo abilita + if ( TestFilter( nLev, nMode, nStat, nType == GDB_TY_GROUP)) { + switch ( nType) { + case GDB_TY_GEO : + { + // recupero il riferimento globale dell'oggetto + Frame3d frFrame ; + if ( ! iIter.GetGlobFrame( frFrame)) + return false ; + //recupero il colore dell'oggetto + Color cCol ; + iIter.GetCalcMaterial( cCol) ; + // recupero eventuale nome + string sName ; + if ( ! iIter.GetName( sName)) + sName = ToString( iIter.GetId()) ; + // emetto l'oggetto + switch ( iIter.GetGeoType()) { + case GEO_PNT3D: { + if ( ! ExportPnt( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + case SRF_BEZIER: { + if ( ! ExportSrfBz( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + case SRF_FLATRGN : + case SRF_TRIMESH : + if ( ! ExportSTM( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + case CRV_ARC : { + if ( ! ExportCrvArc( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + case CRV_BEZIER : { + if ( ! ExportCrvBezier( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + case CRV_COMPO : { + if ( ! ExportCrvCompo( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + case CRV_LINE : { + if ( ! ExportCrvLine( sName, iIter, frFrame, cCol, nLayer)) + return false ; + break ; + } + default : + break ; + } + } + return true ; + case GDB_TY_GROUP: { + int nLayer = iIter.GetId() ; + if ( nLayer == 0) { + m_model.RemoveModelComponent( ON_ModelComponent::Type::Layer, m_model.LayerFromIndex( 0).ModelComponentId()) ; + return ScanGroup( iIter, nLayer) ; + } + // creo il layer e setto le proprietà + ON_Layer* layer = new ON_Layer() ; + std::string sLayName ; + iIter.GetName( sLayName) ; + if ( sLayName == "" ) { + sLayName = "Layer " + ToString( nLayer) ; + } + layer->SetName( ConvertString( sLayName).c_str()) ; + layer->SetIndex( nLayer) ; + ON_Color onCol( 0, 0, 0) ; // black + layer->SetColor( onCol) ; + layer->SetVisible( true) ; + layer->SetLocked( false) ; + int nParent = iIter.GetParentId() ; + if ( nParent != 0) { + // setto il parent + const ON_Layer* onParLay = ON_Layer::Cast( m_model.LayerFromIndex( m_mLayer[nParent]).ModelComponent()) ; + layer->SetParentLayerId( onParLay->Id()) ; + } + // copio le info + STRVECTOR vStrInfo, vStrInfo_split ; + iIter.GetAllInfo( vStrInfo) ; + for ( string sInfo : vStrInfo) { + Tokenize( sInfo, "=", vStrInfo_split) ; + layer->SetUserString( ConvertString( vStrInfo_split[0]).c_str(), ConvertString( vStrInfo_split[1]).c_str()) ; + } + + // aggiungo il layer + ON_ModelComponentReference mcr = m_model.AddManagedModelComponent( layer) ; + int nIndex = mcr.ModelComponentIndex() ; + m_mLayer.insert( pair< int, int>( nLayer, nIndex)) ; + + // esploro il gruppo + return ScanGroup( iIter, nIndex) ; + } + default : + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::AddObjectToModel( const IGdbIterator& iIter, ON_Object* onObject, const int& nLayer, const std::string& sName, const Color& cCol, + ON_3dmObjectAttributes* pOnAttr) +{ + if ( pOnAttr == nullptr) + pOnAttr = new ON_3dmObjectAttributes() ; + pOnAttr->m_layer_index = nLayer ; + pOnAttr->m_name = ConvertString( sName).c_str() ; + pOnAttr->SetColorSource( ON::color_from_object) ; + //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 + ON_Color onCol( cCol.GetIntRed(), cCol.GetIntGreen(), cCol.GetIntBlue(), abs( int( cCol.GetIntAlpha() * 2.55) - 255)) ; + pOnAttr->m_color = onCol ; + // se è una mesh aggiungo il materiale + if ( const ON_Mesh* onMesh = ON_Mesh::Cast( onObject)) { + // aggiungo il materiale al modello se necessario + std::string sCol = ToString(cCol.GetIntRed()) + "," + ToString( cCol.GetIntGreen()) + "," + ToString( cCol.GetIntBlue()) ; + if ( m_mMaterial.find( sCol) == m_mMaterial.end()) { + ON_Material* onMat = new ON_Material ; + ON_Color onCAmb( 126, 126, 126) ; // gray126 + onMat->m_reflection_glossiness = 0.0 ; + onMat->SetEmission( onCol) ; + onMat->SetDiffuse( onCol) ; + onMat->SetAmbient( onCAmb) ; + onMat->SetReflectivity( 0) ; + ON_ModelComponentReference mcr = m_model.AddManagedModelComponent( onMat) ; + int nIndex = mcr.ModelComponentIndex() ; + m_mMaterial.insert( pair< std::string, int>( sCol, nIndex)) ; + pOnAttr->SetMaterialSource( ON::object_material_source::material_from_object) ; + pOnAttr->m_material_index = nIndex ; + } + // sennò richiamo un materiale già definito + else { + pOnAttr->SetMaterialSource( ON::object_material_source::material_from_object) ; + pOnAttr->m_material_index = m_mMaterial[sCol] ; + } + } + // copio le info + STRVECTOR vStrInfo, vStrInfo_split ; + iIter.GetAllInfo(vStrInfo) ; + for ( string sInfo : vStrInfo) { + Tokenize( sInfo, "=", vStrInfo_split) ; + pOnAttr->SetUserString( ConvertString( vStrInfo_split[0]).c_str(), ConvertString( vStrInfo_split[1]).c_str()) ; + } + // aggiungo al modello + ON_ModelComponentReference mcr = m_model.AddManagedModelGeometryComponent( onObject, pOnAttr) ; + return ! mcr.IsEmpty() ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::AddInfoToObject( const IGdbIterator& iIter, ON_Object* onObject) +{ + // copio le info + STRVECTOR vStrInfo, vStrInfo_split ; + iIter.GetAllInfo( vStrInfo) ; + for ( string sInfo : vStrInfo) { + Tokenize( sInfo, "=", vStrInfo_split) ; + onObject->SetUserString( ConvertString( vStrInfo_split[0]).c_str(), ConvertString( vStrInfo_split[1]).c_str()) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::TestFilter( int nLev, int nMode, int nStat, bool bGroup) +{ + int nFilter = bGroup ? m_nGroupFilter : m_nFilter ; + if ( ( nLev == GDB_LV_USER && ( nFilter & EEXFLT_LEVUSER) == 0) || + ( nLev == GDB_LV_SYSTEM && ( nFilter & EEXFLT_LEVSYSTEM) == 0) || + ( nLev == GDB_LV_TEMP && ( nFilter & EEXFLT_LEVTEMP) == 0)) + return false ; + if ( ( nMode == GDB_MD_STD && ( nFilter & EEXFLT_MODESTD) == 0) || + ( nMode == GDB_MD_LOCKED && ( nFilter & EEXFLT_MODELOCKED) == 0) || + ( nMode == GDB_MD_HIDDEN && ( nFilter & EEXFLT_MODEHIDDEN) == 0)) + return false ; + if ( ( nStat == GDB_ST_OFF && ( nFilter & EEXFLT_STAOFF) == 0) || + ( nStat == GDB_ST_ON && ( nFilter & EEXFLT_STAON) == 0) || + ( nStat == GDB_ST_SEL && ( nFilter & EEXFLT_STASEL) == 0)) + return false ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::CalcGroupFilter( void) +{ + m_nGroupFilter = 0 ; + // Status + if ( ( m_nFilter & EEXFLT_STASEL) != 0) + m_nGroupFilter += EEXFLT_STASEL + EEXFLT_STAOFF + EEXFLT_STAON ; + else if ( ( m_nFilter & EEXFLT_STAOFF) != 0) + m_nGroupFilter += EEXFLT_STAOFF + EEXFLT_STAON ; + else + m_nGroupFilter += EEXFLT_STAON ; + // Mode + if ( ( m_nFilter & EEXFLT_MODELOCKED) != 0) + m_nGroupFilter += EEXFLT_MODELOCKED + EEXFLT_MODEHIDDEN + EEXFLT_MODESTD ; + else if ( ( m_nFilter & EEXFLT_MODEHIDDEN) != 0) + m_nGroupFilter += EEXFLT_MODEHIDDEN + EEXFLT_MODESTD ; + else + m_nGroupFilter += EEXFLT_MODESTD ; + // Level + if ( ( m_nFilter & EEXFLT_LEVSYSTEM) != 0) + m_nGroupFilter += EEXFLT_LEVSYSTEM + EEXFLT_LEVTEMP + EEXFLT_LEVUSER ; + else if ( ( m_nFilter & EEXFLT_LEVTEMP) != 0) + m_nGroupFilter += EEXFLT_LEVTEMP + EEXFLT_LEVUSER ; + else + m_nGroupFilter += EEXFLT_LEVUSER ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportPnt(const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pGeoPnt( GetGeoPoint3d( pGeoObj->Clone())) ; + if ( IsNull( pGeoPnt)) + return false ; + // lo porto nel riferimento globale + pGeoPnt->ToGlob( frFrame) ; + Point3d pt = pGeoPnt->GetPoint() ; + ON_Point* onPt = new ON_Point( ConvertPoint( pt)) ; + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onPt, nLayer, sName, cCol) ; ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportSrfBz( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + + //MANCA DA IMPLEMENTARE IL TRIM DELLE SUPERFICI!!///////////////////////////////////////////////////////////////////////////////////////////////////// + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pSrfBz( GetSurfBezier( pGeoObj->Clone())) ; + if ( IsNull( pSrfBz)) + return false ; + // lo porto nel riferimento globale + pSrfBz->ToGlob( frFrame) ; + bool bOk = true ; + int nDegU, nDegV, nSpanU, nSpanV ; + bool bRat = false ; + bool bTrimmed = false ; + pSrfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ; + int nCPU = nDegU * nSpanU + 1 ; + int nCPV = nDegV * nSpanV + 1 ; + ON_NurbsSurface* onNurbsSurf = new ON_NurbsSurface( 3, bRat, nDegU + 1, nDegV + 1, nCPU, nCPV) ; + for ( int u = 0 ; u < nCPU ; ++u) { + for ( int v = 0 ; v < nCPV ; ++v) { + Point3d ptCV = pSrfBz->GetControlPoint( u, v, &bOk) ; + if ( ! bRat) { + onNurbsSurf->SetCV( u, v, ConvertPoint( ptCV)) ; + } + else { + double dW = pSrfBz->GetControlWeight( u, v, &bOk) ; + onNurbsSurf->SetCV( u, v, ConvertPoint( ptCV * dW)) ; + onNurbsSurf->SetWeight( u, v, dW) ; + } + } + } + // imposto il vettore dei nodi in U + int nKnotCountU = nDegU + nCPU - 1 ; + double dKnot = 0 ; + // per costruzione nKnotCount é un multiplo di nDegU + for ( int u = 0 ; u < int ( nKnotCountU / nDegU) ; ++u) { + for ( int p = 0 ; p < nDegU ; ++p) + onNurbsSurf->SetKnot( 0, u * nDegU + p, dKnot) ; + ++dKnot ; + } + + // imposto il vettore dei nodi in V + int nKnotCountV = nDegV + nCPV - 1 ; + dKnot = 0 ; + // per costruzione nKnotCount é un multiplo di nDegU + for ( int v = 0 ; v < int ( nKnotCountV / nDegV) ; ++v) { + for ( int p = 0 ; p < nDegV ; ++p) + onNurbsSurf->SetKnot( 0, v * nDegV + p, dKnot) ; + ++dKnot ; + } + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onNurbsSurf, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportSTM( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pSrfTm ; + if ( pGeoObj->GetType() == SRF_TRIMESH) + pSrfTm.Set( GetSurfTriMesh( pGeoObj->Clone())) ; + else { + const ISurfFlatRegion* pSrfFr = GetSurfFlatRegion( pGeoObj) ; + const ISurfTriMesh* pSrfTm_ = pSrfFr->GetAuxSurf() ; + if ( pSrfTm_ == nullptr){ + return false ; + } + pSrfTm.Set( pSrfTm_->Clone()) ; + } + + if ( IsNull( pSrfTm)) + return false ; + + // lo porto nel frame globale + pSrfTm->ToGlob( frFrame) ; + + int nVertices = pSrfTm->GetVertexCount() ; + int nTriangles = pSrfTm->GetTriangleCount() ; + ON_Mesh* onMesh = new ON_Mesh ; + for ( int v = 0 ; v < nVertices ; ++v) { + Point3d pt ; pSrfTm->GetVertex( v, pt) ; + onMesh->SetVertex( v, ConvertPoint( pt)) ; + } + for ( int t = 0 ; t < nTriangles ; ++t) { + int nIdVert[3] ; pSrfTm->GetTriangle( t, nIdVert) ; + onMesh->SetTriangle( t, nIdVert[0], nIdVert[1], nIdVert[2]) ; + } + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onMesh, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +ON_ArcCurve* +Export3dm::ConvertCrvArc( const ICurveArc* pCrvArc) +{ + double dRad = pCrvArc->GetRadius() ; + Point3d ptCen ; + pCrvArc->GetCenterPoint( ptCen) ; + PtrOwner onArcCrv( new ON_ArcCurve()) ; + if ( ! pCrvArc->IsACircle()) { + Vector3d vtZ = pCrvArc->GetNormVersor() ; + Vector3d vtX, vtY ; + vtX = pCrvArc->GetStartVersor() ; + vtY = vtZ ^ vtX ; + double dAngDeg = pCrvArc->GetAngCenter() ; + ON_Plane onPlane( ConvertPoint( ptCen), ConvertVector( vtX), ConvertVector( vtY)) ; + onArcCrv.Set( new ON_ArcCurve( ON_Arc( onPlane, dRad, dAngDeg * DEGTORAD))) ; + } + else + onArcCrv.Set( new ON_ArcCurve ( ON_Circle( ConvertPoint( ptCen), dRad))) ; + return Release( onArcCrv) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportCrvArc( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pCrvArc( GetCurveArc( pGeoObj->Clone())) ; + if ( IsNull( pCrvArc)) + return false ; + // lo porto nel fram globale + pCrvArc->ToGlob( frFrame) ; + ON_ArcCurve* onArcCrv = ConvertCrvArc( pCrvArc) ; + if ( onArcCrv == nullptr) + return false ; + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onArcCrv, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +ON_NurbsCurve* +Export3dm::ConvertCrvBezier( const ICurveBezier* pCrvBz) +{ + // creo l'oggetto da esportare + int nDeg = pCrvBz->GetDegree() ; + int nCV = nDeg + 1 ; + PtrOwner onNurbsCrv( new ON_NurbsCurve( 3, // dim + pCrvBz->IsRational(), // bRat + nDeg + 1, // order = deg + 1 + nCV)) ; // numero di CP + // imposto i punti di controllo con gli eventuali pesi + if ( ! pCrvBz->IsRational()) { + bool bOk = true ; + for ( int i = 0 ; i < nCV ; ++i) { + ON_3dPoint onPt = ConvertPoint( pCrvBz->GetControlPoint( i, &bOk)) ; + onNurbsCrv->SetCV( i, onPt) ; + } + } + else { + bool bOk = true ; + for ( int i = 0 ; i < nCV ; ++i) { + ON_3dPoint onPt = ConvertPoint( pCrvBz->GetControlPoint( i, &bOk)) ; + double dWeight = pCrvBz->GetControlWeight( i, &bOk) ; + onNurbsCrv->SetCV( i, onPt * dWeight) ; + onNurbsCrv->SetWeight( i, dWeight) ; + } + } + // imposto il vettore dei nodi + int nKnotCount = nDeg + nCV - 1 ; + double dKnot = 0 ; + for ( int u = 0 ; u < int ( nKnotCount / nDeg) ; ++u) { + for ( int p = 0 ; p < nDeg ; ++p) + onNurbsCrv->SetKnot( u * nDeg + p, dKnot) ; + ++dKnot ; + } + + return Release( onNurbsCrv) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportCrvBezier( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pCrvBz( GetCurveBezier( pGeoObj->Clone())) ; + if ( IsNull( pCrvBz)) + return false ; + // lo porto nel riferimento globale + pCrvBz->ToGlob( frFrame) ; + ON_NurbsCurve* onNurbsCrv = ConvertCrvBezier( pCrvBz) ; + if ( onNurbsCrv == nullptr) + return false ; + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onNurbsCrv, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportCrvCompo( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pCrvCompo( GetCurveComposite( pGeoObj->Clone())) ; + if ( IsNull( pCrvCompo)) + return false ; + // lo porto nel riferimento globale + pCrvCompo->ToGlob( frFrame) ; + ON_PolyCurve* onPolyCrv = new ON_PolyCurve ; + for ( const ICurve* pCrv = pCrvCompo->GetFirstCurve() ; pCrv != nullptr ; pCrv = pCrvCompo->GetNextCurve()) { + GeoObjType type = pCrv->GetType() ; + switch ( type) { + case CRV_LINE : { + PtrOwner pCrvL( GetCurveLine( pCrv->Clone())) ; + if ( IsNull( pCrvL)) { + delete onPolyCrv ; + return false ; + } + ON_LineCurve* onLine = ConvertCrvLine( pCrvL) ; + if ( onLine == nullptr) { + delete onPolyCrv ; + return false ; + } + onPolyCrv->Append( onLine) ; + break ; + } + case CRV_ARC : { + PtrOwner pCrvArc( GetCurveArc( pCrv->Clone())) ; + if ( IsNull( pCrvArc)) { + delete onPolyCrv ; + return false ; + } + ON_ArcCurve* onArcCrv = ConvertCrvArc( pCrvArc) ; + if ( onArcCrv == nullptr) { + delete onPolyCrv ; + return false ; + } + onPolyCrv->Append( onArcCrv) ; + break ; + } + case CRV_BEZIER : { + PtrOwner pCrvBz( GetCurveBezier( pCrv->Clone())) ; + if ( IsNull( pCrvBz)) { + delete onPolyCrv ; + return false ; + } + ON_NurbsCurve* onNurbsCrv = ConvertCrvBezier( pCrvBz) ; + if ( onNurbsCrv == nullptr) { + delete onPolyCrv ; + return false ; + } + onPolyCrv->Append( onNurbsCrv) ; + break ; + } + default : break ; + } + } + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onPolyCrv, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +ON_LineCurve* +Export3dm::ConvertCrvLine( const ICurveLine* pCrvL) +{ + Point3d ptStart, ptEnd ; + pCrvL->GetStartPoint( ptStart) ; + pCrvL->GetEndPoint( ptEnd) ; + PtrOwner onCrvLine( new ON_LineCurve( ON_Line( ConvertPoint( ptStart), ConvertPoint( ptEnd)))) ; + return Release( onCrvLine) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ExportCrvLine( const string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) +{ + // recupero l'oggetto geometrico + const IGeoObj* pGeoObj = iIter.GetGeoObj() ; + if ( pGeoObj == nullptr) + return false ; + // verifico oggetto + PtrOwner pCrvL( GetCurveLine( pGeoObj->Clone())) ; + if ( IsNull( pCrvL)) + return false ; + // lo porto nel frame globale + pCrvL->ToGlob( frFrame) ; + ON_LineCurve* onCrvLine = ConvertCrvLine( pCrvL) ; + // aggiungo l'oggetto al modello + return AddObjectToModel( iIter, onCrvLine, nLayer, sName, cCol) ; +} + +//---------------------------------------------------------------------------- +bool +Export3dm::ScanGroup( const IGdbIterator& iIter, const int& nLayer) +{ + // creo un iteratore + PtrOwner pIter( CreateGdbIterator( iIter.GetGDB())) ; + if ( IsNull( pIter)) + return false ; + // scandisco il gruppo + bool bOk = true ; + for ( bool bNext = pIter->GoToFirstInGroup( iIter) ; + bNext ; + bNext = pIter->GoToNext()) { + if ( ! ExportObject( *pIter, nLayer)) + bOk = false ; + } + + return bOk ; +} diff --git a/Export3dm.h b/Export3dm.h new file mode 100644 index 0000000..0f4ddf8 --- /dev/null +++ b/Export3dm.h @@ -0,0 +1,72 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Export3dm.cpp Data : 21.09.23 Versione : +// Contenuto : Dichiarazione della classe ExportStl. +// +// +// +// Modifiche : 21.09.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#define NOMINMAX + +#include "/EgtDev/Include/EE3Export3dm.h" +#include "/EgtDev/Include/EGnWriter.h" +#include "/EgtDev/Include/EGkGeoObj.h" +#include "/EgtDev/Include/EGkGdbIterator.h" +#include "/EgtDev/Include/EGkFrame3d.h" +#include "/EgtDev/Include/EGkPoint3d.h" +#include "/EgtDev/Include/EGkCurveBezier.h" +#include "/EgtDev/Include/EGkCurveArc.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkSurfFlatRegion.h" +#include "/EgtDev/Extern/opennurbs/Include/opennurbs.h" +#include + +//---------------------------------------------------------------------------- +class Export3dm : public IExport3dm +{ + public : + virtual bool SetOptions( int nFilter) ; + virtual bool Export( IGeomDB* pGDB, int nId, const std::string& sFile) ; + + public : + Export3dm(void) : m_nFilter(EEXFLT_DEFAULT) { + CalcGroupFilter() ; + } + + private : + bool ExportObject( const IGdbIterator& iIter, const int& nLayer) ; + bool AddObjectToModel( const IGdbIterator& iIter, ON_Object* onObject, const int& nLayer, const std::string& sName, const Color& cCol, + ON_3dmObjectAttributes* pOnAttr = nullptr) ; + bool AddInfoToObject( const IGdbIterator& iIter, ON_Object* onObject) ; + bool ScanGroup( const IGdbIterator& iIter, const int& nLayer) ; + bool TestFilter( int nLev, int nMode, int nStat, bool bGroup = false) ; + std::wstring ConvertString( const std::string& sName) { return std::wstring( sName.begin(), sName.end()) ;} ; + ON_3dPoint ConvertPoint( const Point3d& pt) { return ON_3dPoint( pt.x, pt.y, pt.z) ;} ; + ON_3dVector ConvertVector( const Vector3d& vt) { return ON_3dVector( vt.x, vt.y, vt.z) ;} ; + ON_NurbsCurve* ConvertCrvBezier( const ICurveBezier* pCrvBz) ; + ON_ArcCurve* ConvertCrvArc( const ICurveArc* pCrvArc) ; + ON_LineCurve* ConvertCrvLine( const ICurveLine* pCrvL) ; + bool ExportPnt( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportSrfBz( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportSTM( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportCrvArc( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportCrvBezier( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportCrvCompo( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool ExportCrvLine( const std::string& sName, const IGdbIterator& iIter, const Frame3d& frFrame, const Color& cCol, const int& nLayer) ; + bool CalcGroupFilter( void) ; + + private : + int m_nFilter ; // filtro su livello, modo e stato, se l'oggeto da valutare è un oggetto geometrico + int m_nGroupFilter ; // filtro su livello, modo e stato, se l'oggetto da valutare è un gruppo + Writer m_Writer ; // scrittore di file di testo + ONX_Model m_model ; // modello opennurbs + std::map m_mLayer ; // mappa dei layer + std::map m_mMaterial ; // mappa dei materiali +} ; diff --git a/Import3dm.cpp b/Import3dm.cpp new file mode 100644 index 0000000..b90c85a --- /dev/null +++ b/Import3dm.cpp @@ -0,0 +1,1306 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Import3dm.cpp Data : 23.06.23 Versione : 2.5f1 +// Contenuto : Implementazione della classe per l'importazione di 3dm. +// +// +// +// Modifiche : 23.06.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "Import3dm.h" +#include "DllMain.h" +#include "/EgtDev/Include/EE3DllMain.h" +#include "/EgtDev/Include/EGnStringUtils.h" +#include "/EgtDev/Include/SELkKeyProc.h" +#include "/EgtDev/Include/EgtKeyCodes.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Include/EGkGeoPoint3d.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkArcSpecial.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkCurveBezier.h" +#include "/EgtDev/Include/EGkCurveAux.h" +#include "/EgtDev/Include/EGkSurfAux.h" +#include "/EgtDev/Include/EGkStmFromCurves.h" +#include "/EgtDev/Include/EGkSurfBezier.h" +#include "/EgtDev/Include/EGkStmFromTriangleSoup.h" +#include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EXeConst.h" +#include "/EgtDev/Include/EGkStringUtils3d.h" +#include "/EgtDev/Include/EGkExtText.h" +#include "/EgtDev/Include/EGkExtDimension.h" +#include "/EgtDev/Include/EGkVector3d.h" +#include "/EgtDev/Include/EGkGeoObjSave.h" +#include + +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 dTextHeight, double dExtLine, double dArrLen, double dTextDist, + bool bLenIsMM, int nDecDig, std::string sFont) +{ + // verifico il DB geometrico + if ( pGDB == nullptr) { + LOG_ERROR( GetEE3Logger(), "Import3dm : Error on GeomDB") + return false ; + } + m_pGDB = pGDB ; + + // verifico l'Id di gruppo + if ( ! m_pGDB->ExistsObj( nIdGroup)) { + LOG_ERROR( GetEE3Logger(), "Import3dm : Error on IdGroup") + return false ; + } + m_nIdGroup = nIdGroup ; + + ONX_Model model ; + + wstring widestr( sFile.begin(), sFile.end()) ; + + const wchar_t* sFileName = widestr.c_str() ; + FILE* archive_fp = ON::OpenFile( sFileName, L"rb") ; + if ( ! archive_fp) { + LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to open file.") ; + return false ; + } + + // create achive object from file pointer + ON_BinaryFile archive( ON::archive_mode::read3dm, archive_fp) ; + + // read the contents of the file into "model" + ON_TextLog dump ; + bool rc = model.Read( archive, &dump) ; + + if ( ! rc) + LOG_ERROR( GetEE3Logger(), "Import3dm : Unable to read file.") ; + + // close the file + ON::CloseFile( archive_fp) ; + + // LAYER + // creo i layer e i conto + ONX_ModelComponentIterator component_iterator_l( model, ON_ModelComponent::Type::Layer) ; + int nFirstId = 0 ; + + ON_UUID ON_nil_uuid = { 0,0,0,{ 0,0,0,0,0,0,0,0}} ; + int nLayDelCount = 0 ; + 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 + auto it_parent = it ; + // risalgo la gerarchia dei layer finché arrivo al primo layer e aggiungo tutti i nomi al nome del sottolayer + wstring ws = wstring(onLayer->Name()) ; + string sName(ws.begin(), ws.end()) ; + while ( ON_UuidCompare( uuidParent, ON_nil_uuid) ) {// ON_UuidCompare restituisce 0 se coincidono + const ON_Layer* onParentLayer = get<0>(it->second) ; + wstring wsParent = wstring( onParentLayer->Name()) ; + string sParentName( wsParent.begin(), wsParent.end()) ; + sName = sParentName + "_" + sName ; + uuidParent = onParentLayer->ParentId() ; + it = std::find_if(m_mLayer.begin(), m_mLayer.end(), + [uuidParent](pair< int, tuple> x){ return !ON_UuidCompare( get<1>(get<1>(x)), uuidParent) ;}); + } + + // 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 nIdLayer = m_pGDB->AddGroup( GDB_ID_NULL, nIdGroup, GLOB_FRM) ; + if ( nFirstId == 0) + nFirstId = nIdLayer ; + int nIndex = onLayer->Index() ; + m_mLayer.insert( std::make_pair( nIdLayer, std::make_tuple(onLayer, uuid, nIndex, false))) ; + m_pGDB->SetName( nIdLayer, sName) ; + } + + // OGGETTI GEOMETRICI + ONX_ModelComponentIterator component_iterator( model, ON_ModelComponent::Type::ModelGeometry) ; + + // se non riesco a convertire un oggetto, lo scarto e incremento il contatore del suo tipo nel dizionario error_count + int nId ; + int nCount = 0 ; + for( const ON_ModelComponent* mc = component_iterator.FirstComponent() ; mc != nullptr ; mc = component_iterator.NextComponent()) { + ++ nCount ; + const ON_ModelGeometryComponent* mgc = ON_ModelGeometryComponent::Cast( mc) ; + const ON_Object* oGeometry = mgc->Geometry( nullptr) ; + // individuo a che layer appartiene l'oggetto + const ON_3dmObjectAttributes* attributes = mgc->Attributes( nullptr) ; + int nLayer = attributes->m_layer_index ; + if ( nLayer < 0) + nLayer = 0 ; + else { + // prendo l'indice che il layer ha nel nostro GDB + auto it = std::find_if(m_mLayer.begin(), m_mLayer.end(), + [nLayer](pair< int, tuple> x){ return get<2>(get<1>(x)) == nLayer ;}); + nLayer = it->first ; + } + // recupero il colore dell'oggetto + ON_Color onCol ; + switch ( attributes->ColorSource()) { + case ON::color_from_parent: // come se fosse from_layer + case ON::color_from_layer : { + onCol = get<0>(m_mLayer[nLayer])->Color() ; + break ; + } + case ON::color_from_object: { + onCol = attributes->m_color ; + break ; + } + case ON::color_from_material: { + // non gestito + break ; + } + } + + Color cCol ; + // N.B. RHINO ha i valori di Alpha invertiti rispetto ai nostri, oltre che su una scala diversa! per loro 0 = opaco e 255 = trasparente + // per noi invece 0 = trasparente, 100 = opaco + cCol.Set( onCol.Red(), onCol.Green(), onCol.Blue(), int( abs( onCol.Alpha() - 255) / 2.55)) ; + // converto l'oggetto e lo aggiungo al GeomDB + ON::object_type type = oGeometry->ObjectType() ; + vector> vpGeoObj ; + switch ( type) { + case ON::object_type::point_object : { + const ON_Point* oPoint = ON_Point::Cast( oGeometry) ; + Point3d pt( ConvertPoint( *oPoint)) ; + // lo aggiungo al GeomDB nel layer corretto + PtrOwner 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) ; + PtrOwner pSurfTm( ConvertExtrusion( onExtrusion)) ; + if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) + vpGeoObj.emplace_back( Release( pSurfTm)) ; + else + m_mError_count["mesh"] += 1 ; + break ; + break ; + } + case ON::object_type::mesh_object :{ + const ON_Mesh* onMesh = ON_Mesh::Cast( oGeometry) ; + PtrOwner 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 = model.ComponentFromId( ON_ModelComponent::Type::DimStyle, onStyleId) ; + const ON_ModelComponent* mc = mcr.ModelComponent() ; + const ON_DimStyle* onDimStyle = ON_DimStyle::Cast( mc) ; + // converto l'oggetto + vpGeoObj = ConvertAnnotation( onAnnot, onDimStyle, dTextHeight, dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont) ; + break ; + } + // TO DO + // oggetto che definisce la zona dell'anteprima di stampa + // degli oggetti potrebbero essere definiti rispetto a questo frame + // + //case ON::object_type::detail_object: { + // const ON_DetailView* onDetail = ON_DetailView::Cast( oGeometry) ; + // ON_NurbsCurve onBoundary = onDetail->m_boundary ; + // ICurve* pCrv = ConvertCurve( &onBoundary) ; + // ON_3dmView onView = onDetail->m_view ; + // ON::view_type onViewType = onView.m_view_type ; + // error_count["detail"] += 1 ; + //} + default: { + m_mError_count["other"] += 1 ; + break ; + } + } + int nSubLayer = nLayer ; + if ((int) vpGeoObj.size() > 1) { + // creo un gruppo per mettere tutti gli oggetti del leader + nSubLayer = m_pGDB->AddGroup( GDB_ID_NULL, nLayer, GLOB_FRM) ; + } + for (int p = 0 ; p < (int) vpGeoObj.size() ; ++p) { + if ( ! IsNull( vpGeoObj[p]) && vpGeoObj[p]->IsValid() ) { + nId = m_pGDB->AddGeoObj( GDB_ID_NULL, nSubLayer, Release( vpGeoObj[p])) ; + m_pGDB->SetMaterial( nId, cCol) ; + } + } + } + + + // 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 ; +} + +//---------------------------------------------------------------------------- +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 ; + } + + // vettore dei nodi + DBLVECTOR vU ; + int nKnot = onNurbsCurve->KnotCount() ; + for ( int j = 0 ; j < nKnot ; ++j ) { + double dKnot = onNurbsCurve->Knot( j) ; + vU.push_back( dKnot) ; + } + nuCurve.vU = vU ; + nuCurve.bClosed = onNurbsCurve->IsClosed() ; + nuCurve.bPeriodic = onNurbsCurve->IsPeriodic() ; + nuCurve.bClamped = onNurbsCurve->IsClamped(2) ; + + // controllo relazione nodi - punti di controllo + int nU = int( nuCurve.vCP.size()) + nuCurve.nDeg - 1 ; + // se ho due nodi di troppo mi basta togliere il primo e l'ultimo per rendere la curva canonica + // se la curva è periodica posso renderla non periodica senza cambiare la forma della curva + if ( nU == int( nuCurve.vU.size()) + 2 || nuCurve.bPeriodic || ! nuCurve.bClamped) + NurbsCurveCanonicalize( nuCurve) ; + + // ora che ho riempito la Nurbs con tutti i dati la converto in Bezier + return NurbsToBezierCurve( nuCurve) ; + break ; + } + case ON::eCurveType::ctOnsurface :{ + const ON_CurveOnSurface* onCurveOnSurface = ON_CurveOnSurface::Cast( onCurve) ; + ON_NurbsCurve onNurbsCurve ; + onCurveOnSurface->GetNurbForm( onNurbsCurve) ; + return ConvertCurve( &onNurbsCurve) ; + break ; + } + case ON::eCurveType::ctProxy :{ + const ON_CurveProxy* onProxyCurve = ON_CurveProxy::Cast( onCurve) ; + ON_Curve* onCurve = onProxyCurve->DuplicateCurve() ; + return ConvertCurve( onCurve) ; + break ; + } + case ON::eCurveType::ctPolycurve : { + const ON_PolyCurve* onPolycurve = ON_PolyCurve::Cast( onCurve) ; + int nCurves = onPolycurve->Count() ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + for ( int i = 0 ; i < nCurves; ++i) { + ICurve* pCurveToAdd = nullptr ; + ON_Curve* onCurveToAdd = onPolycurve->SegmentCurve( i) ; + pCurveToAdd = ConvertCurve( onCurveToAdd) ; + pCrvCompo->AddCurve( pCurveToAdd) ; + } + return Release( pCrvCompo) ; + break ; + } + case ON::eCurveType::ctPolyline : { + const ON_PolylineCurve* onPolyline = ON_PolylineCurve::Cast( onCurve) ; + int nPoints = onPolyline->PointCount() ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + Point3d ptNew , ptOld( ConvertPoint(onPolyline->m_pline[0])) ; + for ( int i = 1 ; i < nPoints ; ++i ) { + ICurveLine* pCurveLine( CreateCurveLine()) ; + ptNew = ConvertPoint( onPolyline->m_pline[i]) ; + pCurveLine->Set( ptOld, ptNew) ; + pCrvCompo->AddCurve( pCurveLine) ; + ptOld = ptNew ; + } + return Release( pCrvCompo) ; + break ; + } + default : + break ; + } + return nullptr ; +} + +//---------------------------------------------------------------------------- +ISurf* +Import3dm::ConvertSurface( const ON_Surface* onSurf) +{ + if ( const ON_NurbsSurface* onNurbsSurface_ = ON_NurbsSurface::Cast( onSurf)) { + ON_NurbsSurface onNurbsSurface( *onNurbsSurface_) ; + SNurbsSurfData sNurbsSurf ; + sNurbsSurf.bClosedU = onNurbsSurface.IsClosed( 0) ; + sNurbsSurf.bClosedV = onNurbsSurface.IsClosed( 1) ; + sNurbsSurf.bPeriodicU = onNurbsSurface.IsPeriodic( 0) ; + sNurbsSurf.bPeriodicV = onNurbsSurface.IsPeriodic( 1) ; + sNurbsSurf.bClampedU = onNurbsSurface.IsClamped( 0, 2) ; + sNurbsSurf.bClampedV = onNurbsSurface.IsClamped( 1, 2) ; + sNurbsSurf.bRat = onNurbsSurface.IsRational() ; + sNurbsSurf.nDegU = onNurbsSurface.Degree( 0) ; + sNurbsSurf.nDegV = onNurbsSurface.Degree( 1) ; + sNurbsSurf.nCPU = onNurbsSurface.CVCount( 0) ; + sNurbsSurf.nCPV = onNurbsSurface.CVCount( 1) ; + PNTVECTOR vCPV( sNurbsSurf.nCPV) ; + sNurbsSurf.mCP.resize( sNurbsSurf.nCPU, vCPV) ; + DBLVECTOR vWV( sNurbsSurf.nCPV) ; + sNurbsSurf.mW.resize( sNurbsSurf.nCPU, vWV) ; + for ( int i = 0 ; i < sNurbsSurf.nCPU ; ++i) { + for ( int j = 0 ; j < sNurbsSurf.nCPV ; ++j) { + ON_4dPoint o4dPoint = onNurbsSurface.ControlPoint(i, j) ; + Point3d ptCP = ConvertPoint( o4dPoint) ; + sNurbsSurf.mCP[i][j] = ptCP ; + if ( sNurbsSurf.bRat) + sNurbsSurf.mCP[i][j] = ptCP / o4dPoint.w ; + else + sNurbsSurf.mCP[i][j] = ptCP ; + sNurbsSurf.mW[i][j] = o4dPoint.w ; + } + } + for ( int i = 0 ; i < onNurbsSurface.KnotCount(0) ; ++i ) + sNurbsSurf.vU.push_back( onNurbsSurface.Knot( 0, i)) ; + + for ( int j = 0 ; j < onNurbsSurface.KnotCount(1) ; ++j ) + sNurbsSurf.vV.push_back( onNurbsSurface.Knot( 1, j)) ; + + if ( sNurbsSurf.bPeriodicU || sNurbsSurf.bPeriodicV || ! sNurbsSurf.bClampedU || ! sNurbsSurf.bClampedV) + NurbsSurfaceCanonicalize( sNurbsSurf) ; + + return NurbsToBezierSurface( sNurbsSurf) ; + } + else if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurf)) { + // recupero i riferimenti del piano e li converto in oggetti nostri + Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ; + Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ; + Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ; + Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ; + ON_Interval on_inX = onPlaneSurface->Extents(0) ; + ON_Interval on_inY = onPlaneSurface->Extents(1) ; + Point3d pt0( on_inX[0], on_inY[0]) ; + Point3d pt1( on_inX[1], on_inY[0]) ; + Point3d pt2( on_inX[1], on_inY[1]) ; + Point3d pt3( on_inX[0], on_inY[1]) ; + + // costruisco la figura e la inserisco nel GDB + PtrOwner 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 ; + 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)) ; + 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, false)) ; + if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) + return Release( pSurfTm) ; + + // se fallisce questo tentativo di conversione allora recupero le curve e costruisco la superficie di Bezier + // in teoria dovrei farcela con uno dei due metodi precedenti + PtrOwner onpCrvEast( onSumSurface->IsoCurve(1, onIntDomain0[1])) ; + PtrOwner onpCrvNorth( onSumSurface->IsoCurve(0, onIntDomain1[1])) ; + // da implementare //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + } + else if ( const ON_SurfaceProxy* onSurfaceProxy = ON_SurfaceProxy::Cast( onSurf)) { + PtrOwner pSurf ; + // bool bTransposed = onSurfaceProxy->ProxySurfaceIsTransposed() ; + if ( const ON_BrepFace* onBrepFace = ON_BrepFace::Cast( onSurfaceProxy)) { + // uso la nurbs form + ON_NurbsSurface onNurbsSurface ; + int nOk = onBrepFace->GetNurbForm( onNurbsSurface) ; + if ( nOk != 0) + pSurf.Set( ConvertSurface( & onNurbsSurface)) ; + else { + // se non è riuscita la conversione in nurbs tengo la superficie originale + const ON_Surface* onSurfFace = onBrepFace->ProxySurface() ; + // qui devo applicare a mano le trasformazioni dalla superfice originale alla proxy + // la funzione getNurbsForm lo fa in automatico + pSurf.Set( ConvertSurface( onSurfFace)) ; + } + } + else if ( const ON_OffsetSurface* onOffsetSurface = ON_OffsetSurface::Cast( onSurfaceProxy)) { + //pSurf.Set( ConvertSurface( onOffsetSurface->BaseSurface())) ; + ON_NurbsSurface onNurbsSurface ; + int nOk = onOffsetSurface->GetNurbForm( onNurbsSurface) ; + if ( nOk != 0) + pSurf.Set( ConvertSurface( &onNurbsSurface)) ; + } + else + pSurf.Set( ConvertSurface( onSurfaceProxy->DuplicateSurface())) ; + return Release( pSurf) ; + } + + return nullptr ; +} + + +//---------------------------------------------------------------------------- +ISURFPOVECTOR +Import3dm::ConvertBrep( const ON_Brep* onBrep, const bool bForceTriMesh) +{ + // se le facce della Brep sono tutte trimesh restituisco un'unica trimesh + // se le facce sono delle NURBS restituisco un vettore di superfici Bezier + // se ForceTriMesh è true allora le Bezier vengono trasformate in trimesh e aggiunte alla zuppa + + ISURFPOVECTOR vSurf ; + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start()) + return vSurf ; + bool bSurfTm = false ; + int nFailedBFace = 0, nFailedTm = 0, nFailedFr = 0, nFailedBz = 0 ; + + for ( int i = 0 ; i < onBrep->m_F.Count() ; ++i) { + ON_BrepFace* onFace = onBrep->Face( i) ; + const ON_Surface* onSurface = onFace->SurfaceOf() ; + PtrOwner pSurf ; + if ( const ON_PlaneSurface* onPlaneSurface = ON_PlaneSurface::Cast( onSurface)) { + SurfFlatRegionByContours SfrCntr ; + for ( int k = 0 ; k < onFace->LoopCount() ; ++k) { + PtrOwner pCurve( ConvertBrepLoop( onFace->Loop( k))) ; + SfrCntr.AddCurve( Release( pCurve)) ; + } + pSurf.Set( SfrCntr.GetSurf()) ; + if ( ! IsNull( pSurf) && pSurf->IsValid()) { + // porto le coordinate dal riferimento del piano di trim alle coordinate globali + Point3d ptOrig = ConvertPoint( onPlaneSurface->m_plane.origin) ; + Vector3d vtX = ConvertVector( onPlaneSurface->m_plane.xaxis) ; + Vector3d vtY = ConvertVector( onPlaneSurface->m_plane.yaxis) ; + Vector3d vtZ = ConvertVector( onPlaneSurface->m_plane.Normal()) ; + Frame3d frPlane ; + frPlane.Set( ptOrig, vtX, vtY, vtZ) ; + pSurf->ToGlob( frPlane) ; + } + } + else + pSurf.Set( ConvertSurface( onFace)) ; + + if ( IsNull( pSurf) || ! pSurf->IsValid()) + ++ nFailedBFace ; + else { + + // se ho una trimesh o una flatregion la aggiungo alla zuppa, se è una bezier la aggiungo al vettore delle superfici + int nType = pSurf->GetType() ; + if ( nType == SRF_TRIMESH) { + bSurfTm = true ; + PtrOwner pSurfTm( GetSurfTriMesh( Release( pSurf))) ; + if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) + stmSoup.AddSurfTriMesh( *pSurfTm) ; + else + ++ nFailedTm ; + } + else if ( nType == SRF_FLATRGN) { + bSurfTm = true ; + PtrOwner pSurfFr( GetSurfFlatRegion( Release( pSurf))) ; + if ( ! IsNull( pSurfFr) && pSurfFr->IsValid()) + stmSoup.AddSurfTriMesh( *pSurfFr->GetAuxSurf()) ; + else + ++ nFailedFr ; + } + else if ( nType == SRF_BEZIER) { + PtrOwner pSurfBezNew( GetSurfBezier( Release( pSurf))) ; + // se ho più di un loop vuol dire che ho dei trim sulla faccia e quindi li aggiungo alla superficie di bezier + // prima della triangolazione + if ( ! IsNull( pSurfBezNew) && pSurfBezNew->IsValid()) { + ON_BrepFace* onFace = onBrep->Face( i) ; + SurfFlatRegionByContours SfrCntr ; + for ( int k = 0 ; k < onFace->LoopCount() ; ++k ) + SfrCntr.AddCurve( ConvertBrepLoop( onFace->Loop( k))) ; + + ISurfFlatRegion* sfrTrim = SfrCntr.GetSurf() ; + // questa regione di Trim deve essere riferita al rettangolo parametrico totale ( spaz param 1x1 -> regione trim 1000x1000) + // devo anche controllare che il sistema di riferimento dello spazio di trim totale sia giusto ( con l'angolo BottomLeft in (0,0) + //posizonato nel primo quadrante del piano XY) + double u0,u1,v0,v1 ; + onFace->GetDomain(0, &u0, &u1) ; + onFace->GetDomain(1, &v0, &v1) ; + double dScaleU = u1 - u0 ; + double dScaleV = v1 - v0 ; + Vector3d vToOrig( -u0, -v0, 0) ; + sfrTrim->Translate( vToOrig) ; + // se la superficie di partenza aveva vettori dei nodi non uniformi devo riscalare lo spazio parametrico in modo da renderli uniformi + // applicando così la trasformazione anche alle curve di trim. + ON_NurbsSurface onNurbsSurface ; + onFace->GetNurbForm( onNurbsSurface) ; + // rendo uniforme lo spazio parametrico nella direzione dei parametri che non lo sono + int nDegU, nDegV, nSpanU, nSpanV ; + bool bRat, bTrim ; + pSurfBezNew->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrim) ; + // devo rendere lo spazio parametrico uniforme solo se la superficie è trimmata, sennò non serve + // per capire se la superficie sia trimmata controllo che lo spazio parametrico trimmato non coincida con tutto lo spazio parametrico + PtrOwner pSurfParam( GetSurfFlatRegionRectangle( dScaleU - EPS_SMALL, dScaleV - EPS_SMALL)) ; + pSurfParam->Subtract( *sfrTrim) ; + if ( pSurfParam->IsValid()) + MakeUniform( &sfrTrim, onNurbsSurface, dScaleU, dScaleV) ; + else + sfrTrim->Scale( GLOB_FRM, nSpanU * SBZ_TREG_COEFF / dScaleU, nSpanV * SBZ_TREG_COEFF / dScaleV, 1) ; + pSurfBezNew->SetTrimRegion( *sfrTrim) ; + + if ( sfrTrim != nullptr) + delete sfrTrim ; + + if ( ! bForceTriMesh) + vSurf.emplace_back( Release( pSurfBezNew)) ; + else + stmSoup.AddSurfTriMesh( *(Release( pSurfBezNew)->GetAuxSurf())) ; + } + else { + ++nFailedBz ; + } + } + } + } + + if ( nFailedBFace != 0) { + string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBFace) + " Brep faces" ; + LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; + } + if ( nFailedTm != 0) { + string sOut = "Import3dm : Failed conversion of " + to_string( nFailedTm) + " trimesh belonging to a Brep" ; + LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; + } + if ( nFailedFr != 0) { + string sOut = "Import3dm : Failed conversion of " + to_string( nFailedFr) + " FlatRegion belonging to a Brep" ; + LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; + } + if ( nFailedBz != 0) { + string sOut = "Import3dm : Failed conversion of " + to_string( nFailedBz) + " NURBS belonging to a Brep" ; + LOG_ERROR( GetEE3Logger(), sOut.c_str()) ; + } + + if ( ! stmSoup.End()) + return vSurf ; + if ( bSurfTm || bForceTriMesh) + vSurf.emplace_back( stmSoup.GetSurf()) ; + + return vSurf ; +} + +//---------------------------------------------------------------------------- +bool +Import3dm::MakeUniform( ISurfFlatRegion** sfr, ON_NurbsSurface onNurbsSurface, double dScaleU, double dScaleV) +{ + // riscalo le superfici prima di effettuare una serie di operazioni di collage + (*sfr)->Scale( GLOB_FRM, SBZ_TREG_COEFF, SBZ_TREG_COEFF, 1) ; + bool bRescaledU = false ; + bool bRescaledV = false ; + int nSpanU = 1, nSpanV = 1 ; + PtrOwner sfr_rescaled( CreateSurfFlatRegion()) ; + for ( int nDir = 0 ; nDir <= 1 ; ++ nDir) { + // vettore dei nodi + DBLVECTOR vU ; + int nExtraKnots = 0 ; + // se la superficie è con deg > 1, periodica, clamped o unclamped devo tagliare Deg - 1 nodi all'estremo interessato + if ( onNurbsSurface.Degree(nDir) > 1 || onNurbsSurface.IsPeriodic( nDir)) { + nExtraKnots = onNurbsSurface.Degree( nDir) - 1 ; + } + for ( int i = nExtraKnots ; i < onNurbsSurface.KnotCount( nDir) - nExtraKnots ; ++i ) { + double dKnot = onNurbsSurface.Knot( nDir, i) * SBZ_TREG_COEFF ; + // lo aggiungo solo se è diverso dal precedente + if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL || dKnot < vU.back() - EPS_SMALL) + vU.push_back( dKnot) ; + } + nDir == 0 ? nSpanU = (int)vU.size() - 1 : nSpanV = (int)vU.size() - 1 ; + // controllo se il vettore dei nodi è uniforme + int a = 0, b = 1 ; + double d0 = abs( vU[b] - vU[a]), d1 = d0 ; + // il vettore è uniforme quando la distanza tra nodi consecutivi è sempre zero o un valore costante + while ( b < (int)vU.size() && ( ( d1 < d0 + EPS_SMALL && d1 > d0 - EPS_SMALL) || d1 < EPS_SMALL)) { + a = b ; + ++b ; + if ( b < (int)vU.size()) + d1 = abs( vU[b] - vU[a]) ; + } + if ( b != (int)vU.size()) { + nDir == 0 ? bRescaledU = true : bRescaledV = true ; + sfr_rescaled.Set( CreateSurfFlatRegion()) ; + if ( IsNull( sfr_rescaled)) + return false ; + for ( int p = 0 ; p < (int)vU.size() - 1 ; ++p) { + PtrOwner pSfr_copy( (*sfr)->Clone()) ; + if ( IsNull( pSfr_copy)) + return false ; + double dLenStrip = abs( vU[p+1] - vU[p]) ; + if ( dLenStrip < EPS_SMALL) + continue ; + // creo la maschera per tagliare la superficie originale e ottenere una striscia + PtrOwner pSfrTrim( CreateSurfFlatRegion()) ; + + // ricavo la maschera del trim, con cui poi farò l'intersezione con la sfr iniziale + Vector3d vtTrim ; + if ( nDir == 0) { + pSfrTrim.Set( GetSurfFlatRegionRectangle( dLenStrip, dScaleV * SBZ_TREG_COEFF + 2)) ; + vtTrim.Set( abs(vU[p] - vU.front()), - 1, 0) ; + } + else{ + pSfrTrim.Set( GetSurfFlatRegionRectangle( dScaleU * SBZ_TREG_COEFF + 2, dLenStrip)) ; + vtTrim.Set( - 1, abs(vU[p] - vU.front()), 0) ; + } + pSfrTrim->Translate( vtTrim) ; + + if ( ! pSfr_copy->Intersect( *pSfrTrim)) + return false ; + + // aggiungo la nuova striscia solo se è valida + if ( pSfr_copy->IsValid() ) { + if ( nDir == 0) + pSfr_copy->Scale( GLOB_FRM, SBZ_TREG_COEFF / dLenStrip, 1, 1) ; + else + pSfr_copy->Scale( GLOB_FRM, 1, SBZ_TREG_COEFF / dLenStrip, 1) ; + + // prima di riunire la striscia al resto devo traslarla sul bordo destro della superificie che sto ricostruendo + + Point3d pt ; + nDir == 0 ? pt.Set( abs(vU[p] - vU.front()), 0, 0) : pt.Set( 0,abs(vU[p] - vU.front()), 0) ; + if ( nDir == 0) + pt.Scale( GLOB_FRM, SBZ_TREG_COEFF / dLenStrip, 1, 1) ; + else + pt.Scale( GLOB_FRM, 1, SBZ_TREG_COEFF / dLenStrip, 1) ; + + Vector3d vtJoin ; + if ( nDir == 0) + vtJoin.Set( p * SBZ_TREG_COEFF - pt.x, 0, 0) ; + else + vtJoin.Set( 0, p * SBZ_TREG_COEFF - pt.y, 0) ; + pSfr_copy->Translate( vtJoin) ; + if ( sfr_rescaled->IsValid()) { + if ( ! sfr_rescaled->Add( *pSfr_copy)) + return false ; + } + else + sfr_rescaled.Set( pSfr_copy) ; + } + } + if ( nDir == 0) { + dScaleU = (int)vU.size() - 1 ; + if ( sfr_rescaled->IsValid()) + *sfr = Release( sfr_rescaled) ; + } + else + dScaleV = (int)vU.size() - 1 ; + } + } + + if ( ! IsNull( sfr_rescaled) && sfr_rescaled->IsValid()) + *sfr = Release( sfr_rescaled) ; + + if ( ! bRescaledU && ! bRescaledV) + ( *sfr)->Scale( GLOB_FRM, nSpanU / dScaleU, nSpanV / dScaleV, 1) ; + else if ( bRescaledU && ! bRescaledV) + ( *sfr)->Scale( GLOB_FRM, 1, nSpanV / dScaleV, 1) ; + else if ( ! bRescaledU && bRescaledV) + ( *sfr)->Scale( GLOB_FRM, nSpanU / dScaleU, 1, 1) ; + + return true ; +} + + +//---------------------------------------------------------------------------- +ICurve* +Import3dm::ConvertBrepLoop( const ON_BrepLoop* onBrepLoop) +{ + int nTrim = onBrepLoop->TrimCount() ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return nullptr ; + for ( int i = 0 ; i < nTrim ; ++i) { + ON_BrepTrim* onBrepTrim = onBrepLoop->Trim( i) ; + ON_CurveProxy* onCurveProxy = ON_CurveProxy::Cast( onBrepTrim); + pCrvCompo->AddCurve( ConvertCurve( onCurveProxy)) ; + } + return Release( pCrvCompo) ; +} + +//---------------------------------------------------------------------------- +ISurfTriMesh* +Import3dm::ConvertExtrusion( const ON_Extrusion* onExtrusion) +{ + Point3d ptStart( ConvertPoint( onExtrusion->PathStart())) ; + Point3d ptEnd( ConvertPoint( onExtrusion->PathEnd())) ; + Frame3d frRail ; + frRail.Set( ptStart, Z_AX) ; + ON_SimpleArray onSaProfile ; + int nProfiles = onExtrusion->GetProfileCurves( onSaProfile) ; + Vector3d vDir = ptEnd - ptStart ; + int nIsCapped = onExtrusion->IsCapped() ; // 0: no or profile is open /1: bottom cap( ptEnd) /2: top cap( ptStart) /3: both ends capped. + PtrOwner pSurfTm( CreateSurfTriMesh()) ; + if ( IsNull(pSurfTm)) + return nullptr ; + // creo la superficie a partire dalle curve + CICURVEPVECTOR vCrvProfile ; + for (int i = 0 ; i < nProfiles ; ++i ) { + const ON_Curve* onCurve = onSaProfile[i] ; + PtrOwner pCurve( ConvertCurve( onCurve)) ; + if ( IsNull(pCurve) || ! pCurve->IsValid()) { + m_mError_count["extrusion"] += 1 ; + break ; + } + pCurve->ToGlob( frRail) ; + vCrvProfile.emplace_back( Release(pCurve)) ; + } + + // se l'estrusione è capped sia sopra che sotto uso la funzione *byRegionExtrusion + if ( nIsCapped == 3) { + pSurfTm.Set( GetSurfTriMeshByRegionExtrusion( vCrvProfile, vDir)) ; + } + else { + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start()) + return nullptr ; + for ( int i = 0 ; i < (int)vCrvProfile.size() ; ++i ) + stmSoup.AddSurfTriMesh( *GetSurfTriMeshByExtrusion( vCrvProfile[i], vDir, false)) ; + + // controllo se la superficie è capped solo sopra o sotto ed eventualmente aggiungo alla trimesh la superficie adeguata + if ( nIsCapped != 0) { + PtrOwner pSurfTmCap( GetSurfTriMeshByRegion( vCrvProfile)) ; + if ( ! IsNull( pSurfTmCap) && pSurfTmCap->IsValid()) { + // se capped sopra traslo la trimeshregion + if ( nIsCapped == 1) + pSurfTmCap->Translate(vDir) ; + // sennò la aggiungo direttamente + stmSoup.AddSurfTriMesh( *pSurfTmCap) ; + } + } + if ( ! stmSoup.End()) + return nullptr ; + pSurfTm.Set( GetSurfTriMesh( stmSoup.GetSurf())) ; + } + + for ( int k = 0 ; k < (int)vCrvProfile.size() ; ++k) { + if ( vCrvProfile[k] != nullptr) + delete vCrvProfile[k] ; + } + + if ( ! IsNull( pSurfTm) && pSurfTm->IsValid()) + return Release( pSurfTm) ; + else { + // se non sono riuscito a creare la superficie per qualche motivo, allora tento una conversione con gli strumenti di OPENURBS prima + // di convertire la superficie + //// CONVERSIONE DELL'EXTRUSION AD UN'ALTRA SUPERFICIE RHINO PRIMA DI ESSERE CONVERTITA + ON_Object* onObject = nullptr ; + ISurf* pSurf = nullptr ; + PtrOwner 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) ; + } + } + } + pSurfTm->AdjustTopology() ; + return Release( pSurfTm) ; +} + +//---------------------------------------------------------------------------- +std::vector> +Import3dm::ConvertAnnotation( const ON_Annotation* onAnnot, const ON_DimStyle* onDimStyle, double dTextHeight, double dExtLine, double dArrLen, double dTextDist, + bool bLenIsMM, int nDecDig, std::string sFont) +{ + // TO DO + // la posizione è da correggere se le annotazioni sono presenti nell'anteprima di stampa + // ( dovrebbe esserci nel modello un oggetto detail che ne definisce l'impaginazione) + vector> vpObj ; + ON::AnnotationType onAnnType = onAnnot->Type() ; + switch( onAnnType) { + case ON::AnnotationType::Text : { + const ON_Text* onText = ON_Text::Cast( onAnnot) ; + ON_wString wsText = onText->PlainText() ; + std::wstring ws( wsText) ; + std::string str( ws.begin(), ws.end()) ; + ON_Plane onPlane = onText->Plane() ; + Point3d ptOrig = ConvertPoint( onPlane.origin) ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Vector3d vtDir = ConvertVector( onText->HorizontalDirection()) ; + PtrOwner tText( CreateExtText()) ; + + tText->Set( ptOrig, vtN, vtDir, str, sFont, false, dTextHeight) ; + if ( ! IsNull( tText) && tText->IsValid()) { + vpObj.emplace_back( Release( tText)) ; + return vpObj ; + } + else + m_mError_count["annotation"] += 1 ; + break ; + } + case ON::AnnotationType::Leader : { + const ON_Leader* onLeader = ON_Leader::Cast( onAnnot) ; + ON_wString wsText = onLeader->PlainText() ; + std::wstring ws( wsText) ; + std::string str( ws.begin(), ws.end()) ; + ON_Plane onPlane = onAnnot->Plane() ; + Point3d ptOrig = ConvertPoint( onPlane.origin) ; + Vector3d vtX = ConvertVector( onPlane.xaxis) ; + Vector3d vtY = ConvertVector( onPlane.yaxis) ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Vector3d vtDir = ConvertVector( onAnnot->HorizontalDirection()) ; + ON_2dPoint on2dPoint ; + double dScale = onLeader->DimScale( onDimStyle) ; + onLeader->GetTextPoint2d( onDimStyle, dScale, on2dPoint) ; + Point3d ptTextPoint( on2dPoint.x, on2dPoint.y) ; + Frame3d frPlane ; + frPlane.Set( ptOrig, vtX, vtY,vtN) ; + ptTextPoint.ToGlob( frPlane) ; + PtrOwner tText( CreateExtText()) ; + tText->Set( ptTextPoint, vtN, vtDir, str, sFont, false, dTextHeight) ; + //aggiungo al gruppo: testo, linea e landing + if ( ! IsNull( tText) && tText->IsValid()) + vpObj.emplace_back( Release( tText)) ; + else + break ; + const ON_Curve* onCurve = onLeader->Curve( onDimStyle) ; + PtrOwner pCurve( ConvertCurve( onCurve)) ; + if ( ! IsNull( pCurve) && pCurve->IsValid()) { + vpObj.emplace_back( Release( pCurve)) ; + } + else { + vpObj.clear() ; + break ; + } + if ( onLeader->LeaderHasLanding( onDimStyle)) { + ON_Line onLine ; + onLeader->LandingLine2d( onDimStyle, dScale, onLine) ; + Point3d ptStart = ConvertPoint(onLine.from) ; + Point3d ptEnd = ConvertPoint(onLine.to) ; + PtrOwner pCrvL( CreateCurveLine()) ; + pCrvL->Set( ptStart, ptEnd) ; + if ( ! IsNull( pCrvL) && pCrvL->IsValid()) { + pCrvL->ToGlob( frPlane) ; + vpObj.emplace_back( Release( pCrvL)) ; + } + else { + vpObj.clear() ; + break ; + } + } + break ; + } + case ON::AnnotationType::Aligned : + case ON::AnnotationType::Rotated : { + const ON_DimLinear* onDimLin = ON_DimLinear::Cast( onAnnot) ; + // recupero tutti i dati della quota + ON_3dPoint onPt1, onPt2, onPtAr1, onPtAr2, onPtDimLine, onPtText ; + onDimLin->Get3dPoints( &onPt1, &onPt2, &onPtAr1, &onPtAr2, &onPtDimLine, &onPtText) ; + double dAngDeg = onDimLin->TextRotationRadians() * RADTODEG ; // rotazione del testo rispetto alla direzione orizzontale + ON_Plane onPlane = onDimLin->Plane() ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Vector3d vtDir = ConvertPoint(onPt2) - ConvertPoint(onPt1) ; + if ( ! vtDir.Normalize() || + ! vtDir.Rotate( vtN, dAngDeg)) + break ; + Point3d ptP1( ConvertPoint( onPt1)) ; + Point3d ptP2( ConvertPoint( onPt2)) ; + Point3d ptPDimL( ConvertPoint( onPtDimLine)) ; + + // creo la quota + PtrOwner pDim( CreateExtDimension()) ; + if ( onAnnType == ON::AnnotationType::Aligned) { + if ( IsNull( pDim ) || + ! pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) || + ! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, V_NULL, "<>")) + break ; + } + else if ( onAnnType == ON::AnnotationType::Rotated){ + if ( IsNull( pDim ) || + ! pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) || + ! pDim->SetLinear( ptP1, ptP2, ptPDimL, vtN, vtDir, "<>")) + break ; + } + + // inserisco la quota nel DB + if ( ! IsNull( pDim) && pDim->IsValid()) { + vpObj.emplace_back( Release( pDim)) ; + return vpObj ; + } + else + break ; + } + case ON::AnnotationType::Angular : + case ON::AnnotationType::Angular3pt : { + // recupero tutti i dati della quota + const ON_DimAngular* onDimAng = ON_DimAngular::Cast( onAnnot) ; + ON_3dPoint onPtCen, onPt1, onPt2, onPtAr1, onPtAr2, onPtDimLine, onPtText ; + onDimAng->Get3dPoints( &onPtCen, &onPt1, &onPt2, &onPtAr1, &onPtAr2, &onPtDimLine, &onPtText) ; + ON_Plane onPlane = onDimAng->Plane() ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Point3d ptCen( ConvertPoint( onPtCen)) ; + Point3d ptP1( ConvertPoint( onPt1)) ; + Point3d ptP2( ConvertPoint( onPt2)) ; + Point3d ptPDimL( ConvertPoint( onPtDimLine)) ; + + // creo la quota + PtrOwner pDim( CreateExtDimension()) ; + if ( ! IsNull( pDim) && + pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) && + pDim->SetAngular( ptP1, ptCen, ptP2, ptPDimL, vtN, "<>") && + pDim->IsValid()) { + vpObj.emplace_back( Release( pDim)) ; + return vpObj ; + } + else + break ; + } + case ON::AnnotationType::Radius : { + const ON_DimRadial* onDimRad = ON_DimRadial::Cast( onAnnot) ; + ON_3dPoint onPtCen, onPt1, onPt2, onPtDim ; + onDimRad->Get3dPoints( &onPtCen, &onPtDim, &onPt1, &onPt2) ; + ON_Plane onPlane = onDimRad->Plane() ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Point3d ptCen( ConvertPoint( onPtCen)) ; + Point3d ptDim( ConvertPoint( onPtDim)) ; + + // creo la quota + PtrOwner pDim( CreateExtDimension()) ; + if ( ! IsNull( pDim ) && + pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) && + pDim->SetRadial( ptCen, ptDim, vtN, "<>")) { + vpObj.emplace_back( Release( pDim)) ; + return vpObj ; + } + else + break ; + } + case ON::AnnotationType::Diameter : { + const ON_DimRadial* onDimRad = ON_DimRadial::Cast( onAnnot) ; + ON_3dPoint onPtCen, onPt1, onPt2, onPtDim ; + onDimRad->Get3dPoints( &onPtCen, &onPtDim, &onPt1, &onPt2) ; + ON_Plane onPlane = onDimRad->Plane() ; + Vector3d vtN = ConvertVector( onPlane.Normal()) ; + Point3d ptCen( ConvertPoint( onPtCen)) ; + Point3d ptDim( ConvertPoint( onPtDim)) ; + // creo la quota + PtrOwner pDim( CreateExtDimension()) ; + if ( ! IsNull( pDim ) || + pDim->SetStyle( dExtLine, dArrLen, dTextDist, bLenIsMM, nDecDig, sFont, dTextHeight) || + pDim->SetDiametral( ptCen, ptDim, vtN, "<>")) { + vpObj.emplace_back( Release( pDim)) ; + return vpObj ; + } + else + break ; + } + default : + break ; + } + + m_mError_count["annotation"] += 1 ; + return vpObj ; +} diff --git a/Import3dm.h b/Import3dm.h new file mode 100644 index 0000000..27fe6b3 --- /dev/null +++ b/Import3dm.h @@ -0,0 +1,62 @@ +//---------------------------------------------------------------------------- +// EgalTech 2023 +//---------------------------------------------------------------------------- +// File : Import3dm.h Data : 23.06.23 Versione : 2.5f1 +// Contenuto : Dichiarazione della classe Import3dm. +// +// +// +// Modifiche : 23.06.23 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EE3Import3dm.h" +#include "/EgtDev/Include/EGkSurfTriMesh.h" +#include "/EgtDev/Include/EGkSurfFlatRegion.h" +#include "/EgtDev/Include/EGkCurve.h" +#include "/EgtDev/Include/EGkGeoObj.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Extern/opennurbs/Include/opennurbs.h" +#include +#include + +//---------------------------------------------------------------------------- +class Import3dm : public IImport3dm +{ + public : + bool Import( const std::string& sFile, IGeomDB* pGDB, int nIdGroup, + double dTextHeight = 2.0, double dExtLine = 5.0, double dArrLen = 5.0, double dTextDist = 2.0, + bool bLenIsMM = true, int nDecDig = -2, std::string sFont = "ModernPropS.Nfe") override ; + + private : + Point3d ConvertPoint( const ON_Point& onPoint) + { return Point3d( onPoint.point.x, onPoint.point.y, onPoint.point.z) ; } ; + Point3d ConvertPoint( const ON_3dPoint& on3dPoint) + { return Point3d( on3dPoint.x, on3dPoint.y, on3dPoint.z) ; } ; + Point3d ConvertPoint( const ON_4dPoint& on4dPoint) + { return Point3d( on4dPoint.x, on4dPoint.y, on4dPoint.z) ; } ; + Point3d ConvertPoint( const ON_3fPoint& on3fPoint) + { return Point3d( on3fPoint.x, on3fPoint.y, on3fPoint.z) ; } ; + Vector3d ConvertVector( const ON_3dVector& onVector) + { return Vector3d( onVector.x, onVector.y, onVector.z) ; } ; + Vector3d ConvertVector( const ON_2dVector& onVector) + { return Vector3d( onVector.x, onVector.y, 0) ; } ; + ICurve* ConvertCurve( const ON_Curve* onCurve) ; + ISurf* ConvertSurface( const ON_Surface* onSurf) ; + ISurfTriMesh* ConvertExtrusion( const ON_Extrusion* onExtrusion) ; + ISurfTriMesh* ConvertMesh( const ON_Mesh* onMesh) ; + std::vector> ConvertAnnotation( const ON_Annotation* onAnnot, const ON_DimStyle* onDimStyle, double dTextHeight, double dExtLine, double dArrLen, double dTextDist, + bool bLenIsMM, int nDecDig, std::string sFont) ; + ISURFPOVECTOR ConvertBrep( const ON_Brep* onBrep, const bool bForceTriMesh) ; + ICurve* ConvertBrepLoop( const ON_BrepLoop* onBrepLoop) ; + bool MakeUniform( ISurfFlatRegion** sfr, ON_NurbsSurface onNurbsSurface, double dScaleU, double dScaleV) ; + + private : + IGeomDB* m_pGDB ; + int m_nIdGroup ; + std::map< int, std::tuple> m_mLayer ; // mappa dei layer con id nel GDB e l'uuid nel modello 3dm, un int per l'indice del layer nel model e un bool che indica la presenza di sottolayer + std::map< std::string, int> m_mError_count ; +} ; \ No newline at end of file diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..c7d8ded Binary files /dev/null and b/resource.h differ diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 0000000..b3f9c87 --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : file di origine che include solo le inclusioni standard +// EgtExchange.pch sarà l'intestazione precompilata +// stdafx.obj conterrà le informazioni sui tipi precompilati + +#include "stdafx.h" + +// TODO: fare riferimento alle intestazioni aggiuntive necessarie in STDAFX.H +// e non in questo file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..64428d6 --- /dev/null +++ b/stdafx.h @@ -0,0 +1,37 @@ +// stdafx.h : file di inclusione per file di inclusione di sistema standard +// o file di inclusione specifici del progetto utilizzati di frequente, ma +// modificati raramente +// + +#pragma once + +#include "/EgtDev/Include/EgtTargetVer.h" + +#include +#include +#include +#include + +// in Debug riconoscimento memory leakage +#if defined( _DEBUG) + #define _CRTDBG_MAP_ALLOC + #include + #include +#endif + +// in Debug controllo iteratori +#if defined( _DEBUG) + #define _SECURE_SCL 1 +#else + #define _SECURE_SCL 0 +#endif + +#include "/EgtDev/Include/EgtLibVer.h" + +#pragma comment(lib, EGTLIBDIR "EgtGeneral" EGTLIBVER ".lib") +#pragma comment(lib, EGTLIBDIR "EgtNumKernel" EGTLIBVER ".lib") +#pragma comment(lib, EGTLIBDIR "EgtGeomKernel" EGTLIBVER ".lib") +#pragma comment(lib, EGTLIBDIR "SEgtLock" EGTLIBVER ".lib") +#pragma comment(lib, EGTEXTDIR "/opennurbs/Lib/opennurbs_public" EGTLIBVER ".lib") + +