VDF常见问题整理(十二):复杂自定义对象的入门指南
VectorDraw Developer Framework(VDF)是一个用于应用程序可视化的图形引擎库。有了VDF提供的功能,您可以轻松地创建、编辑、管理、输出、输入和打印2D和3D图形文件。
VectorDraw Developer Framework试用版下载
问:
能否提供复杂自定义对象的入门指南?
答:
我们将尝试为您提供有关自定义对象的详细说明以及您应该如何尝试实现此类实现。我们的指南是针对C#中的.NET项目,主要是我们使用的编程语言。
首先,您必须创建一个包含2个项目的解决方案,就像我们的样本中实现的那样。一个项目将是一个非常简单的控件形式(可滚动,框架无关紧要),最好是vdFramedControl,因为具有属性列表和命令行的vdFramedControl将为您提供一个很好的调试项目。在任何情况下,您为vdFramedControl编写的代码对于vdScrollableControl都是相同的。所以我们有一个带有vdFramedControl的项目和一些用于测试自定义对象的按钮。
第二个项目将是一个DLL,它将包含您的自定义对象(与我们的示例中的完全相同)。具有该表单的其他项目需要此项目的引用,以便您可以使用自定义对象进行测试。
完成自定义对象的实现后,可以在主应用程序中引用dll而不会出现问题,您可以使用此解决方案来测试和调试自定义对象。
现在,在这些初始设置之后,我们开始使用自定义对象。
首先,您需要为自定义对象提供一些属性,这些属性与它的几何有关,以及如何绘制此对象。再找一个vdFigure对象并定义这样的对象。
public class vdBox :vdFigure , IvdProxyFigure
作为vdFigure的vdBox,已经有一个pencolor,一个图层,一个penstyle等,接下来将可以用于绘制对象(稍后将在draw方法中解释)。
这样的自定义对象需要IvdProxyFigure,为对象添加一个空构造函数,还有一个传递Document的帮助构造函数。您还可以添加一个传递一些基本属性的构造函数,但这可以在我们完成属性后添加。
/// 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. /// The Document that the object will use.public vdBox(vdDocument Doc) { SetUnRegisterDocument(Doc); setDocumentDefaults(); }
我们还将为对象添加一些属性:
-
我们需要一个VertexList(点集合)来保持小矩形的点。
-
您还需要一个主矩形的中心点(gPoint)。
-
main的MainWidth / MainHeight(双精度值)。
-
小矩形的LittleWidth / LittleHeight(双值)。
-
您应该添加所有自定义对象示例中所述的属性,如下所示。
private gPoint mInsertionPoint = null; /// /// The Insertion Point of the vdBox object. /// [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); } }
Globalized ...在属性列表中用于显示按钮的描述,属性的名称以及它的类别。如果您不打算在应用程序中使用我们的属性列表,则不必添加这些内容。
现在我们已经完成了属性的设置,接下来需要重写Draw方法。
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; }
如果调用base.Draw,那么必须始终调用AfterDraw,小心任何try {} catch语句。
这些调用基本上会初始化绘制的一些功能,并设置基本颜色用vdFigure的pencolor等绘制,因此,如果我们在draw方法中绘制一条线并且该对象的pencolor为红色,那么该线将为红色。
您可以使用如下所示的渲染的PushPenStyle方法和PopPenStyle(总是在后面)来更改颜色。
render.PushPenstyle(BackGroundColor, false); render.DrawSolidPolygon(this, mSegments, vdRender.PolygonType.Simple); render.PopPenstyle();
现在需要绘制主矩形,但事先解释一下ECS矩阵,您可以在我们的自定义对象和VDF对象中看到ECSMatrix。在用户坐标系中绘制对象要容易得多,比方说0,0,0然后使用ECSMatrix转换绘制对象。例如,我们将通过将中心点设置为0,0,0绘制主矩形,然后使用ECSMatrix上的InsertionPoint将对象转换到那里。
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();
这将绘制一个矩形。现在我们覆盖ECSMatrix并设置InsertionPoint。
public override Matrix ECSMatrix { get { if (mEcsMatrix != null) return mEcsMatrix; mEcsMatrix = new Matrix(); mEcsMatrix.TranslateMatrix(InsertionPoint.x, InsertionPoint.y, InsertionPoint.z); return mEcsMatrix; } }
对于EcsMatrix,您可以添加属性,如ExtrusionVector,Rotation,Scale等查看我们的样品。在我们看到绘制对象之前需要实现的最后一件事是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; } }
必须根据对象的各种属性计算BoundingBox,它是一个始终包含对象的框。
现在,在初始编码之后,我们可以将自定义对象添加到模型(文档)的实体中并查看它。转到用于调试的Sample应用程序,在添加所需的引用之后,让我们将此自定义对象添加到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);
注意:矩形以10,10绘制,宽度为3.0。
这个矩形已经可以选择,您可以看到它的属性-framedControl的propertiesList,并且还可以更改它们以查看它们如何与对象交互。
在我们完成对象的绘制和它的绘制属性之后,我们将不得不实现一些基本的覆盖方法,这些方法是几种vdraw方法所必需的。
首先,我们添加Serialize / DeSerialize覆盖方法,以便将对象保存在vdml / vdcl中(实现保存了对象的所有属性,可以在我们的示例中看到)。
每次需要重绘项目时都会调用Update覆盖。在这里,您可以初始化一些与对象绘制有关的私有数据。如果更改对象或任何其他属性的颜色,则将调用此方法。例如,如果您对对象的绘制进行了必要的硬计算(并且需要时间来计算),则可以将结果保存在私有结构中。然后在draw方法中,如果结果的值为null,则仅执行此计算,并将此value = null设置为update方法。这样,如果对象未更改,则除非需要更新对象,否则不会调用计算。如果更改基本属性,则只在应用程序中的自定义对象外调用update。
移动或缩放对象时调用Transformby覆盖。例如,您可以调用CmdMove命令并选择对象。如果您实现TransformBy,那么您可以通过在此方法中更改它的InsertionPoint来移动您的对象。GetGripPoints是一种方法,您可以在其中添加对象所需的夹点。将对象添加到Document的实体时,将调用OnDocumentSelected override。你可以在这里为对象做初始化的东西。
克隆对象需要MatchProperties覆盖。例如,当您调用move命令然后创建并绘制克隆对象以便您看到对象移动时,VectorDraw将使用克隆。了解如何使用示例中自定义对象的属性实现此方法。
在爆炸自定义对象时调用爆炸方法,你应该在这里返回VectorDraw原语像vdRect,vdPolyline,vdCircle等对象。如果要在DWG / DXF文件中导出对象,也会调用此方法,结果将是以这些格式保存。
如果希望自定义对象在命令中显示Osnaps,则会将getOsnapPoints覆盖用于Osnaps。
完成上述操作后,您可以将自定义对象添加到文档的实体中,以格式绘制,保存/导出。您可以使用代码添加此对象。
现在,您必须创建一个命令CreateBox。通过向用户询问简单的点和宽度然后创建对象,可以执行如下的简单命令。
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; }
并在测试按钮中调用此方法。
vdBox.CreateBox(vdFramedControl1.BaseControl.ActiveDocument);
如果您希望用户进行交互并在命令期间实时绘制对象,则可以实现更复杂的操作(例如,如果要在选择框的宽度时查看要绘制的自定义对象) 使用ActionEntityEx。您可以在VectorDrawPolygon命令的CmdPolygon中看到一个很好的示例。
相关资料推荐:
VectorDraw Developer Framework(VDF)示例