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. OpenvSwitch系列之ovs-vsctl命令使用

    Open vSwitch系列之一 Open vSwitch诞生 Open vSwitch系列之二 安装指定版本ovs Open vSwitch系列之三 ovs-vsctl 命令使用 OpenvSwit ...

  2. C#数据转换

    C 货币 2.5.ToString("C") ¥2.50 D 十进制数 25.ToString("D5") 00025 E 科学型 25000.ToString ...

  3. Leetcode(6)Z字形变换

    Leetcode(6)Z字形变换 [题目表述]: 将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列. 比如输入字符串为 "LEETCODEISHIRING" ...

  4. Activity 的 36 大难点,你会几个?「建议收藏」

    前言 学 Android 有一段时间了,一直都只顾着学新的东西,最近发现很多平常用的少的东西竟让都忘了,趁着这两天,打算把有关 Activity 的内容以问题的形式梳理出来,也供大家查缺补漏. 本文中 ...

  5. 文本查重算法SimHash

    1.介绍 爬虫采集了大量的文本数据,如何进行去重?可以使用文本计算MD5,然后与已经抓取下来的MD5集合进行比较,但这种做法有个问题,文本稍有不同MD5值都会大相径庭, 无法处理文本相似问题.另一种方 ...

  6. [AI开发]零数学公式告诉你什么是(卷积)神经网络

    大部分介绍神经网络的文章中概念性的东西太多,而且夹杂着很多数学公式,读起来让人头疼,尤其没什么基础的人完全get不到作者想要表达的思想.本篇文章尝试零公式(但有少量数学知识)说清楚什么是神经网络,并且 ...

  7. SpringBoot是如何启动的?

    本文是通过查看SpringBoot源码整理出来的SpringBoot大致启动流程,整体大方向是以简单为出发点,不说太多复杂的东西,内部实现细节本文不深扣因为每个人的思路.理解都不一样,我个人看的理解跟 ...

  8. Linux 命令行获取天气

    目标: 使用 Linux 命令行显示天气预报. 发行版: 所有 Linux 发行版. 要求: 能连上因特网的 Linux 难度: 容易 约定: # - 需要使用 root 权限来执行指定命令,可以直接 ...

  9. 《Effective Java》 读书笔记(五)使用依赖注入取代原本的资源依赖

    相信接触过Spring的同学,对于依赖注入并不陌生. 刚开始在听说这个名字的时候,一直不明白到底什么叫依赖注入,后来才发现,依赖注入一直都存在我们日常代码中,只是我们没有刻意的把它提出来,然后再取这样 ...

  10. AXI4-Stream协议总结与分析

    一.协议介绍 1.AXI4_Stream:适用于高速数据流,去掉了地址项,允许无限制的数据突发传输.除了总线时钟和总线复位,其他的接口信号都是以字母T开头. 2.信号接口描述: (1).ACLK--- ...