参考:
在 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)> 4)
- 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[3];
- double[] point2 = new double[3];
- // Call imported arx function
- acedTextBox(rb.UnmanagedObject, point1, point2);
- pt1 = new Point3d(point1);
- pt2 = new Point3d(point2);
- var ptX = pt1 + Vector3d.XAxis * 40;
- var ptY = pt2 + Vector3d.YAxis * 50;
- 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), 0);
- // 求垂直于 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
- }
来源: https://www.cnblogs.com/HelloQLQ/p/11921618.html