# Error handling
# Exceptional (unrecoverable) errors
Simplygon API reports exceptional errors through the error handling class ErrorHandler. A user can derive a class from ErrorHandler, which then will receive processing errors, and handle them appropriately. Any internal standard exception (such as null-pointer exception or out of memory exceptions etc) is reported through the same error handler. In C# and Python, if no error handler is set, the errors are reported through exception handling.
Please note that if you receive an exceptional error, the library is placed in an exceptional state. The safest way to handle this is to shut down and unload/reload the library before continuing. Failing to do this might affect the quality of the processing, and will lead to memory leaks.
# Recoverable processing errors
A lot of processing errors are recoverable, and the user can safely continue processing, or try reprocessing with new data.
These errors are instead reported through the log and in return values from the Run methods in e.g. processing objects, casters or pipelines.
To instead have all errors be reported through the ErrorHandler, please set the global setting ReportErrorCodesToErrorHandler to true.
# ErrorHandler example
This example shows how to use the Simplygon error handler.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include <string>
#include <stdlib.h>
#include <filesystem>
#include <future>
#include "SimplygonLoader.h"
class CustomErrorHandler : public Simplygon::ErrorHandler
{
public:
void HandleError(Simplygon::spObject object, const char* interfaceName, const char* methodName, Simplygon::rid errorType , const char* errorText) override
{
printf("Error (%s:%s): %s\n", interfaceName, methodName, errorText);
}
} customErrorHandler;
void CheckLog(Simplygon::ISimplygon* sg)
{
// Check if any errors occurred.
bool hasErrors = sg->ErrorOccurred();
if (hasErrors)
{
Simplygon::spStringArray errors = sg->CreateStringArray();
sg->GetErrorMessages(errors);
auto errorCount = errors->GetItemCount();
if (errorCount > 0)
{
printf("%s\n", "Errors:");
for (auto errorIndex = 0U; errorIndex < errorCount; ++errorIndex)
{
Simplygon::spString errorString = errors->GetItem((int)errorIndex);
printf("%s\n", errorString.c_str());
}
sg->ClearErrorMessages();
}
}
else
{
printf("%s\n", "No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg->WarningOccurred();
if (hasWarnings)
{
Simplygon::spStringArray warnings = sg->CreateStringArray();
sg->GetWarningMessages(warnings);
auto warningCount = warnings->GetItemCount();
if (warningCount > 0)
{
printf("%s\n", "Warnings:");
for (auto warningIndex = 0U; warningIndex < warningCount; ++warningIndex)
{
Simplygon::spString warningString = warnings->GetItem((int)warningIndex);
printf("%s\n", warningString.c_str());
}
sg->ClearWarningMessages();
}
}
else
{
printf("%s\n", "No warnings.");
}
// Error out if Simplygon has errors.
if (hasErrors)
{
throw std::exception("Processing failed with an error");
}
}
void RunReduction(Simplygon::ISimplygon* sg)
{
// Set the custom error handler to the Simplygon interface.
sg->SetErrorHandler(&customErrorHandler);
// Create the reduction pipeline.
Simplygon::spReductionPipeline sgReductionPipeline = sg->CreateReductionPipeline();
// To be able to use the T-Junction remover, the welder has to be enabled so this will trigger an
// error.
Simplygon::spRepairSettings sgRepairSettings = sgReductionPipeline->GetRepairSettings();
sgRepairSettings->SetUseWelding( false );
sgRepairSettings->SetUseTJunctionRemover( true );
// Start the reduction pipeline and the faulty settings will cause an error.
printf("%s\n", "Start the reduction pipeline and the faulty settings will cause an error.");
sgReductionPipeline->RunSceneFromFile("../../../Assets/SimplygonMan/SimplygonMan.obj", "Output.fbx", Simplygon::EPipelineRunMode::RunInNewProcess);
// Check log for any warnings or errors.
printf("%s\n", "Check log for any warnings or errors.");
CheckLog(sg);
}
int main()
{
Simplygon::ISimplygon* sg = NULL;
Simplygon::EErrorCodes initval = Simplygon::Initialize( &sg );
if( initval != Simplygon::EErrorCodes::NoError )
{
printf( "Failed to initialize Simplygon: ErrorCode(%d)", (int)initval );
return int(initval);
}
RunReduction(sg);
Simplygon::Deinitialize(sg);
return 0;
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Threading.Tasks;
public class CustomErrorHandler : Simplygon.ErrorHandler
{
public override void HandleError(Simplygon.spObject obj, string interfaceName, string methodName, int errorType , string errorText)
{
Console.WriteLine($"Error ({interfaceName}:{methodName}): {errorText}");
}
}
public class Program
{
static private CustomErrorHandler customErrorHandler;
static void CheckLog(Simplygon.ISimplygon sg)
{
// Check if any errors occurred.
bool hasErrors = sg.ErrorOccurred();
if (hasErrors)
{
Simplygon.spStringArray errors = sg.CreateStringArray();
sg.GetErrorMessages(errors);
var errorCount = errors.GetItemCount();
if (errorCount > 0)
{
Console.WriteLine("Errors:");
for (uint errorIndex = 0; errorIndex < errorCount; ++errorIndex)
{
string errorString = errors.GetItem((int)errorIndex);
Console.WriteLine(errorString);
}
sg.ClearErrorMessages();
}
}
else
{
Console.WriteLine("No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg.WarningOccurred();
if (hasWarnings)
{
Simplygon.spStringArray warnings = sg.CreateStringArray();
sg.GetWarningMessages(warnings);
var warningCount = warnings.GetItemCount();
if (warningCount > 0)
{
Console.WriteLine("Warnings:");
for (uint warningIndex = 0; warningIndex < warningCount; ++warningIndex)
{
string warningString = warnings.GetItem((int)warningIndex);
Console.WriteLine(warningString);
}
sg.ClearWarningMessages();
}
}
else
{
Console.WriteLine("No warnings.");
}
// Error out if Simplygon has errors.
if (hasErrors)
{
throw new System.Exception("Processing failed with an error");
}
}
static void RunReduction(Simplygon.ISimplygon sg)
{
// Set the custom error handler to the Simplygon interface.
sg.SetErrorHandler(customErrorHandler);
// Create the reduction pipeline.
using Simplygon.spReductionPipeline sgReductionPipeline = sg.CreateReductionPipeline();
// To be able to use the T-Junction remover, the welder has to be enabled so this will trigger an
// error.
using Simplygon.spRepairSettings sgRepairSettings = sgReductionPipeline.GetRepairSettings();
sgRepairSettings.SetUseWelding( false );
sgRepairSettings.SetUseTJunctionRemover( true );
// Start the reduction pipeline and the faulty settings will cause an error.
Console.WriteLine("Start the reduction pipeline and the faulty settings will cause an error.");
sgReductionPipeline.RunSceneFromFile("../../../Assets/SimplygonMan/SimplygonMan.obj", "Output.fbx", Simplygon.EPipelineRunMode.RunInNewProcess);
// Check log for any warnings or errors.
Console.WriteLine("Check log for any warnings or errors.");
CheckLog(sg);
}
static int Main(string[] args)
{
using var sg = Simplygon.Loader.InitSimplygon(out var errorCode, out var errorMessage);
if (errorCode != Simplygon.EErrorCodes.NoError)
{
Console.WriteLine( $"Failed to initialize Simplygon: ErrorCode({(int)errorCode}) {errorMessage}" );
return (int)errorCode;
}
customErrorHandler = new CustomErrorHandler();
RunReduction(sg);
return 0;
}
}
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
import math
import os
import sys
import glob
import gc
import threading
from pathlib import Path
from simplygon10 import simplygon_loader
from simplygon10 import Simplygon
class CustomErrorHandler(Simplygon.ErrorHandler):
def HandleError(self, object: Simplygon.spObject, interfaceName: str, methodName: str, errorType: int, errorText: str):
print('Error (%s:%s): %s' %(interfaceName, methodName, errorText))
customErrorHandler = CustomErrorHandler()
def CheckLog(sg: Simplygon.ISimplygon):
# Check if any errors occurred.
hasErrors = sg.ErrorOccurred()
if hasErrors:
errors = sg.CreateStringArray()
sg.GetErrorMessages(errors)
errorCount = errors.GetItemCount()
if errorCount > 0:
print('Errors:')
for errorIndex in range(errorCount):
errorString = errors.GetItem(errorIndex)
print(errorString)
sg.ClearErrorMessages()
else:
print('No errors.')
# Check if any warnings occurred.
hasWarnings = sg.WarningOccurred()
if hasWarnings:
warnings = sg.CreateStringArray()
sg.GetWarningMessages(warnings)
warningCount = warnings.GetItemCount()
if warningCount > 0:
print('Warnings:')
for warningIndex in range(warningCount):
warningString = warnings.GetItem(warningIndex)
print(warningString)
sg.ClearWarningMessages()
else:
print('No warnings.')
# Error out if Simplygon has errors.
if hasErrors:
raise Exception('Processing failed with an error')
def RunReduction(sg: Simplygon.ISimplygon):
# Set the custom error handler to the Simplygon interface.
sg.SetErrorHandler(customErrorHandler)
# Create the reduction pipeline.
sgReductionPipeline = sg.CreateReductionPipeline()
# To be able to use the T-Junction remover, the welder has to be enabled so this will trigger an
# error.
sgRepairSettings = sgReductionPipeline.GetRepairSettings()
sgRepairSettings.SetUseWelding( False )
sgRepairSettings.SetUseTJunctionRemover( True )
# Start the reduction pipeline and the faulty settings will cause an error.
print("Start the reduction pipeline and the faulty settings will cause an error.")
sgReductionPipeline.RunSceneFromFile('../../../Assets/SimplygonMan/SimplygonMan.obj', 'Output.fbx', Simplygon.EPipelineRunMode_RunInNewProcess)
# Check log for any warnings or errors.
print("Check log for any warnings or errors.")
CheckLog(sg)
if __name__ == '__main__':
sg = simplygon_loader.init_simplygon()
if sg is None:
exit(Simplygon.GetLastInitializationError())
RunReduction(sg)
sg = None
gc.collect()