qjchen 发表于 2011-1-4 22:55:29

[飞马小程序] 带Jig效果的过一点绘制垂直于曲线的直线段

本帖最后由 qjchen 于 2011-12-20 11:53 编辑

这段代码主要是为了弥补LISP中grread较难实现捕捉的缺点
各位见笑了 :)

撰写此段代码的时候,学习了ahlzl兄和飞狐兄的相关代码,谢谢两位~

平台 : VS2008+CAD2007
命令 : JPE
效果 :如下



代码 :


using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
namespace JigPerToCurve
{
    public class Class0 : IExtensionApplication
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      // 加载程序时的初始化操作
      void IExtensionApplication.Initialize()
      {
            ed.WriteMessage("**Write by qjchen@gmail.com, To draw a line per to a curve, Command:JPE");
      }
      // 卸载程序时的清除操作
      void IExtensionApplication.Terminate()
      {
      }
    }
    public class Class1 : DrawJig
    {
      private Line ent;
      private Curve curve;
      
      public void Createjigjdx()
      {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptEntityOptions optEnt = new PromptEntityOptions("\n选择曲线:");
            PromptEntityResult resEnt = ed.GetEntity(optEnt);
            if (resEnt.Status == PromptStatus.OK)
            {
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                  BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                  BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt, OpenMode.ForWrite);
                  curve = (Curve)(trans.GetObject(resEnt.ObjectId, OpenMode.ForWrite));
                  ent = new Line(Point3d.Origin, Point3d.Origin);
                  PromptResult resJig = ed.Drag(this);
                  if (resJig.Status == PromptStatus.OK)
                  {
                        btr.AppendEntity(ent);
                        trans.AddNewlyCreatedDBObject(ent, true);
                  }
                  trans.Commit();
                }
            }
      }
      // Sampler函数用于检测用户的输入.
      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
            Database db = HostApplicationServices.WorkingDatabase;
            JigPromptPointOptions optJigDis = new JigPromptPointOptions("\n请指定一个新的点");
            optJigDis.UserInputControls = UserInputControls.Accept3dCoordinates;
            PromptPointResult resJigDis = prompts.AcquirePoint(optJigDis);
            //curPt就是现在屏幕上鼠标位置点
            Point3d curPt = resJigDis.Value;
            //下面这句话很重要,不然会出错,必须保证这个点是在线上
            Point3d point = curve.GetClosestPointTo(curPt, false);
            if (resJigDis.Status == PromptStatus.Cancel)
            {
                return SamplerStatus.Cancel;
            }
            Vector3d vtan = curve.GetFirstDerivative(point);
            Vector3d vnor0 = vtan.RotateBy(Math.PI / 2, Vector3d.ZAxis).GetNormal();
            Vector3d vnor1 = vtan.RotateBy(-Math.PI / 2, Vector3d.ZAxis).GetNormal();
            double vsize = (double)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("VIEWSIZE");
            Point3d point_per0 = point + vnor0.MultiplyBy(vsize / 5.0);
            Point3d point_per1 = point + vnor1.MultiplyBy(vsize / 5.0);
            //判断当前点在曲线的哪边,若相等的时候取默认的
            if (point_per1.DistanceTo(curPt) < point_per0.DistanceTo(curPt))
            {
                point_per0 = point_per1;
            }
            ent.StartPoint = point;
            ent.EndPoint = point_per0;
            return SamplerStatus.OK;
      }
      // WorldDraw函数用于刷新屏幕上显示的图形.
      protected override bool WorldDraw(WorldDraw draw)
      {
            // 刷新画面.
            draw.Geometry.Draw(ent);
            return true;
      }
    }
}


雪山飞狐_lzh 发表于 2011-1-4 23:17:38

点的计算也可以这样
var ver = (point - curpt).GetNormal() * vsize / 5.0;
ent.StartPoint = point;
ent.EndPoint = point + vec;
最近点与当前点的连线应该就是垂线吧
当然,如果相等还是应该按切向量的垂直方向
另外,还应该判断是否在曲线以外

qjchen 发表于 2011-1-5 08:38:51

本帖最后由 qjchen 于 2011-1-5 08:40 编辑

To 飞狐兄~
谢谢指导,直接连接curPt和point确实是好方法:)
刚才我又仔细想了一下
最近点与当前点的连线应该就是垂线吧==> 这个不一定,在端部的地方就不是这样
当然,如果相等还是应该按切向量的垂直方向,另外,还应该判断是否在曲线以外==> 确实如此

我上面的程序,假如不考虑Jig的画,那么编起来倒是简单些,只需要GetPoint就可以了,这样子得到的点肯定在曲线上,但是后来我加上了Jig之后,就发现

PromptPointResult resJigDis = prompts.AcquirePoint(optJigDis);
          //curPt就是现在屏幕上鼠标位置点
            Point3d curPt = resJigDis.Value;
            //下面这句话很重要,不然会出错,必须保证这个点是在线上
            Point3d point = curve.GetClosestPointTo(curPt, false);

CurPt点只是鼠标当前位置点,并不保证在曲线上的,所以 .GetFirstDerivative会出错,而我的程序的目的是要完成 过曲线上一点做垂线的 ,而非过曲线外一点的(假如那样的画,用per捕捉即可),所以只好用了这个方法,所以就导致了后面 鼠标沿曲线走动的时候,若出了曲线区域,在端点的部分仍然采用垂线的做法。

这段程序的局限在于,其实Jig只是花哨用的,真正用捕捉取到曲线上点的时候,它无法正确画出用户需要的向曲线的哪边画垂线的目的。可能得修改一下,变成一个先确定取点,再Jig方向的程序(不过这个用Lisp可能更简单)。

谢谢飞狐兄的指导~




669423907 发表于 2011-3-30 23:28:29

好程序!请问复制代码后该保存什么格式呢?

llikk_love 发表于 2011-12-26 11:24:44

好程序啊。

gyl 发表于 2011-12-27 08:51:07

不错的程序,有实用意义。

david.xw 发表于 2012-1-11 10:49:58

不错的程序,收藏,收后参考用!

zhengjian211 发表于 2012-4-4 22:14:59

请问楼主:能不能不需要去掉选择曲线这一句:
PromptEntityOptions optEnt = new PromptEntityOptions("\n选择曲线:");
PromptEntityResult resEnt = ed.GetEntity(optEnt);

能直接通过jig移动时的点来获取此曲线吗?这样只需要1步操作。
简单说就是 如何获取通过某点的曲线呢?
不知道我表达清楚没有。

凤在江湖 发表于 2012-4-10 11:49:06

正需要学习呢

mapzq 发表于 2012-9-3 11:31:52

什么格式这个代码?
页: [1] 2
查看完整版本: 带Jig效果的过一点绘制垂直于曲线的直线段