(continued)
Performance considerations
Using progress indicator obviously adds certain overhead as calculating current position and redrawing a widget eats some CPU time. So, be careful to not abuse an indicator by updating it after every tiny operation. Instead you might prefer to request its update after some chunks of operations (e.g. after every 10th).
int aNbOps = ...;
int aThreshold = 10;
int aNbChunks = aNbOps / aThreshold;
anIndicator->SetRange (0, aNbChunks);
for (i = 1; i <= aNbOps; i++) {
if (i % aThreshold)
anIndicator->Increment();
}
Inserting your indicator into Open CASCADE algorithms
Once you have implemented your subclass, you can pass it to OCC algorithms. As I said above, at the moment, Open CASCADE currently supports progress indicators in IGES, STEP and BRep readers and writers.
Here are examples of how you can provide your indicators into IGES and BRep readers.
IGESCAFControl_Reader aReader;
Handle(Message_ProgressIndicator) anIndicator = ...;
//to make progress indicator work more smoothly divide the transfer into
//two steps: loading (30%) and mapping (70%), including shape healing
anIndicator->NewScope (30, (Standard_CString)qApp->translate ("Exchanger", "Loading file").toAscii());
Standard_Boolean aRes = (aReader.ReadFile (theFileName.ToCString()) == IFSelect_RetDone);
anIndicator->EndScope ();
if (aRes) {
//setting progress into the reader object to track every entity
//(using TransientProcess() is possible only after ReadFile())
aReader.WS()->MapReader()->SetProgress (anIndicator);
anIndicator->NewScope (70, (Standard_CString)qApp->translate ("Exchanger", "Translating file").toAscii());
aRes = aReader.Transfer (theDoc);
anIndicator->EndScope ();
//work-around to decremenet reference counter inside TransientProcess
aReader.WS()->MapReader()->SetProgress (NULL);
}
Importing native BRep file is more straightforward:
Standard_Boolean aResult = BRepTools::Read (aShape, theFileName.ToCString(), aBuilder, anIndicator);
Multi-threading issues
In its current implementation Message_ProgressIndicator is exclusively tailored for use within a single thread. This stems from its implementation concept based on a stack of nested sub-ranges – every time you signal a progress (e.g. with Increment() or EndScope()) it applies to the current open sub-range. This makes it unusable for multi-threaded environment where concurrent threads can perform their own chunks of tasks and report progress. I first encountered this working on parallelizing IGES import.
Upon part 1 publication, Andrey from OCC was very kind to let me know that they are prototyping multi-threaded version of the progress indicator. So chances are it can appear in near releases. Anyway, as long as you use the indicator in a single thread even within a multi-threaded environment (e.g. if your OCC-based algorithms run in a separate worker thread) you are safe to go.
So, go and plan your goal, set your range, make your next step and report how closer you are now ;-).
Performance considerations
Using progress indicator obviously adds certain overhead as calculating current position and redrawing a widget eats some CPU time. So, be careful to not abuse an indicator by updating it after every tiny operation. Instead you might prefer to request its update after some chunks of operations (e.g. after every 10th).
int aNbOps = ...;
int aThreshold = 10;
int aNbChunks = aNbOps / aThreshold;
anIndicator->SetRange (0, aNbChunks);
for (i = 1; i <= aNbOps; i++) {
if (i % aThreshold)
anIndicator->Increment();
}
Inserting your indicator into Open CASCADE algorithms
Once you have implemented your subclass, you can pass it to OCC algorithms. As I said above, at the moment, Open CASCADE currently supports progress indicators in IGES, STEP and BRep readers and writers.
Here are examples of how you can provide your indicators into IGES and BRep readers.
IGESCAFControl_Reader aReader;
Handle(Message_ProgressIndicator) anIndicator = ...;
//to make progress indicator work more smoothly divide the transfer into
//two steps: loading (30%) and mapping (70%), including shape healing
anIndicator->NewScope (30, (Standard_CString)qApp->translate ("Exchanger", "Loading file").toAscii());
Standard_Boolean aRes = (aReader.ReadFile (theFileName.ToCString()) == IFSelect_RetDone);
anIndicator->EndScope ();
if (aRes) {
//setting progress into the reader object to track every entity
//(using TransientProcess() is possible only after ReadFile())
aReader.WS()->MapReader()->SetProgress (anIndicator);
anIndicator->NewScope (70, (Standard_CString)qApp->translate ("Exchanger", "Translating file").toAscii());
aRes = aReader.Transfer (theDoc);
anIndicator->EndScope ();
//work-around to decremenet reference counter inside TransientProcess
aReader.WS()->MapReader()->SetProgress (NULL);
}
Importing native BRep file is more straightforward:
Standard_Boolean aResult = BRepTools::Read (aShape, theFileName.ToCString(), aBuilder, anIndicator);
Multi-threading issues
In its current implementation Message_ProgressIndicator is exclusively tailored for use within a single thread. This stems from its implementation concept based on a stack of nested sub-ranges – every time you signal a progress (e.g. with Increment() or EndScope()) it applies to the current open sub-range. This makes it unusable for multi-threaded environment where concurrent threads can perform their own chunks of tasks and report progress. I first encountered this working on parallelizing IGES import.
Upon part 1 publication, Andrey from OCC was very kind to let me know that they are prototyping multi-threaded version of the progress indicator. So chances are it can appear in near releases. Anyway, as long as you use the indicator in a single thread even within a multi-threaded environment (e.g. if your OCC-based algorithms run in a separate worker thread) you are safe to go.
So, go and plan your goal, set your range, make your next step and report how closer you are now ;-).