AutoCad 二次开发 文字镜像

在autocad中如果使用Mirror命令把块参照给镜像了(最终得到一个对称的块),块里面的文字包括DBText和MText以及标注上面的文字都会被对称,变得不易阅读。而在单个字体实体和标注实体镜像的时候只要设置系统变量mirrtext为0镜像后的文字就不会与原文字对称变成我们未学习过的文字了。
 
所以我们在镜像块的时候就可以先把块炸开是用快捷键X,或者输入explode,然后在使用镜像命令。之后在把对称后的实体集合组成一个新的块。不过这样操作十分的繁琐,我觉得其中这样做的优势是mirror时的jig操作可以很方便的预先知道我们想要的对称后的结果。但如果用代码实现这种jig操作,我觉得有点复杂,目前我还不知道怎么实现。
 
我要讲的主要就是用代码来实现块的镜像。难点就在与文字的镜像,和标注的镜像。这篇文章先讲文字的镜像。文字镜像的主要步骤分为:
1.找到镜像前文字边界的四个角,这四个角构成了一个矩形,我们要求得这个矩形的长和宽所代表的向量。
2.判断文字镜像后的方向,如果是偏向朝Y轴镜像,那么文字镜像后的方向是沿着X轴翻转的,如果是偏向朝X轴镜像,那么文字镜像后的方向是沿着X轴翻转的。这里我以沿着Y轴镜像为例子。
3.移动镜像后切被翻转后的文字,这里也是根据镜像轴的不同,需按不同的向量来移动。
 
详细情况见图:
图中左边是要镜像的文字,文字上的蓝色线,和黄色线是我调试的时候加入的,黄线左端是 pt1,右端是pt2,蓝线左端是pt3,右端是pt4。 中间的竖线是Y轴镜像线,右边就是不同情况下镜像后的文字。其中黄色部分表示正确的镜像结果,红色部分表示:镜像后延第一个步骤移动后求得的向量移动了文字的position但是没翻转的结果。黑色部分表示:镜像后翻转了文字但文字的position没有按向量移动的结果。
下面我就来仔细分析一下代码:
要实现第一步骤,前提是要有一段P/Invoke的代码:
其中 引入的acdb22.dll是 autocad2018中的版本,不同版本,这个dll后面的数字不一样。我们可以到cad安装目录下查找acdb几个字,找到后面带数字的就是了,64位的安装目录默认位置:C:\Program Files\Autodesk\AutoCAD 2018。这两个函数一个是32位,一个是64位,具体用哪个后面的代码会自动判断。这个函数作用我觉得主要是求 这个name。
 
这里用到了accore.dll,有的cad版本没有这个dll,就用acad.exe代替就可以了。上面的acdbEntGet主要是根据entity的名字求的entity实体的Intptr,下面的函数时求的文字边界对角点,这里注意,我把这个两个点用直线打印在cad空间里,发现它时在原点,没旋转的线,但其实文字不的position不在原点,也带有旋转角度。后面要求的文字边界向量就是根据这两个点来的。
上面求得的pt1,pt2 经过:
pt1 = pt1.TransformBy(rotMat).Add(dbText.Position.GetAsVector());
pt2 = pt2.TransformBy(rotMat).Add(dbText.Position.GetAsVector());
这种操作就得到了第一幅图中的黄线。
在经过这样的操作,得到的pt3 和pt4就是第一幅图的蓝线。这其中的rotDir和linDir就是我们要求得的宽和长代表的向量了,然后在把它给镜像了得到的mirRotDir和mirLinDir就是镜像后的文字要移动的向量了,这里第一步就结束了。
第二步,第三步:

大的话,就说明文字需要朝X轴翻转,所以这里的IsMirroredInX=true就代表需要朝X轴翻转。
紧接着下面句,如果没加mirLineDir这个向量,就会出现第一幅图中的画黑线的情况,如果不加IsMirrorInX就会出现画红线的情况。
到这里就全部结束了。
下面给出所有代码:
public class MyMirror
{
Document Doc = Application.DocumentManager.MdiActiveDocument;
Editor Ed = Application.DocumentManager.MdiActiveDocument.Editor;
Database Db = Application.DocumentManager.MdiActiveDocument.Database; List<Entity> list = new List<Entity>();
List<ObjectId> listOId = new List<ObjectId>(); [CommandMethod("testM")] public void MirrorTextCmd() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; //Entity selection PromptEntityOptions peo = new PromptEntityOptions( "\nSelect a text entity:"); peo.SetRejectMessage("\nMust be text entity..."); peo.AddAllowedClass(typeof(DBText), true); PromptEntityResult perText = ed.GetEntity(peo); if (perText.Status != PromptStatus.OK) return; peo = new PromptEntityOptions("\nSelect a mirror line:"); peo.SetRejectMessage("\nMust be a line entity..."); peo.AddAllowedClass(typeof(Line), true); PromptEntityResult perLine = ed.GetEntity(peo); if (perLine.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { Line line = tr.GetObject(perLine.ObjectId, OpenMode.ForRead) as Line; Line3d mirrorLine = new Line3d( line.StartPoint, line.EndPoint); MirrorText(perText.ObjectId, mirrorLine); tr.Commit(); } } void MirrorText(ObjectId oId, Line3d mirrorLine) { Database db = oId.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { // Get text entity DBText dbText = tr.GetObject(oId, OpenMode.ForRead) as DBText; // Clone original entity DBText mirroredTxt = dbText.Clone() as DBText; // Create a mirror matrix Matrix3d mirrorMatrix = Matrix3d.Mirroring(mirrorLine); // Do a geometric mirror on the cloned text mirroredTxt.TransformBy(mirrorMatrix); // Get text bounding box Point3d pt1, pt2, pt3, pt4; GetTextBoxCorners( dbText, out pt1, out pt2, out pt3, out pt4); // Get the perpendicular direction to the original text Vector3d rotDir = pt4.Subtract(pt1.GetAsVector()).GetAsVector(); // Get the colinear direction to the original text Vector3d linDir = pt3.Subtract(pt1.GetAsVector()).GetAsVector(); // Compute mirrored directions Vector3d mirRotDir = rotDir.TransformBy(mirrorMatrix); Vector3d mirLinDir = linDir.TransformBy(mirrorMatrix); //Check if we need to mirror in Y or in X if (Math.Abs(mirrorLine.Direction.Y) > Math.Abs(mirrorLine.Direction.X)) { // Handle the case where text is mirrored twice // instead of doing "oMirroredTxt.IsMirroredInX = true" mirroredTxt.IsMirroredInX = !mirroredTxt.IsMirroredInX; mirroredTxt.Position = mirroredTxt.Position + mirLinDir; } else { mirroredTxt.IsMirroredInY = !mirroredTxt.IsMirroredInY; mirroredTxt.Position = mirroredTxt.Position + mirRotDir; } // Add mirrored text to database //btr.AppendEntity(mirroredTxt); //tr.AddNewlyCreatedDBObject(mirroredTxt, true); //list.Add(mirroredTxt);
mirroredTxt.ToSpace();
tr.Commit(); } }
#region p/Invoke public struct ads_name
{ public IntPtr a; public IntPtr b; }; // Exported function names valid only for R19 [DllImport("acdb22.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")] public static extern int acdbGetAdsName32( ref ads_name name, ObjectId objId); [DllImport("acdb22.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] public static extern int acdbGetAdsName64( ref ads_name name, ObjectId objId); public static int acdbGetAdsName(ref ads_name name, ObjectId objId) { if (Marshal.SizeOf(IntPtr.Zero) > ) return acdbGetAdsName64(ref name, objId); return acdbGetAdsName32(ref name, objId); } [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acdbEntGet")] public static extern System.IntPtr acdbEntGet( ref ads_name ename); [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTextBox")] public static extern System.IntPtr acedTextBox( IntPtr rb, double[] point1, double[] point2); void GetTextBoxCorners(DBText dbText, out Point3d pt1, out Point3d pt2, out Point3d pt3, out Point3d pt4) { ads_name name = new ads_name(); int result = acdbGetAdsName( ref name, dbText.ObjectId); ResultBuffer rb = new ResultBuffer(); Interop.AttachUnmanagedObject( rb, acdbEntGet(ref name), true); double[] point1 = new double[]; double[] point2 = new double[]; // Call imported arx function acedTextBox(rb.UnmanagedObject, point1, point2); pt1 = new Point3d(point1); pt2 = new Point3d(point2); var ptX = pt1 + Vector3d.XAxis * ;
var ptY = pt2 + Vector3d.YAxis * ; var lX = new Line(pt1, ptX);
var lY = new Line(pt2, ptY); lX.Color= Color.FromColor(System.Drawing.Color.Green);
lY.Color= Color.FromColor(System.Drawing.Color.Orange); Line line = new Line(pt1, pt2); line.Color = Color.FromColor(System.Drawing.Color.Red); line.ToSpace();
lX.ToSpace();
lY.ToSpace(); // Create rotation matrix Matrix3d rotMat = Matrix3d.Rotation( dbText.Rotation, dbText.Normal, pt1); // The returned points from acedTextBox need // to be transformed as follow pt1 = pt1.TransformBy(rotMat).Add(dbText.Position.GetAsVector()); pt2 = pt2.TransformBy(rotMat).Add(dbText.Position.GetAsVector()); Line linetrans = new Line(pt1, pt2); linetrans.Color = Color.FromColor(System.Drawing.Color.Yellow) ; linetrans.ToSpace(); Vector3d rotDir = new Vector3d( -Math.Sin(dbText.Rotation), Math.Cos(dbText.Rotation), ); //求垂直于rotDir和normal的法向量
Vector3d linDir = rotDir.CrossProduct(dbText.Normal); double actualWidth = Math.Abs((pt2.GetAsVector() - pt1.GetAsVector()) .DotProduct(linDir)); pt3 = pt1.Add(linDir * actualWidth); pt4 = pt2.Subtract(linDir * actualWidth); Line linetrans2 = new Line(pt3, pt4); linetrans2.Color = Color.FromColor(System.Drawing.Color.Blue); linetrans2.ToSpace();
} #endregion
}

AutoCad 二次开发 文字镜像的更多相关文章

  1. AutoCAD二次开发——AutoCAD.NET API开发环境搭建

    AutoCAD二次开发工具:1986年AutoLisp,1989年ADS,1990年DCL,1993年ADS-RX,1995年ObjectARX,1996年Active X Automation(CO ...

  2. 1,下载和部署开发环境--AutoCAD二次开发

    环境需求为: AutoCAD 2020版 ObjectARX SDK 下载地址:https://www.autodesk.com/developer-network/platform-technolo ...

  3. AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层

    AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层 AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层我理解的图层的作用大概是把 ...

  4. AutoCad 二次开发 jig操作之标注跟随线移动

    AutoCad 二次开发 jig操作之标注跟随线移动 在autocad当中,我认为的jig操作的意思就是即时绘图的意思,它能够实时的显示出当前的操作,以便我们直观的感受到当前的绘图操作是什么样子会有什 ...

  5. AutoCAD二次开发-使用ObjectARX向导创建应用程序(HelloWorld例子)

    AutoCAD2007+vs2005 首先自己去网上搜索下载AutoCAD2007的ARX开发包. 解压后如下 打开后如下 classmap文件夹为C++类和.net类的框架图,是一个DWG文件. d ...

  6. 我的AutoCAD二次开发之路 (一)

    原帖地址 http://379910987.blog.163.com/blog/static/33523797201011184552167/ 今天在改代码的时候,遇到了AddVertexAt方法的用 ...

  7. Autocad中使用命令来调用python对Autocad二次开发打包后的exe程序

    在Autocad中直接调用Python二次开发程序是有必要的,下面介绍一种方法来实现这个功能: 其基本思路是:先将二次开发的程序打包为可执行程序exe,然后编写lsp文件,该文件写入调用exe程序的语 ...

  8. 承接 AutoCAD 二次开发 项目

    本人有多年的CAD开发经验,独立完成多个CAD二次开发项目.熟悉.net及Asp.net开发技术,和Lisp开发技术. 现在成立了工作室,独立承接CAD二次开发项目.结项后提供源码及开发文档,有需要的 ...

  9. AutoCad 二次开发 .net 之创建Table

    我使用了COM对象来在cad2018中创建table表格,需要的ObjectArx开发包可以在官网上下载,并且需要使用.netframework4.6的库才行. 项目里除了引用常规的Cad开发dll, ...

随机推荐

  1. 实践开发:vue框架重点知识分析

    一个VUE项目的主树: assets文件夹是放静态资源: components是放组件: router是定义路由相关的配置; view视图: app.vue是一个应用主组件: main.js是入口文件 ...

  2. Vulnhub靶场渗透练习(五) Lazysysadmin

    第一步扫描ip    nmap 192.168.18.*  获取ip 192.168.18.147 扫描端口 root@kali:~# masscan - --rate= Starting massc ...

  3. C# 闭包对像

    主要内容: 1.描述出现的现像 2.分析其出现的原因 3.提示 一.看如下一段代码及结果 class Program { static void Main(string[] args) { List& ...

  4. JUC - ReentrantLock 的基本用法 以及 lock()、tryLock()、lockInterruptibly()的区别

    ReentrantLock 与 synchronized对比 最近有在阅读Java并发编程实战这本书,又看到了ReentrantLock和synchronized的对比,发现自己以前对于Renntra ...

  5. Fiddler抓包工具的基本操作

    Fiddler ——位于客户端和服务器端的HTTP代理 代理:客户端所有请求都先经过fiddler,然后转发到相应服务器 服务器端所有相应都先经过fiddler,然后发送到客户端 1. 常用的HTTP ...

  6. css四种基本选择器

    css选择器是什么? 要使用css对HTML页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到CSS选择器. HTML页面中的元素就是通过CSS选择器进行控制的. CSS选择器:就是指定CS ...

  7. Dubbo 优雅停机演进之路

    一.前言 在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理.接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如 ...

  8. 【MySQL】MySQL服务启动失解决方法

    写在前面的话:前段时间,为了更加流畅愉快的玩PUBG,我在任务管理器中,关闭了mysqld服务.后来我在使用MySQL数据库服务的时候,发现去到MySQL安装目录下双击运行mysqld.exe(数据库 ...

  9. Java 生成在线二维码 以Base64返回前端、或者写入到本地磁盘

    思路 现阶段遇到这样一个问题,在原有的产品上加入线下优惠券模式,用户领取优惠券以后,获取到一个唯一的ID作为领取凭证,但是在线下用扫码枪进行扫码的时候,总不能让人手动输入吧 于是乎就想出了一个办法,后 ...

  10. js实现的几种继承方式

    他山之石,可以攻玉,本人一直以谦虚的态度学他人之所长,补自己之所短,望各位老师指正! 拜谢 js几种继承方式,学习中的总结: 所谓的继承是为了继承共有的属性,减少不必要代码的书写 第一种:借用构造函数 ...