Prod.: Engine, ver.: 6, ID: 60001640, HowTo : Can you give me a getting started guide for complex custom objects ?

HowTo : Can you give me a getting started guide for complex custom objects ?

Article60001640
TypeHowTo
ProductEngine
Version6
Date Added3/13/2012
Submitted by
Keywords

Subject

Can you give me a getting started guide for complex custom objects ?

Summary

Can you give me a getting started guide for complex custom objects ?

Solution

 
I will try to give you a good description on Custom Objects and how you should try to approach such an implementation.

My guide is for a .NET project in c# which is mainly the programming language that we use.

First of all you will have to create a solution with 2 projects like it is implemented in our samples. One project will be a very simple form with a control (Scrollable , framed doesn't matter) , preferably vdFramedControl because the vdFramedControl having the Properties List and the commandLine will give you a good debug project. In any case the code you will write for the vdFramedControl it is the same for the vdScrollableControl.

So we have a project with a vdFramedControl and some buttons to be used for testing the custom object.

The second project will be a dll which will contain your custom objects (exactly as it is in our samples). A reference for this project is required to the other project with the form so you can use your custom object for testing.

Once you finish the implementation of your custom object then the dll can be referenced in your main application without a problem and you can have this solution for testing and debugging your custom object.

Now after these initial setup lets start with the Custom Object.

First of all you will need to have some properties for your custom object that have to do with it's Geometry and how this object will be drawn.
I believe that you should go for a vdFigure object.
So we first define the object like this

public class vdBox : vdFigure, IvdProxyFigure

The vdBox being a vdFigure has already a pencolor , a layer , a penstyle etc... will could be used in drawing the object (will explain later in the draw method)

The IvdProxyFigure is required for such a custom object.
Add an empty constructor for the object (required always)
And also a help constructor passing a Document. You can also add a constructor passing some of the basic properties but this can be added later after we finish with the properties.

///
Empty constructor of the object always required for creating a custom object.
public
vdBox()
{
}
/// Helpfull constructor that also initializes the object with Document's defaults.
/// <param name="Doc">The Document that the object will use.</param>
public vdBox(vdDocument Doc)
{
SetUnRegisterDocument(Doc);
setDocumentDefaults();
}

We will also add some properties for the object:

We will need a VertexList (collection of points) in order to keep the points of the little rectagles
You will also need a centerpoint (gPoint) for the main rectangle
and a MainWidth/MainHeight (double values) for the main
and also LittleWidth/LittleHeight (double values) for the little rectangles
You should add the properties like explained in all our custom objects samples , like below

private
gPoint mInsertionPoint = null;
/// <summary>
///
The Insertion Point of the vdBox object.
/// </summary>
[EditorAttribute(typeof(VectorDraw.Professional.PropertyList.vdPickPointDialog), typeof(System.Drawing.Design.UITypeEditor))]
[
GlobalizedCategory("Geometry")]
[
GlobalizedDisplayName("InsertionPoint")]
[
GlobalizedDescription("Get/Set the Insertion Point of the vdTable object in World Coordinative System.")]
public gPoint InsertionPoint
{
get { if (mInsertionPoint == null)mInsertionPoint = new gPoint(); return mInsertionPoint; }
set
{
if (InsertionPoint.AreEqual(value)) return;
AddHistory(
"InsertionPoint", value); //For the Undo/Redo implementation of VectorDraw
mInsertionPoint.CopyFrom(
value);
}
}

The Globalized... are used in the properties list to display a description on the button , the name of the property and also it's category. You do not have to add these if you do not intend to use our propertieslist in your application.

Now that we have finished the properties (more properties can be added later while the implementation progresses but at least we have the geometrical properties in order to draw the object.

We override the Draw method.

public override VectorDraw.Render.vdRender.DrawStatus Draw(VectorDraw.Render.vdRender render)
{
vdRender.DrawStatus doDraw = base.Draw(render);
if (doDraw == vdRender.DrawStatus.Successed)
{
//Draw stuff here
}
AfterDraw(render);
return doDraw;
}

If the base.Draw is called then the AfterDraw must always be called!!!! Be careful with any try{} catch statements.
These calls basically initialize some features for the draw and also set the base color to be drawn with the vdFigure's pencolor etc...
So for example if we draw a line inside the draw method and the pencolor of the object is red then the line will be red.
You can change colors by using PushPenStyle methods and PopPenStyle (always after) of the render like below


render.PushPenstyle(BackGroundColor, false);
render.DrawSolidPolygon(this, mSegments, vdRender.PolygonType.Simple);
render.PopPenstyle();

Now lets draw the main rectangle but prior explain about the ECS matrix ; I'm sure you have seen the ECSMatrix in our custom objects and also in our VDF  objects. It is much easier to draw your object in user Coordinate System , lets say 0,0,0 and then by using the ECSMatrix transform the object where it is supposed to be drawn. For example we will draw the main rectangle by having the centerpoint to 0,0,0 and then use the InsertionPoint on the ECSMatrix to translate the object there.

double wid = 3.0; //(this Value will Be property among others)
render.PushMatrix(ECSMatrix);
gPoints pts = new gPoints();
pts.Add(
new gPoint (-wid,-wid,0.0));
pts.Add(
new gPoint(wid, -wid, 0.0));
pts.Add(
new gPoint(wid, wid, 0.0));
pts.Add(
new gPoint(-wid, wid, 0.0));
pts.Add(new gPoint (-wid,-wid,0.0));
render.DrawPLine(
this
, pts);
render.PopMatrix();

This will draw a rectangle

Now we override the ECSMatrix and set the InsertionPoint

public override Matrix ECSMatrix
{
get
{
if (mEcsMatrix != null) return mEcsMatrix;
mEcsMatrix =
new Matrix();
mEcsMatrix.TranslateMatrix(InsertionPoint.x, InsertionPoint.y, InsertionPoint.z);
return mEcsMatrix;
}
}

To the EcsMatrix you can add properties Like ExtrusionVector , Rotation , Scale etc... Check our samples.

The last thing that needs implementation before we see our object drawn is the BoundingBox.

public
override Box BoundingBox
{
get
{
if (mBoundBox.IsEmpty)
{
mBoundBox =
new Box();
mBoundBox.AddPoint(
new gPoint());
mBoundBox.AddWidth(3.0);
mBoundBox.TransformBy(ECSMatrix);
}
return mBoundBox;
}
}

The BoundingBox has to be calculated depending the various properties of the object and it is a box that always contains the object.

 
Now after this initial coding our custom object is ready to be added in the entities of a model ( of a Document) and to see it drawn.
Lets go to the Sample application that is used for debugging and after adding the references required lets add this custom object to the Document.

Add the code to a simple test button :
vdBox box = new vdBox(vdFramedControl1.BaseControl.ActiveDocument);
box.InsertionPoint =
new gPoint(10, 10, 0);
vdFramedControl1.BaseControl.ActiveDocument.Model.Entities.AddItem(box);
vdFramedControl1.BaseControl.ActiveDocument.Redraw(
true);

A rectangle is drawn at 10,10 with width 3.0 !!!!

You will notice that this rectangle is already selectable , and you can see it's properties to the framedControl's propertiesList and also change them to see how they interact with the object.
After we finish the draw of the object and it's draw properties then we will have to implement some basic override methods which are required for several methods of vdraw.

First of all we add the Serialize / DeSerialize override methods so the object is saved in vdml/vdcl (Implementation is saving all the properties of the object and can be seen in our samples).

The Update override is called every time a redraw of the item is required. Here you can initialize some private data that have to do with the draw of the object. If you change the color of the object or any other property then this method will be called. For example if you have a hard calculation that is required (and needs time to calculate) for the draw of the object you can keep the result in a private structure. Then in the draw method only do this calculation if the value of the result is null , and set this value = null to the update method. This way if the object is not changed then the calculation will not be called unless an update of the object is required. You only call update outside the custom object in your application if you change a basic property.

Transformby override is called when the object is moved , scaled etc.... For example you can call the CmdMove command and select your object. If you implement the TransformBy then you can move you object by changing it's InsertionPoint in this method.

GetGripPoints is the3 method where you add the grips that you will need for your object.

OnDocumentSelected override is called when the object is added to a Document's Entities. You can do intialization stuff here for the object.

MatchProperties override is required to Clone the object. Clone is used by VectorDraw for example when you call the move command then a cloned object is created and is drawn so you see the object moving. See how this method is implemented using the properties' of the custom object in our samples.

Explode Method is called when you explode the custom object and you should return here VectorDraw primitive Objects like vdRect , vdPolyline , vdCircle etc... This method will also be called if you want to export your object in DWG/DXF file so the result will be saved in these formats.

getOsnapPoints override is used for Osnaps if you want your custom object to show Osnaps while in a command.

After the above implementations your custom object is ready to be added in a Document's Entities , drawn , saved / exported in a format. You can add this object with code.

Now you will have to create a command CreateBox for example.
A simple command like below can be performed by asking your user for a simple point and a width and then create your object.

public
static bool CreateBox(vdDocument Doc)
{
gPoint cen = new gPoint();
Doc.Prompt(
"Insertion Point : ");
object ret = Doc.ActionUtility.getUserPoint();
Doc.Prompt(
null);
if (ret == null || !(ret is gPoint)) return false;
cen = ret
as gPoint;
Doc.Prompt(
"Width : ");
ret = Doc.ActionUtility.getUserDist(cen);
Doc.Prompt(
null);
if (ret == null) return false;
double Width = (double)ret;
vdBox box = new vdBox(Doc);
box.InsertionPoint = cen;
Doc.Model.Entities.AddItem(box);
return true;
}

And call this method in a test button
vdBox.CreateBox(vdFramedControl1.BaseControl.ActiveDocument);

A more complex action can be implemented if you want your user to have interaction and your object to be drawn real-time during the command (for example if you want to see your custom object to be drawn while you select the Width of the Box) using the ActionEntityEx. You can see a good example to the VectorDrawPolygon command CmdPolygon.

Further information can be provided if you have a specific issue creating your custom object. It is impossible to explain all the various implementations that you may want for your custom object. For example you may want different draws in 2D or in 3D , you may want to only select by clicking specific figures , you may want your action to draw other things that do not draw with the object , you may want not to see these objects in viewports and the list/capabilities is endless...