Friday, February 6, 2009

Using System.Reflection to get OCAF attributes applied to a Label

OCAF tree is the highlevel structure of data that stores the data in a tree formed by number in it's nodes, and extra data named attributes.

The NaroCAD C# code to access one specific attribute may be like this:

OCTDF_Label label = ...
// Check for integer attribute for an attribute
OCTDataStd_Integer integerAttr = new OCTDataStd_Integer();
if (label.FindAttribute(OCTDataStd_Integer.GetID(), integerAttr))
{
//using integerAttr...
}

How can we get the list of attribute types are attached to a label? As we don't have a real type introspection accessible using C++ code, or to C# (like from void * to decide which type of object is added, OpenCascade itself makes this thing a bit harder too, as is C++ code and NaroCad is C# code).

What is the solution to get the list of attributes then? We can scan the OCWrappers.dll assembly and to see which class have a method: GetId and invoke it to simulate the previous code:

Assembly assembly = Assembly.Load("OCWrappers");

foreach (Type type in assembly.GetTypes())
{

try
{
MethodInfo[] mis = type.GetMethods();
MethodInfo miGetId = null;
foreach(MethodInfo mi in mis)
{
if(mi.Name == ("GetID"))
{
miGetId = mi;
}
}
if(miGetId != null)
{
OCTDF_Attribute attrPtr = Activator.CreateInstance(type) as OCTDF_Attribute;
OCStandard_GUID attrGetId = miGetId.Invoke(type, new object[] {} ) as OCStandard_GUID;
if (childLabel.FindAttribute(attrGetId, attrPtr))
{
//code that gets the attribute name which is: type.Name
}
}
}
}
catch
{
//calls may fail so we should skip missused called types
}
}

If you are curious, you may look to the NaroCad implementation which is a bit more improved as the assembly is preprocessed and cached, so only a small list of candidates will be applied to a label, and the OCWrappers assembly is not loaded before every label.

8 comments:

Mihai said...

I'm trying to draw a circle in vb.net with the following piece of code using OCWrappers, but it doesen't show anything.Please help!

Private Sub Create2DView()
Dim device As OCWNT_GraphicDevice = New OCWNT_GraphicDevice(True, Me.Handle)
Dim aWindow As OCWNT_Window = New OCWNT_Window(device, Me.Handle, OCQuantity_NameOfColor.Quantity_NOC_BLACK)
Dim driver As OCWNT_WDriver = New OCWNT_WDriver(aWindow)
Dim gView As New OCGraphic2d_View
Dim viewer As New OCV2d_Viewer(device, gView, "Visu2d", "")
Dim view As OCV2d_View = New OCV2d_View(driver, viewer, 0, 0, 1500)

Dim ggview As New OCGraphic2d_View

Dim gObject As New OCGraphic2d_GraphicObject(ggview)
Dim gCircle As New OCGraphic2d_Circle(gObject, 100, 100, 100)
gCircle.SetColorIndex(3)
gCircle.SetWidthIndex(1)

Dim aPath As New OCOSD_Path
Dim oColl As New OCTCollection_AsciiString("c:\OpenCASCADE6.3.0\data\images\Image.xwd")


view.Update()
End Sub

bxtrx said...

Hi,

Not sure if I understand well your code but I don't see any 2D context creation code:
context2d = new OCAIS2D_InteractiveContext(this.viewer2d);

and then you have to display the shape using the context. The NaroCad project has also some 2D code artifacts, you can search for the Line2D.cs and Shape2d.cs to see a sample of a line drawn in 2D (the code is C# but should be no problem to convert it). For example look at the Shape2d at Display() to see how the shape is displayed (something like context2d.Display(this, updateViewer); ).

You should also check on the window you render that some OpenCascade content is rendered.


Best regards,
Mihai

Mihai said...

Thank you for your reply. Still not working. bbelow you can find my code converted in c#:

private void Form1_Load(object sender, EventArgs e)
{
OCWNT_GraphicDevice device = new OCWNT_GraphicDevice(true, this.Handle);
OCGraphic2d_View gView = new OCGraphic2d_View();
OCV2d_Viewer viewer = new OCV2d_Viewer(device, gView, "Visu2d", "");

OCAIS2D_InteractiveContext context2d = new OCAIS2D_InteractiveContext(viewer);

OCGraphic2d_GraphicObject gObject = new OCGraphic2d_GraphicObject();
gObject.SetView(gView);
OCGraphic2d_Circle gCircle = new OCGraphic2d_Circle(gObject, 10, 10, 10);
gCircle.SetColorIndex(3);
gCircle.SetWidthIndex(1);

context2d.DisplayAll(true,true) ;
}

Best Regards,
Mihai

bxtrx said...

Hi,

I still don't see in your code where do you tell the context to display your object, something like context.Display(myObject). Please look at the sample code from the two files that I told you below to see how it is done.

Best regards,
Mihai

Mihai said...

Still not working. Shape2d.cs it doesen't help me too much. This became just too frustrating for me beacause I just want to display a simple circle.

private void Form1_Load(object sender, EventArgs e)
{
OCWNT_GraphicDevice device = new OCWNT_GraphicDevice(true, this.Handle);
OCGraphic2d_View gView = new OCGraphic2d_View();

OCV2d_Viewer viewer = new OCV2d_Viewer(device, gView, "Visu2d", "");

OCWNT_Window aWindow = new OCWNT_Window(device, this.Handle, OCQuantity_NameOfColor.Quantity_NOC_WHITE);
OCWNT_WDriver driver = new OCWNT_WDriver(aWindow);
OCV2d_View view = new OCV2d_View(driver, viewer, 10, 10, 1500);
viewer.AddView(view);

OCAIS2D_InteractiveContext context2d = new OCAIS2D_InteractiveContext(viewer);

OCGraphic2d_GraphicObject gObject = new OCGraphic2d_GraphicObject();
gObject.SetView(gView);

OCGraphic2d_Circle gCircle = new OCGraphic2d_Circle(gObject, 10, 10, 100);
gCircle.SetColorIndex(4);
gCircle.SetWidthIndex(1);


OCAIS2D_InteractiveObject iObj = new OCAIS2D_InteractiveObject();
iObj.SetContext(context2d);
iObj.SetView(gView);

context2d.Display(iObj, true);
}

Best Regards,
Mihai

bxtrx said...

How about Circle2d.cs located in the same folder? This contains code that draws a 2d ellipse pretty close to your case. How about inserting those two files into your project and just using them?

From what I see there Ellipse2D is derived from Shape2D that is derived from OCAIS2D_InteractiveObject and the ellipse is built like the following (code from Circle2D.cs):
_ellipse = new OCGraphic2d_Ellips(this, _centerX, _centerY, _majorRadius, _minorRadius, _angle);
_ellipse.SetColorIndex(1);
_ellipse.SetWidthIndex(1);
_ellipse.SetTypeIndex(1);

and the display is something like (inherited from Shape2D):
context2d.Display(this, updateViewer);

Mihai said...

Still I was unable to solve the problem. I will appreciate if you can give me your email adrress. In this way, I can send you the entire VS solution. Maybe in this way you can find where the problem is. My email address is State.Mihai@gmail.com

Thanks in advance.

Mihai said...

You can find my VS project here:

http://www.turboupload.com/h11wtd9400ze/WindowsFormsApplication1.zip.html