调用控件函数:DrawCustomEntity直接在图上,绘制自定义实体,如下C#代码:
private void button2_Click(object sender, EventArgs e) { // 调用DrawCustomEntity绘制一个自定义实体,实体类型字符串为:DrawCustEntity MxDrawCustomEntity ent = (MxDrawCustomEntity)axMxDrawX1.DrawCustomEntity("DrawCustEntity",""); // 开始设置自定义实体的属性。 ent.BeginSetValue(); // 设置属性Width ent.SetDouble("Width", 30); MxDrawPoint pt1 = new MxDrawPoint(); pt1.x = 10; pt1.y = 10; MxDrawPoint pt2 = new MxDrawPoint(); pt2.x = 100; pt2.y = 200; // 设置属性Point1,Point2 ent.SetPoint("Point1", pt1); ent.SetPoint("Point2", pt2); ent.SetLong("Count", 2); // 结束设置自定义实体的属性。 ent.EntSetValue(); // 更新显示 axMxDrawX1.UpdateDisplay(); }
下面函数MyDrawMline,用来具体绘制自定义实体,将用在后面的事件中调用。
// MyDrawMline,用来绘制我们的自定义实体 private void MyDrawMline(MxDrawWorldDraw pWorldDraw, MxDrawCustomEntity pCustomEntity, MxDrawPoint curPt) { // 取自定义实体的端点数目。 if (!pCustomEntity.IsHave("Count")) return; long lCount = pCustomEntity.GetLong("Count"); MxDrawPolyline tmpPl = new MxDrawPolyline(); for (long i = 0; i < lCount; i++) { String sName; sName = "Point" + (i + 1).ToString(); if (!pCustomEntity.IsHave(sName)) break; // 取自定义实体的端点坐标。 MxDrawPoint pt = pCustomEntity.GetPoint(sName); // 把端点坐标,传给pl线,用于生成双线。 tmpPl.AddVertexAt(pt); } if (curPt != null) tmpPl.AddVertexAt(curPt); if (tmpPl.NumVerts < 2) { // 端点数少于2就,不构成直线,就不需要显示。 return; } // 求pl线,开始点的导数. MxDrawVector3d vecFx; if (!tmpPl.GetFirstDeriv(tmpPl.GetStartParam(), out vecFx)) return; if (vecFx.IsZeroLength()) return; // 把向量旋转90度. vecFx.RotateByXyPlan(3.14159265 / 2.0); vecFx.Normalize(); // 得到双线的宽度属性。 double dWidth = pCustomEntity.GetDouble("Width"); vecFx.Mult(dWidth); MxDrawPoint startPt = tmpPl.GetStartPoint(); // 向pl线,两个方向偏移, MxDrawPoint offsetPt1 = new MxDrawPoint(); offsetPt1.x = startPt.x; offsetPt1.y = startPt.y; offsetPt1.Add(vecFx); MxDrawPoint offsetPt2 = new MxDrawPoint(); offsetPt2.x = startPt.x; offsetPt2.y = startPt.y; offsetPt2.Sum(vecFx); MxDrawText text = new MxDrawText(); text.TextString = "Test"; text.Height = 100; text.Position = startPt; text.AlignmentPoint = startPt; MxDrawPoint pt1, pt2; text.GetBoundingBox(out pt1, out pt2); MxDrawPoint pt3 = new MxDrawPoint(); pt3.x = pt1.x; pt3.y = pt2.y; MxDrawPoint pt4 = new MxDrawPoint(); pt4.x = pt2.x; pt4.y = pt1.y; MxDrawPoints pts = new MxDrawPoints(); pts.Add(pt1.x, pt1.y, 0); pts.Add(pt3.x, pt3.y, 0); pts.Add(pt2.x, pt2.y, 0); pts.Add(pt4.x, pt4.y, 0); Int32 lDraworder = pWorldDraw.Draworder; pWorldDraw.Draworder = lDraworder + 1; pWorldDraw.DrawWipeout(pts); pWorldDraw.Draworder = lDraworder + 2; pWorldDraw.DrawEntity((MxDrawEntity)text); pWorldDraw.Draworder = lDraworder; // pWorldDraw-> { MxDrawResbuf newobj; if (tmpPl.OffsetCurves(dWidth, offsetPt1, out newobj)) { for (Int32 j = 0; j < newobj.Count; j++) { MxDrawEntity tmpObj = (MxDrawEntity)newobj.AtObject(j); if (tmpObj == null) continue; pWorldDraw.DrawEntity(tmpObj); } newobj.RemoveAll(); } } { MxDrawResbuf newobj; if (tmpPl.OffsetCurves(dWidth, offsetPt2, out newobj)) { for (Int32 j = 0; j < newobj.Count; j++) { MxDrawEntity tmpObj = (MxDrawEntity)newobj.AtObject(j); if (tmpObj == null) continue; pWorldDraw.DrawEntity(tmpObj); } // 这不使用newobj,需要显示调用RemoveAll函数清楚内存。 // 不然这个可能就会程序退出时才释放,这时它会去释放控件对象指针,有可能会出错。 newobj.RemoveAll(); } } }
下面代码让用户在图上循环点取点坐标,直接到按ESC退出,然后绘制自定义实体,在点取点过程中可以看动态画制效果,C#代码实现如下:
private void DrawMlineCommand() { // 定义取点变量。 MxDrawUiPrPoint getPt = new MxDrawUiPrPoint(); getPt.message = "点取第一点"; // 等用户在图上点取一个点 if (getPt.go() != MCAD_McUiPrStatus.mcOk) { return; } // 返回点的点对象值。 var frstPt = getPt.value(); if (frstPt == null) { return; } // 定义第二个取点变量。 MxDrawUiPrPoint getSecondPt = new MxDrawUiPrPoint(); getSecondPt.message = "点取第二点"; getSecondPt.basePoint = frstPt; getSecondPt.setUseBasePt(false); // 设置在取点时的动态绘制. MxDrawCustomEntity spDrawData = getSecondPt.InitUserDraw("DrawCustEntity"); // 设置绘制变量。Width,Point1 spDrawData.SetDouble("Width", 30); spDrawData.SetPoint("Point1", frstPt); Int32 lCount = 1; spDrawData.SetLong("Count", 1); // 循环取点,直到用户按ESC取消. while (true) { if (getSecondPt.go() != MCAD_McUiPrStatus.mcOk) break; var secondPt = getSecondPt.value(); if (secondPt == null) break; lCount++; String sPointName = "Point" + lCount.ToString(); spDrawData.SetPoint(sPointName, secondPt); spDrawData.SetLong("Count", lCount); } // 把自定义实本对象spDrawData画在图上。 if (lCount > 1) axMxDrawX1.DrawEntity(spDrawData); }
添加控件DynWorldDraw事件,在事件中响应自定义实体的动态绘制,C#代码实现如下:
private void axMxDrawX1_DynWorldDraw(object sender, AxMxDrawXLib._DMxDrawXEvents_DynWorldDrawEvent e) { // 得到当前动态绘制数据。 MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pData; String sGuid = pCustomEntity.Guid; e.pRet = 0; // 得到绘制对象. MxDrawWorldDraw pWorldDraw = (MxDrawWorldDraw)e.pWorldDraw; // 得到当前鼠标点. MxDrawPoint curPt = new MxDrawPoint(); curPt.x = e.dX; curPt.y = e.dY; if (sGuid == "DrawCustEntity") { // 动态绘制DrawCustEntity MyDrawMline(pWorldDraw, pCustomEntity, curPt); } }
需要添加DMxDrawXEvents::CustomEntity_Explode事件,绘制自定义实体
注意:该事件必须实现,如果不实现自定义实体将不会保存到图纸中。
如:C#代码实现如下:
private void axMxDrawX1_CustomEntity_Explode(object sender, AxMxDrawXLib._DMxDrawXEvents_CustomEntity_ExplodeEvent e) { // 得到自定义实体对象. MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pCustomEntity; // 得到自定义实体类型 var sGuid = pCustomEntity.Guid; // 得到绘制对象. MxDrawWorldDraw pWorldDraw = (MxDrawWorldDraw)e.pDraw; if (sGuid == "DrawCustEntity") { // 绘制自定义实体. MyDrawMline(pWorldDraw, pCustomEntity, null); e.pRet = 1; } }
自定义实体支持夹点编辑,下面事件返回实体的夹点
需要响应_DMxDrawXEvents::CustomEntity_getGripPoints事件,C#代码实现如下:
private void axMxDrawX1_CustomEntity_getGripPoints(object sender, AxMxDrawXLib._DMxDrawXEvents_CustomEntity_getGripPointsEvent e) { // 得到自定义实体对象. MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pCustomEntity; // 得到自定实体类型 var sGuid = pCustomEntity.Guid; e.pOk = 0; if (sGuid == "DrawCustEntity") { if (!pCustomEntity.IsHave("Count")) return; long lCount = pCustomEntity.GetLong("Count"); // 把需要的夹点数据,放在ret链表中,用于返回 MxDrawResbuf ret = (MxDrawResbuf)axMxDrawX1.NewResbuf(); for (long i = 0; i < lCount; i++) { String sName; sName = "Point" + (i + 1).ToString(); if (!pCustomEntity.IsHave(sName)) break; // 取自定义实体的端点坐标。 MxDrawPoint pt = pCustomEntity.GetPoint(sName); ret.AddPoint(pt); } e.pOk = 1; // 返回夹点数据。 axMxDrawX1.SetEventRetEx(ret); } }
自定义实体夹点移动后,调用moveGripPointsAt事件修改自定义实体。
响应CustomEntity_moveGripPointsAt事件。
下面例子夹点移动后,在moveGripPointsAt修改自定义实体的点坐标,C#代码实现如下:
private void axMxDrawX1_CustomEntity_moveGripPointsAt(object sender, AxMxDrawXLib._DMxDrawXEvents_CustomEntity_moveGripPointsAtEvent e) { e.pRet = 1; // 得到自定义实体对像. MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pCustomEntity; var sGuid = pCustomEntity.Guid; if (sGuid == "DrawCustEntity") { if (!pCustomEntity.IsHave("Count")) return; long lCount = pCustomEntity.GetLong("Count"); for (long i = 0; i < lCount; i++) { String sName; sName = "Point" + (i + 1).ToString(); if (!pCustomEntity.IsHave(sName)) break; // 取自定义实体的端点坐标。 MxDrawPoint pt = pCustomEntity.GetPoint(sName); // e.lGridIndex表示移动了第几个夹点. if (i == e.lGridIndex) { pt.x = pt.x + e.dOffsetX; pt.y = pt.y + e.dOffsetY; // 修改移动后的点坐标值。 pCustomEntity.SetPoint(sName, pt); } } } }
想要支持自定义实体的移动,旋转,缩放功能,需要添加坐标变换事件处理,事件名:CustomEntity_transformBy
函数实现c#代码如下:
private void axMxDrawX1_CustomEntity_transformBy(object sender, _DMxDrawXEvents_CustomEntity_transformByEvent e) { e.pOk = 1; MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pCustomEntity; // 得到自定义实体类型 var sGuid = pCustomEntity.Guid; if (sGuid == "DrawCustEntity") { if (!pCustomEntity.IsHave("Count")) return; long lCount = pCustomEntity.GetLong("Count"); // 对实体的点坐标进行坐标变换。 for (long i = 0; i < lCount; i++) { String sName; sName = "Point" + (i + 1).ToString(); if (!pCustomEntity.IsHave(sName)) break; // 取自定义实体的端点坐标。 MxDrawPoint pt = pCustomEntity.GetPoint(sName); // 计算出新的坐标。 pt.TransformBy((MxDrawMatrix3d)e.pMatXform); pCustomEntity.SetPoint(sName, pt); } } }
如果需要捕捉两个实体的交点,需要响应自定义实体求交事件:CustomEntity_intersectWith
下面c#代码响应求交事件,然后得到自定义实体,计算出交点返回:
private void axMxDrawX1_CustomEntity_intersectWith(object sender, _DMxDrawXEvents_CustomEntity_intersectWithEvent e) { // 得到自定义实体。 MxDrawEntity pThis = (MxDrawEntity)e.pCustomEntity; // 得到另一个求交的实体。 MxDrawEntity pOther = (MxDrawEntity)e.pOhterEntity; if (pThis.ObjectName != "MxDrawXCustomEntity" || pOther.ObjectName != "MxDrawXCustomEntity") return; MxDrawCustomEntity pEnt1 = (MxDrawCustomEntity)pThis; MxDrawCustomEntity pEnt2 = (MxDrawCustomEntity)pOther; // 判断自定义有没有我们需要的属性。 if (!pEnt1.IsHave("Point1")) return; if (!pEnt1.IsHave("Point2")) return; if (!pEnt2.IsHave("Point1")) return; if (!pEnt2.IsHave("Point2")) return; // 取自定义实体的端点坐标。 MxDrawPoint pt11 = pEnt1.GetPoint("Point1"); MxDrawPoint pt12 = pEnt1.GetPoint("Point2"); MxDrawPoint pt21 = pEnt2.GetPoint("Point1"); MxDrawPoint pt22 = pEnt2.GetPoint("Point2"); // 创建两个临时的直线,用来求交点。 MxDrawLine line1 = new MxDrawLine(); line1.StartPoint = pt11; line1.EndPoint = pt12; MxDrawLine line2 = new MxDrawLine(); line2.StartPoint = pt21; line2.EndPoint = pt22; // 返回求到的交点。 MxDrawPoints pts = line1.IntersectWith(line2, MCAD_McExtendOption.mcExtendNone); if(pts.Count > 0 ) { MxDrawResbuf ret = (MxDrawResbuf)axMxDrawX1.NewResbuf(); for (Int32 i = 0; i < pts.Count; i++) { ret.AddPoint(pts.Item(i)); } // 告诉控件,求到了交点。 e.pOk = 1; axMxDrawX1.SetEventRetEx(ret); } }
如果需要捕捉自定义实体的端点,最近点等,需要响应捕捉事件:CustomEntity_getOsnapPoints
如下C#代码,返回自定义实体的端点,计算最近点并返回。
// 响应该事件,计算自定义实体捕捉点 private void axMxDrawX1_CustomEntity_getOsnapPoints(object sender, _DMxDrawXEvents_CustomEntity_getOsnapPointsEvent e) { // enum OsnapMode { kOsModeEnd = 1, // kOsModeMid = 2, // kOsModeCen = 3, // kOsModeNode = 4, // kOsModeQuad = 5, // kOsModeIns = 7, // kOsModePerp = 8, // kOsModeTan = 9, // kOsModeNear = 10, // kOsModeInt = 11 // }; e.pOk = 0; // 得到自义实体对象。 MxDrawCustomEntity pCustomEntity = (MxDrawCustomEntity)e.pCustomEntity; String sGuid = pCustomEntity.Guid; if (sGuid == "DrawCustEntity") { if (!pCustomEntity.IsHave("Count")) return; // 得到点数. long lCount = pCustomEntity.GetLong("Count"); if (lCount < 2) return; if (e.lOsnapMode == 1) { // 端点捕捉。 MxDrawPoint pickPoint = (MxDrawPoint)axMxDrawX1.NewPoint(); // 得到当前鼠标点。 pickPoint.x = e.dPickPointX; pickPoint.y = e.dPickPointY; // 得到开始点,结束点。 String sName = "Point1"; MxDrawPoint stp = pCustomEntity.GetPoint(sName); sName = "Point" + lCount.ToString(); MxDrawPoint ept = pCustomEntity.GetPoint(sName); // 计算出当前点与那个点最近,然后返回. Double dDis1 = pickPoint.DistanceTo(stp); Double dDis2 = pickPoint.DistanceTo(ept); if (dDis1 < dDis2) { e.pSnapPointsX = stp.x; e.pSnapPointsY = stp.y; } else { e.pSnapPointsX = ept.x; e.pSnapPointsY = ept.y; } e.pOk = 1; } else if (e.lOsnapMode == 10) { // 最近点捕捉。 MxDrawPolyline pl = new MxDrawPolyline(); // 把自定义实体变成一个 PL线,用于计算最近点坐标。 for (long i = 0; i < lCount; i++) { String sName; sName = "Point" + (i + 1).ToString(); if (!pCustomEntity.IsHave(sName)) break; // 取自定义实体的端点坐标。 MxDrawPoint pt = pCustomEntity.GetPoint(sName); pl.AddVertexAt(pt); } // 得到当前鼠标点。 MxDrawPoint pickPoint = (MxDrawPoint)axMxDrawX1.NewPoint(); pickPoint.x = e.dPickPointX; pickPoint.y = e.dPickPointY; // 计算最近点。 MxDrawPoint closePoint = pl.GetClosestPointTo2(pickPoint, false); if (closePoint != null) { // 计算最点,然后返回。 e.pSnapPointsX = closePoint.x; e.pSnapPointsY = closePoint.y; e.pOk = 1; } } } }
运行效果如下图 :