Thursday, May 29, 2008

Work Progress

Spent the day thinking at the OpenCascade and NaroCAD architecture.

1. Reviewed the most important OpenCascade classes and their architecture:
- the V3d_Viewer that creates with the method CreateView a new V3d_View, the V3D_View to which it can be attached a window handle and the AIS_InteractiveCOntext that receives as parameter a V3d_Viewer,
- the same for 2D: the V2d_Viewer to which V2d_View can be attached, the AIS2D_InteractiveContext for managing the graphic behaviour,
- analyzed as data container the TDocStd_Document that has the methods NewCommand for starting an Undo operation, CommitCommand to close an Undo Operation, the Main() that returns the root Label to the data structure,
- looked how the commands are prepared for Undo using OCAF: the FunctionDriver class is initialized with the Root Label got from document. To implement a Rectangle drawing command a RectangleDriver that inherits from FunctionDriver is implemented and also it has to implement the MustExecute() and Execute() methods which adds the model as child Label to the root Label tree. This solution seems to be an Command design pattern the only difference being that the commands are identified by GUIDs,
- another important classes for the architecture are: the DriverTable that has the methods FindDriver, AddDriver used for retrieving command drivers, the AISViewer class used to define an interactive viewer attribute from a Label (with the methods New, Find and Get), the AISPresentation class that associates an AIS_InteractiveObject to a Label data structure.

All these classes will be used for creating Views, defining commands with Undo, store application data, connect application data with the Viewers.

2. Another area that was analyzed is implementing an Multiview architecture: the application has a main form that has child windows, each child can be split into one to four views. The implementation will be made using MDI forms, a TableLayoutPanel that holds 1-4 controls which will be set as rendering areas for OpenCascade. A solution with having a transparent Tree View over the OpenCascade model doesn't seem to work properly. For the moment the Tree View will be implemented on the left side of the Views.

3. Started also some development. Implemented a basic Controller class, implemented basic View, implemented a MultiView interface that will be inherited by the Forms to support Multiview. Next development steps to achieve the previously proposed tasks will be:
- add OpenCascade code to see if the engine can render on a custom control from the View,
- extend the Controller class to porcess Operations like Zoom, Pan, Rotate,
- implement the 3dView, 3dViewer from OpenCascade in the application,
- make the model loading from file code.
When these tasks will be made the design document will be extended with more explanations in order to create the big integration picture of all the components, OCAF integration will be analyzed and probably also some wrappers to this component will be needed.

Tuesday, May 27, 2008

Next development steps

Looked over the J. Hill wrappers. Only the OCAF package is missing, the other packages seem to cover all the functionalities we need. Will think at a solution for this.

Started implementing NaroCAD in C#. Made the main dialog with the manipulation toolbar (pan, zoom, rotate, etc). Implemented the Operation and Action classes, added an Operation factory class, started implementing a Controller.

In the next two days will continue with the following tasks:
- finish the Controller class,
- add the C# View classes,
- implement with the .Net wrappers a BRep shape load and display,
- make the manipulation classes operate on the loaded shape.

Monday, May 26, 2008

Started coding

Succeeded to build the MakeBottle and AISSelect C# samples using J.Hill's .Net wrappers. The debug version of the applications worked very well.

Will analyze the functionalities wrapped and if there are packages missing.

Sunday, May 11, 2008

C++/CLI vs C# (4)

Finished the 2nd point proposed for analysis:

2. Study the unmanaged to managed wrapping methods and make a performance estimation for both managed languages

Testing system

Single core Celeron M 1.5 Ghz processor.
Executed the test method call 100 million times.

Tested code
A c++ dll contains a class that has a method that receives as parameter a structure pointer (code shown below). The purpose of the exercise is to wrap the C++ class into a managed class and use this class to pass a structure as parameter.

struct MyStruct
{
int SomeId;
double SomePrice;
};

class EXAMPLEUNMANAGEDDLL_API TestInterop
{
public:
TestInterop();
void PassStructIn(MyStruct* myStruct);
void PassStructIn(int* myStruct);
virtual ~TestInterop();
};

Provided also a C bridge that allows calling the class method by providing the class pointer as parameter (needed for P/Invoke calls):
extern "C" EXAMPLEUNMANAGEDDLL_API void PassStructInBridge(TestInterop* pObject, MyStruct* myStruct)

Test case results
- native C++ test: called using the C bridge the class method
for 100 million calls the time is 1127 milliseconds
- C# test: imported the C bridge function with P/Invoke, wrapped the P/Invoke functions into a managed class, created a managed version of the structure passed as parameter. (note: it is also possible to wrap the class by P/Invoking directly the mangled name. That method should have the same performance).
for 100 million calls the time is 10950 milliseconds
- C++/CLI test: tested two cases, one case when directly used the unmanaged code into the managed one using the C++ interop and another case in which made a managed wrapper (in a separate dll) that holds a pointer to the unmanaged class and translates method calls to the unmanaged code (used as struct passed as parameter the definition from the unmanaged header file and didn't create a managed version)
100 million calls with C++ interop and no bridge/wrapper take 4280 milliseconds
100 million calls with C++/CLI bridge as managed wrapper take 4031 milliseconds

Conclusions
Wrapping the unmanaged code in C++/CLI (~4000 ms) is 2.5 times faster than wrapping it into C# (~11000 ms).
This speed difference is probably given by the fact that in the C++/CLI case used the unmanaged struct to be passed as parameter and no marshaling appeared.

Looking at the test results I think wrapping OpenCascade should be made with C++/CLI if there would be many repetitive calls to the unmanaged code. I will analyze the application structure and think at the functionality areas where repetitive calls might be used.

Friday, May 9, 2008

C++/CLI vs C# (3)

1. Analyze the speed of calls from both managed languages to an unmanaged dll

Implemented a c++ dll that contains a function that has as parameter a structure like the following:
struct MyStruct
{
int SomeId;
double SomePrice;
}
extern "C" __declspec(dllexport) void PassStructIn(MyStruct* myStruct);

Implemented a C++/CLI application and also a C# application that make 150 millions calls to this function, passes a reference to the structure to the unmanaged code and have the values set in the unmanaged code.

The test results are the following:
C++/CLI 4140 milliseconds
C# 10890 milliseconds

It seems that the C++/CLI calls to unmanaged code is two time and a half faster than the C# ones.

There are many other possibilities to test but for this project this quick test is relevant for taking an architectural decision.

C++/CLI vs C# (2)

Changed the approach of testing the performance penalty of a C# implementation versus a C++/CLI implementation. The following steps will be made:

1. Analyze the speed of calls from both managed languages to an unmanaged dll,
2. Study the unmanaged to managed wrapping methods and make a performance estimation for both managed languages,
3. On the application architecture analyze the critical points and analyze the possibility to implement the functionality with a mixed code (C# for GUI, C++/CLI for OpenCascade calls).

Saturday, May 3, 2008

C++/CLI vs C# (1)

Worked at analyzing the benefits of implementing NaroCAD with C# versus the C++/CLI implementation.

Didn't obtain any clear conclusion yet. Until now the conclusions are the following:

1. The C++/CLI implementation has the advantage that it can mix unmanaged and managed code with ease (on the other side this can be seen as an disadvantage if not used with care), the P/Invoke layer/maybe marshaling can be avoided for speed critical code areas, a wrapper can be probably avoided if not needed or if it affects the speed,

2. Couldn't measure yet the performance cost of using a C# wrapper around the OpenCascade code and the impact that this wrapper might have on NaroCAD. From the two C# wrappers that I tried until now the conclusions are the following:
- tried the wrapper from Sofa.de, implemented using P/Invoke. Succeeded to implement easily the MakeBottle code into the C# project provided by OpenCascade. The main problem here is that the wrapper doesn't cover the AIS packages and OCAF, couldn't make some display performance tests. Using this wrapper will need some additional work to wrap the packages that are not covered. Looked also at the Cadability.Net sample application provided by Sofa and it seems that for drawing they are using some ACIS plugins, probably this explains the missing packages and their license costs,
- tried the wrapper from Jonathan Hill. Couldn't make it work for VS2005, some OpenCASCADEX.dll registration fails. It would be interesting to analyze it because I saw in some forum posts that he might not use P/Invoke as wrapping method.

Looked at some QuakeII port to .Net: http://www.codeproject.com/KB/mcpp/quake2.aspx. They claim that the managed version performs 85% as fast as the native version, the speed is good and the testers didn't notice the difference between the two versions. This performance might be acceptable considering the advantages of using .Net.


I will continue analyzing this problem and see what the final conclusion is.