2018-06-04 17:27:33 +02:00
#ifdef HAS_WIN10SDK
2018-06-04 21:22:42 +02:00
#ifndef NOMINMAX
# define NOMINMAX
#endif
2018-11-08 20:18:40 +01:00
// Windows Runtime
#include <roapi.h>
// for ComPtr
#include <wrl/client.h>
// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
#include <winrt/robuffer.h>
#include <winrt/windows.storage.provider.h>
#include <winrt/windows.graphics.printing3d.h>
2018-06-04 17:27:33 +02:00
#include "FixModelByWin10.hpp"
2018-06-06 15:19:06 +02:00
#include <atomic>
#include <chrono>
2018-06-04 17:27:33 +02:00
#include <cstdint>
2018-06-06 15:19:06 +02:00
#include <condition_variable>
#include <exception>
#include <string>
2018-06-04 21:22:42 +02:00
#include <thread>
2018-06-06 15:19:06 +02:00
#include <boost/filesystem.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/nowide/cstdio.hpp>
2018-06-04 21:22:42 +02:00
#include "libslic3r/Model.hpp"
#include "libslic3r/Print.hpp"
2020-06-24 09:20:04 +02:00
#include "libslic3r/PresetBundle.hpp"
2018-06-04 21:22:42 +02:00
#include "libslic3r/Format/3mf.hpp"
#include "../GUI/GUI.hpp"
2018-11-26 14:41:58 +01:00
#include "../GUI/I18N.hpp"
2018-06-04 21:22:42 +02:00
2018-06-06 15:19:06 +02:00
#include <wx/msgdlg.h>
2018-06-04 21:22:42 +02:00
#include <wx/progdlg.h>
2018-06-04 17:27:33 +02:00
extern "C" {
// from rapi.h
typedef HRESULT ( __stdcall * FunctionRoInitialize )( int );
typedef HRESULT ( __stdcall * FunctionRoUninitialize )();
typedef HRESULT ( __stdcall * FunctionRoActivateInstance )( HSTRING activatableClassId , IInspectable ** instance );
typedef HRESULT ( __stdcall * FunctionRoGetActivationFactory )( HSTRING activatableClassId , REFIID iid , void ** factory );
// from winstring.h
typedef HRESULT ( __stdcall * FunctionWindowsCreateString )( LPCWSTR sourceString , UINT32 length , HSTRING * string );
typedef HRESULT ( __stdcall * FunctionWindowsDelteString )( HSTRING string );
}
2018-06-04 21:22:42 +02:00
namespace Slic3r {
2018-06-04 17:27:33 +02:00
HMODULE s_hRuntimeObjectLibrary = nullptr ;
FunctionRoInitialize s_RoInitialize = nullptr ;
FunctionRoUninitialize s_RoUninitialize = nullptr ;
FunctionRoActivateInstance s_RoActivateInstance = nullptr ;
FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr ;
FunctionWindowsCreateString s_WindowsCreateString = nullptr ;
FunctionWindowsDelteString s_WindowsDeleteString = nullptr ;
bool winrt_load_runtime_object_library ()
{
if ( s_hRuntimeObjectLibrary == nullptr )
s_hRuntimeObjectLibrary = LoadLibrary ( L "ComBase.dll" );
if ( s_hRuntimeObjectLibrary != nullptr ) {
s_RoInitialize = ( FunctionRoInitialize ) GetProcAddress ( s_hRuntimeObjectLibrary , "RoInitialize" );
s_RoUninitialize = ( FunctionRoUninitialize ) GetProcAddress ( s_hRuntimeObjectLibrary , "RoUninitialize" );
s_RoActivateInstance = ( FunctionRoActivateInstance ) GetProcAddress ( s_hRuntimeObjectLibrary , "RoActivateInstance" );
s_RoGetActivationFactory = ( FunctionRoGetActivationFactory ) GetProcAddress ( s_hRuntimeObjectLibrary , "RoGetActivationFactory" );
s_WindowsCreateString = ( FunctionWindowsCreateString ) GetProcAddress ( s_hRuntimeObjectLibrary , "WindowsCreateString" );
s_WindowsDeleteString = ( FunctionWindowsDelteString ) GetProcAddress ( s_hRuntimeObjectLibrary , "WindowsDeleteString" );
}
return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString ;
}
static HRESULT winrt_activate_instance ( const std :: wstring & class_name , IInspectable ** pinst )
{
HSTRING hClassName ;
HRESULT hr = ( * s_WindowsCreateString )( class_name . c_str (), class_name . size (), & hClassName );
if ( S_OK != hr )
return hr ;
hr = ( * s_RoActivateInstance )( hClassName , pinst );
( * s_WindowsDeleteString )( hClassName );
return hr ;
}
template < typename TYPE >
static HRESULT winrt_activate_instance ( const std :: wstring & class_name , TYPE ** pinst )
{
IInspectable * pinspectable = nullptr ;
HRESULT hr = winrt_activate_instance ( class_name , & pinspectable );
if ( S_OK != hr )
return hr ;
hr = pinspectable -> QueryInterface ( __uuidof ( TYPE ), ( void ** ) pinst );
pinspectable -> Release ();
return hr ;
}
static HRESULT winrt_get_activation_factory ( const std :: wstring & class_name , REFIID iid , void ** pinst )
{
HSTRING hClassName ;
HRESULT hr = ( * s_WindowsCreateString )( class_name . c_str (), class_name . size (), & hClassName );
if ( S_OK != hr )
return hr ;
hr = ( * s_RoGetActivationFactory )( hClassName , iid , pinst );
( * s_WindowsDeleteString )( hClassName );
return hr ;
}
template < typename TYPE >
static HRESULT winrt_get_activation_factory ( const std :: wstring & class_name , TYPE ** pinst )
{
return winrt_get_activation_factory ( class_name , __uuidof ( TYPE ), reinterpret_cast < void **> ( pinst ));
}
2018-06-06 15:19:06 +02:00
// To be called often to test whether to cancel the operation.
typedef std :: function < void () > ThrowOnCancelFn ;
2018-06-04 17:27:33 +02:00
template < typename T >
2018-06-06 15:19:06 +02:00
static AsyncStatus winrt_async_await ( const Microsoft :: WRL :: ComPtr < T > & asyncAction , ThrowOnCancelFn throw_on_cancel , int blocking_tick_ms = 100 )
2018-06-04 17:27:33 +02:00
{
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncInfo > asyncInfo ;
asyncAction . As ( & asyncInfo );
AsyncStatus status ;
// Ugly blocking loop until the RepairAsync call finishes.
//FIXME replace with a callback.
// https://social.msdn.microsoft.com/Forums/en-US/a5038fb4-b7b7-4504-969d-c102faa389fb/trying-to-block-an-async-operation-and-wait-for-a-particular-time?forum=vclanguage
for (;;) {
asyncInfo -> get_Status ( & status );
if ( status != AsyncStatus :: Started )
return status ;
2018-06-06 15:19:06 +02:00
throw_on_cancel ();
2018-06-04 17:27:33 +02:00
:: Sleep ( blocking_tick_ms );
}
}
static HRESULT winrt_open_file_stream (
const std :: wstring & path ,
ABI :: Windows :: Storage :: FileAccessMode mode ,
2018-06-06 15:19:06 +02:00
ABI :: Windows :: Storage :: Streams :: IRandomAccessStream ** fileStream ,
ThrowOnCancelFn throw_on_cancel )
2018-06-04 17:27:33 +02:00
{
// Get the file factory.
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: IStorageFileStatics > fileFactory ;
HRESULT hr = winrt_get_activation_factory ( L "Windows.Storage.StorageFile" , fileFactory . GetAddressOf ());
if ( FAILED ( hr )) return hr ;
// Open the file asynchronously.
HSTRING hstr_path ;
hr = ( * s_WindowsCreateString )( path . c_str (), path . size (), & hstr_path );
if ( FAILED ( hr )) return hr ;
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncOperation < ABI :: Windows :: Storage :: StorageFile *>> fileOpenAsync ;
hr = fileFactory -> GetFileFromPathAsync ( hstr_path , fileOpenAsync . GetAddressOf ());
if ( FAILED ( hr )) return hr ;
( * s_WindowsDeleteString )( hstr_path );
// Wait until the file gets open, get the actual file.
2018-06-06 15:19:06 +02:00
AsyncStatus status = winrt_async_await ( fileOpenAsync , throw_on_cancel );
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: IStorageFile > storageFile ;
if ( status == AsyncStatus :: Completed ) {
hr = fileOpenAsync -> GetResults ( storageFile . GetAddressOf ());
} else {
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncInfo > asyncInfo ;
hr = fileOpenAsync . As ( & asyncInfo );
if ( FAILED ( hr )) return hr ;
HRESULT err ;
hr = asyncInfo -> get_ErrorCode ( & err );
return FAILED ( hr ) ? hr : err ;
}
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncOperation < ABI :: Windows :: Storage :: Streams :: IRandomAccessStream *>> fileStreamAsync ;
hr = storageFile -> OpenAsync ( mode , fileStreamAsync . GetAddressOf ());
if ( FAILED ( hr )) return hr ;
2018-06-06 15:19:06 +02:00
status = winrt_async_await ( fileStreamAsync , throw_on_cancel );
2018-06-04 17:27:33 +02:00
if ( status == AsyncStatus :: Completed ) {
hr = fileStreamAsync -> GetResults ( fileStream );
} else {
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncInfo > asyncInfo ;
hr = fileStreamAsync . As ( & asyncInfo );
if ( FAILED ( hr )) return hr ;
HRESULT err ;
hr = asyncInfo -> get_ErrorCode ( & err );
if ( ! FAILED ( hr ))
hr = err ;
}
return hr ;
}
bool is_windows10 ()
{
HKEY hKey ;
LONG lRes = RegOpenKeyExW ( HKEY_LOCAL_MACHINE , L "SOFTWARE \\ Microsoft \\ Windows NT \\ CurrentVersion" , 0 , KEY_READ , & hKey );
if ( lRes == ERROR_SUCCESS ) {
WCHAR szBuffer [ 512 ];
DWORD dwBufferSize = sizeof ( szBuffer );
lRes = RegQueryValueExW ( hKey , L "ProductName" , 0 , nullptr , ( LPBYTE ) szBuffer , & dwBufferSize );
if ( lRes == ERROR_SUCCESS )
return wcsncmp ( szBuffer , L "Windows 10" , 10 ) == 0 ;
RegCloseKey ( hKey );
}
return false ;
}
2018-06-06 15:19:06 +02:00
// Progress function, to be called regularly to update the progress.
typedef std :: function < void ( const char * /* message */ , unsigned /* progress */ ) > ProgressFn ;
2018-06-04 17:27:33 +02:00
2018-06-06 15:19:06 +02:00
void fix_model_by_win10_sdk ( const std :: string & path_src , const std :: string & path_dst , ProgressFn on_progress , ThrowOnCancelFn throw_on_cancel )
{
if ( ! is_windows10 ())
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( "fix_model_by_win10_sdk called on non Windows 10 system" );
2018-06-06 15:19:06 +02:00
if ( ! winrt_load_runtime_object_library ())
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( "Failed to initialize the WinRT library." );
2018-06-04 17:27:33 +02:00
2018-06-04 21:22:42 +02:00
HRESULT hr = ( * s_RoInitialize )( RO_INIT_MULTITHREADED );
2018-06-04 17:27:33 +02:00
{
2019-02-03 22:14:34 +01:00
on_progress ( L ( "Exporting source model" ), 20 );
2018-06-06 15:19:06 +02:00
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: Streams :: IRandomAccessStream > fileStream ;
2018-06-06 15:19:06 +02:00
hr = winrt_open_file_stream ( boost :: nowide :: widen ( path_src ), ABI :: Windows :: Storage :: FileAccessMode :: FileAccessMode_Read , fileStream . GetAddressOf (), throw_on_cancel );
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Graphics :: Printing3D :: IPrinting3D3MFPackage > printing3d3mfpackage ;
hr = winrt_activate_instance ( L "Windows.Graphics.Printing3D.Printing3D3MFPackage" , printing3d3mfpackage . GetAddressOf ());
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncOperation < ABI :: Windows :: Graphics :: Printing3D :: Printing3DModel *>> modelAsync ;
hr = printing3d3mfpackage -> LoadModelFromPackageAsync ( fileStream . Get (), modelAsync . GetAddressOf ());
2018-06-06 15:19:06 +02:00
AsyncStatus status = winrt_async_await ( modelAsync , throw_on_cancel );
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Graphics :: Printing3D :: IPrinting3DModel > model ;
2018-06-06 15:19:06 +02:00
if ( status == AsyncStatus :: Completed )
2018-06-04 17:27:33 +02:00
hr = modelAsync -> GetResults ( model . GetAddressOf ());
2018-06-06 15:19:06 +02:00
else
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Failed loading the input model." ));
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: Collections :: IVector < ABI :: Windows :: Graphics :: Printing3D :: Printing3DMesh *>> meshes ;
hr = model -> get_Meshes ( meshes . GetAddressOf ());
unsigned num_meshes = 0 ;
hr = meshes -> get_Size ( & num_meshes );
2019-02-03 22:14:34 +01:00
on_progress ( L ( "Repairing model by the Netfabb service" ), 40 );
2018-06-06 15:19:06 +02:00
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncAction > repairAsync ;
hr = model -> RepairAsync ( repairAsync . GetAddressOf ());
2018-06-06 15:19:06 +02:00
status = winrt_async_await ( repairAsync , throw_on_cancel );
if ( status != AsyncStatus :: Completed )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Mesh repair failed." ));
2018-06-04 17:27:33 +02:00
repairAsync -> GetResults ();
2019-02-03 22:14:34 +01:00
on_progress ( L ( "Loading repaired model" ), 60 );
2018-06-06 15:19:06 +02:00
2018-06-04 17:27:33 +02:00
// Verify the number of meshes returned after the repair action.
meshes . Reset ();
hr = model -> get_Meshes ( meshes . GetAddressOf ());
hr = meshes -> get_Size ( & num_meshes );
// Save model to this class' Printing3D3MFPackage.
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncAction > saveToPackageAsync ;
hr = printing3d3mfpackage -> SaveModelToPackageAsync ( model . Get (), saveToPackageAsync . GetAddressOf ());
2018-06-06 15:19:06 +02:00
status = winrt_async_await ( saveToPackageAsync , throw_on_cancel );
if ( status != AsyncStatus :: Completed )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Saving mesh into the 3MF container failed." ));
2018-06-04 17:27:33 +02:00
hr = saveToPackageAsync -> GetResults ();
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncOperation < ABI :: Windows :: Storage :: Streams :: IRandomAccessStream *>> generatorStreamAsync ;
hr = printing3d3mfpackage -> SaveAsync ( generatorStreamAsync . GetAddressOf ());
2018-06-06 15:19:06 +02:00
status = winrt_async_await ( generatorStreamAsync , throw_on_cancel );
if ( status != AsyncStatus :: Completed )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Saving mesh into the 3MF container failed." ));
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: Streams :: IRandomAccessStream > generatorStream ;
hr = generatorStreamAsync -> GetResults ( generatorStream . GetAddressOf ());
// Go to the beginning of the stream.
generatorStream -> Seek ( 0 );
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: Streams :: IInputStream > inputStream ;
hr = generatorStream . As ( & inputStream );
// Get the buffer factory.
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: Streams :: IBufferFactory > bufferFactory ;
hr = winrt_get_activation_factory ( L "Windows.Storage.Streams.Buffer" , bufferFactory . GetAddressOf ());
// Open the destination file.
2018-06-04 21:22:42 +02:00
FILE * fout = boost :: nowide :: fopen ( path_dst . c_str (), "wb" );
2018-06-04 17:27:33 +02:00
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Storage :: Streams :: IBuffer > buffer ;
byte * buffer_ptr ;
bufferFactory -> Create ( 65536 * 2048 , buffer . GetAddressOf ());
{
Microsoft :: WRL :: ComPtr < Windows :: Storage :: Streams :: IBufferByteAccess > bufferByteAccess ;
buffer . As ( & bufferByteAccess );
hr = bufferByteAccess -> Buffer ( & buffer_ptr );
}
uint32_t length ;
hr = buffer -> get_Length ( & length );
Microsoft :: WRL :: ComPtr < ABI :: Windows :: Foundation :: IAsyncOperationWithProgress < ABI :: Windows :: Storage :: Streams :: IBuffer * , UINT32 >> asyncRead ;
for (;;) {
hr = inputStream -> ReadAsync ( buffer . Get (), 65536 * 2048 , ABI :: Windows :: Storage :: Streams :: InputStreamOptions_ReadAhead , asyncRead . GetAddressOf ());
2018-06-06 15:19:06 +02:00
status = winrt_async_await ( asyncRead , throw_on_cancel );
if ( status != AsyncStatus :: Completed )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Saving mesh into the 3MF container failed." ));
2018-06-04 17:27:33 +02:00
hr = buffer -> get_Length ( & length );
if ( length == 0 )
break ;
fwrite ( buffer_ptr , length , 1 , fout );
}
fclose ( fout );
// Here all the COM objects will be released through the ComPtr destructors.
}
( * s_RoUninitialize )();
}
2018-06-06 15:19:06 +02:00
class RepairCanceledException : public std :: exception {
public :
const char * what () const throw () { return "Model repair has been canceled" ; }
};
2019-02-03 22:14:34 +01:00
void fix_model_by_win10_sdk_gui ( ModelObject & model_object , int volume_idx )
2018-06-04 21:22:42 +02:00
{
2018-06-06 15:19:06 +02:00
std :: mutex mutex ;
std :: condition_variable condition ;
std :: unique_lock < std :: mutex > lock ( mutex );
struct Progress {
std :: string message ;
int percent = 0 ;
bool updated = false ;
} progress ;
std :: atomic < bool > canceled = false ;
std :: atomic < bool > finished = false ;
2019-02-03 22:14:34 +01:00
std :: vector < ModelVolume *> volumes ;
if ( volume_idx == - 1 )
volumes = model_object . volumes ;
else
volumes . emplace_back ( model_object . volumes [ volume_idx ]);
2018-06-06 15:19:06 +02:00
// Open a progress dialog.
2018-06-04 21:22:42 +02:00
wxProgressDialog progress_dialog (
2020-07-10 10:20:57 +02:00
_L ( "Model fixing" ),
_L ( "Exporting model" ) + "..." ,
2018-06-06 15:19:06 +02:00
100 , nullptr , wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT );
2018-06-04 21:22:42 +02:00
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
2019-02-03 22:14:34 +01:00
bool success = false ;
size_t ivolume = 0 ;
auto on_progress = [ & mutex , & condition , & ivolume , & volumes , & progress ]( const char * msg , unsigned prcnt ) {
2018-06-06 15:19:06 +02:00
std :: lock_guard < std :: mutex > lk ( mutex );
progress . message = msg ;
2019-02-03 22:14:34 +01:00
progress . percent = ( int ) floor (( float ( prcnt ) + float ( ivolume ) * 100.f ) / float ( volumes . size ()));
2018-06-06 15:19:06 +02:00
progress . updated = true ;
condition . notify_all ();
};
2019-02-03 22:14:34 +01:00
auto worker_thread = boost :: thread ([ & model_object , & volumes , & ivolume , on_progress , & success , & canceled , & finished ]() {
2018-06-06 15:19:06 +02:00
try {
2019-02-03 22:14:34 +01:00
std :: vector < TriangleMesh > meshes_repaired ;
meshes_repaired . reserve ( volumes . size ());
for (; ivolume < volumes . size (); ++ ivolume ) {
on_progress ( L ( "Exporting source model" ), 0 );
boost :: filesystem :: path path_src = boost :: filesystem :: temp_directory_path () / boost :: filesystem :: unique_path ();
path_src += ".3mf" ;
Model model ;
ModelObject * model_object = model . add_object ();
model_object -> add_volume ( * volumes [ ivolume ]);
model_object -> add_instance ();
2021-03-08 09:36:13 +01:00
if ( ! Slic3r :: store_3mf ( path_src . string (). c_str (), & model , nullptr , false , nullptr , false )) {
2020-01-08 11:11:38 +01:00
boost :: filesystem :: remove ( path_src );
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Export of a temporary 3mf file failed" ));
2020-01-08 11:11:38 +01:00
}
2019-02-03 22:14:34 +01:00
model . clear_objects ();
model . clear_materials ();
boost :: filesystem :: path path_dst = boost :: filesystem :: temp_directory_path () / boost :: filesystem :: unique_path ();
path_dst += ".3mf" ;
fix_model_by_win10_sdk ( path_src . string (). c_str (), path_dst . string (), on_progress ,
[ & canceled ]() { if ( canceled ) throw RepairCanceledException (); });
2018-06-06 15:19:06 +02:00
boost :: filesystem :: remove ( path_src );
2019-02-03 22:14:34 +01:00
// PresetBundle bundle;
on_progress ( L ( "Loading repaired model" ), 80 );
DynamicPrintConfig config ;
2019-08-23 13:44:07 +02:00
bool loaded = Slic3r :: load_3mf ( path_dst . string (). c_str (), & config , & model , false );
2019-02-03 22:14:34 +01:00
boost :: filesystem :: remove ( path_dst );
if ( ! loaded )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Import of the repaired 3mf file failed" ));
2019-02-03 22:14:34 +01:00
if ( model . objects . size () == 0 )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Repaired 3MF file does not contain any object" ));
2019-02-03 22:14:34 +01:00
if ( model . objects . size () > 1 )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Repaired 3MF file contains more than one object" ));
2019-02-03 22:14:34 +01:00
if ( model . objects . front () -> volumes . size () == 0 )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Repaired 3MF file does not contain any volume" ));
2019-02-03 22:14:34 +01:00
if ( model . objects . front () -> volumes . size () > 1 )
2020-09-14 16:27:55 +02:00
throw Slic3r :: RuntimeError ( L ( "Repaired 3MF file contains more than one volume" ));
2019-06-13 16:33:50 +02:00
meshes_repaired . emplace_back ( std :: move ( model . objects . front () -> volumes . front () -> mesh ()));
2018-06-06 15:19:06 +02:00
}
2019-02-03 22:14:34 +01:00
for ( size_t i = 0 ; i < volumes . size (); ++ i ) {
2019-06-13 16:33:50 +02:00
volumes [ i ] -> set_mesh ( std :: move ( meshes_repaired [ i ]));
2019-02-03 22:14:34 +01:00
volumes [ i ] -> set_new_unique_id ();
}
model_object . invalidate_bounding_box ();
-- ivolume ;
on_progress ( L ( "Model repair finished" ), 100 );
2018-06-06 15:19:06 +02:00
success = true ;
finished = true ;
2018-11-08 20:18:40 +01:00
} catch ( RepairCanceledException & /* ex */ ) {
2018-06-06 15:19:06 +02:00
canceled = true ;
finished = true ;
on_progress ( L ( "Model repair canceled" ), 100 );
} catch ( std :: exception & ex ) {
success = false ;
finished = true ;
on_progress ( ex . what (), 100 );
}
2018-06-04 21:22:42 +02:00
});
2018-06-06 15:19:06 +02:00
while ( ! finished ) {
condition . wait_for ( lock , std :: chrono :: milliseconds ( 500 ), [ & progress ]{ return progress . updated ; });
if ( ! progress_dialog . Update ( progress . percent , _ ( progress . message )))
canceled = true ;
progress . updated = false ;
}
if ( canceled ) {
// Nothing to show.
} else if ( success ) {
wxMessageDialog dlg ( nullptr , _ ( L ( "Model repaired successfully" )), _ ( L ( "Model Repair by the Netfabb service" )), wxICON_INFORMATION | wxOK_DEFAULT );
dlg . ShowModal ();
} else {
2019-12-04 11:12:28 +01:00
wxMessageDialog dlg ( nullptr , _ ( L ( "Model repair failed:" )) + " \n " + _ ( progress . message ), _ ( L ( "Model Repair by the Netfabb service" )), wxICON_ERROR | wxOK_DEFAULT );
2018-06-06 15:19:06 +02:00
dlg . ShowModal ();
}
worker_thread . join ();
2018-06-04 21:22:42 +02:00
}
} // namespace Slic3r
2018-06-04 17:27:33 +02:00
#endif /* HAS_WIN10SDK */