ADN Open CIS
Сообщество программистов Autodesk в СНГ

26/10/2013

Зеркальное отображение примитива однострочного текста (DBText)

Некоторое время назад, когда этого блога еще не было, был написан следующий .NET код для отзеркаливания однострочного текста  (DBText), чтобы решить один из запросов от члена AND. Через какое-то время снова возникла необходимость в этом коде. Вы сами сможете увидеть, что он не так прост, как могло бы показаться:

Код - C#: [Выделить]
  1. // Mirrors a DBText entity, by Philippe Leefsma 4/10/2013
  2. [CommandMethod("MirrorTextCmd")]
  3. public void MirrorTextCmd()
  4. {
  5.     Document doc = Application.DocumentManager.MdiActiveDocument;
  6.     Database db = doc.Database;
  7.     Editor ed = doc.Editor;
  8.  
  9.     // Выбор примитива
  10.     PromptEntityOptions peo = new PromptEntityOptions(
  11.         "\nВыберите примитив текста:");
  12.  
  13.     peo.SetRejectMessage("\nЭто не текст...");
  14.     peo.AddAllowedClass(typeof(DBText), true);
  15.  
  16.     PromptEntityResult perText = ed.GetEntity(peo);
  17.  
  18.     if (perText.Status != PromptStatus.OK)
  19.         return;
  20.  
  21.     peo = new PromptEntityOptions("\nВыберите отрезок для отзеркаливания:");
  22.     peo.SetRejectMessage("\nЭто должен быть отрезок...");
  23.     peo.AddAllowedClass(typeof(Line), true);
  24.  
  25.     PromptEntityResult perLine = ed.GetEntity(peo);
  26.  
  27.     if (perLine.Status != PromptStatus.OK)
  28.         return;
  29.  
  30.     using (Transaction tr = db.TransactionManager.StartTransaction())
  31.     {
  32.         Line line = tr.GetObject(perLine.ObjectId, OpenMode.ForRead)
  33.             as Line;
  34.  
  35.         Line3d mirrorLine = new Line3d(
  36.             line.StartPoint,
  37.             line.EndPoint);
  38.  
  39.         MirrorText(perText.ObjectId, mirrorLine);
  40.  
  41.         tr.Commit();
  42.     }
  43. }
  44.  
  45. void MirrorText(ObjectId TextId, Line3d mirrorLine)
  46. {
  47.     Database db = TextId.Database;
  48.  
  49.     using (Transaction tr = db.TransactionManager.StartTransaction())
  50.     {
  51.         BlockTableRecord btr = tr.GetObject(
  52.             db.CurrentSpaceId,
  53.             OpenMode.ForWrite) as BlockTableRecord;
  54.  
  55.         // Получаем примитив текста
  56.         DBText dbText = tr.GetObject(TextId, OpenMode.ForRead)
  57.             as DBText;
  58.  
  59.         // Клонируем исходный примитив
  60.         DBText mirroredTxt = dbText.Clone() as DBText;
  61.  
  62.         // Создаём матрицу отзеркаливания
  63.         Matrix3d mirrorMatrix = Matrix3d.Mirroring(mirrorLine);
  64.  
  65.         // Выполняем геометрическое отзеркаливание
  66.         mirroredTxt.TransformBy(mirrorMatrix);
  67.  
  68.         // Получаем ограничивающий прямоугольник для текста
  69.         Point3d pt1, pt2, pt3, pt4;
  70.         GetTextBoxCorners(
  71.             dbText,
  72.             out pt1,
  73.             out pt2,
  74.             out pt3,
  75.             out pt4);
  76.  
  77.         // Получаем перпендикуляр к исходному тексту
  78.         Vector3d rotDir =
  79.             pt4.Subtract(pt1.GetAsVector()).GetAsVector();
  80.  
  81.         // Получаем направление исходного текста
  82.         Vector3d linDir =
  83.             pt3.Subtract(pt1.GetAsVector()).GetAsVector();
  84.  
  85.         // Вычисляем отзеркаленные направления
  86.         Vector3d mirRotDir = rotDir.TransformBy(mirrorMatrix);
  87.         Vector3d mirLinDir = linDir.TransformBy(mirrorMatrix);
  88.  
  89.         // Проверяем нужно ли отражать относительно X или Y
  90.         if (Math.Abs(mirrorLine.Direction.Y) >
  91.             Math.Abs(mirrorLine.Direction.X))
  92.         {
  93.             // Обрабатываем ситуацию, когда текст отзеркален дважды
  94.             // вместо того чтобы делать "oMirroredTxt.IsMirroredInX = true"
  95.             mirroredTxt.IsMirroredInX = !mirroredTxt.IsMirroredInX;
  96.             mirroredTxt.Position = mirroredTxt.Position + mirLinDir;
  97.         }
  98.         else
  99.         {
  100.             mirroredTxt.IsMirroredInY = !mirroredTxt.IsMirroredInY;
  101.             mirroredTxt.Position = mirroredTxt.Position + mirRotDir;
  102.         }
  103.  
  104.         // Добавляем отзеркаленый текст в базу чертежа
  105.         btr.AppendEntity(mirroredTxt);
  106.         tr.AddNewlyCreatedDBObject(mirroredTxt, true);
  107.  
  108.         tr.Commit();
  109.     }
  110. }
  111.  
  112. // Нам понадобится набор функций с использованием P/Invoked
  113. // чтобы получить ограничивающий прямоугольник для DBtext
  114. // т.к. функция "acedTextBox" не объявлена в .Net
  115.  
  116. public struct ads_name
  117. {
  118.     public IntPtr a;
  119.     public IntPtr b;
  120. };
  121.  
  122. // Экспортированные функции справедливы только в R19
  123. // Для остальных версий сделайте самостоятельно
  124. [DllImport("acdb19.dll",
  125.     CallingConvention = CallingConvention.Cdecl,
  126.     EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")]
  127. public static extern int acdbGetAdsName32(
  128.     ref ads_name name,
  129.     ObjectId objId);
  130.  
  131. [DllImport("acdb19.dll",
  132.     CallingConvention = CallingConvention.Cdecl,
  133.     EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")]
  134. public static extern int acdbGetAdsName64(
  135.     ref ads_name name,
  136.     ObjectId objId);
  137.  
  138. public static int acdbGetAdsName(ref ads_name name, ObjectId objId)
  139. {
  140.     if (Marshal.SizeOf(IntPtr.Zero) > 4)
  141.         return acdbGetAdsName64(ref name, objId);
  142.  
  143.     return acdbGetAdsName32(ref name, objId);
  144. }
  145.  
  146. [DllImport("accore.dll",
  147.     CharSet = CharSet.Unicode,
  148.     CallingConvention = CallingConvention.Cdecl,
  149.     EntryPoint = "acdbEntGet")]
  150. public static extern System.IntPtr acdbEntGet(
  151.     ref ads_name ename);
  152.  
  153. [DllImport("accore.dll",
  154.     CharSet = CharSet.Unicode,
  155.     CallingConvention = CallingConvention.Cdecl,
  156.     EntryPoint = "acedTextBox")]
  157. public static extern System.IntPtr acedTextBox(
  158.     IntPtr rb,
  159.     double[] point1,
  160.     double[] point2);
  161.  
  162. void GetTextBoxCorners(
  163.     DBText dbText,
  164.     out Point3d pt1,
  165.     out Point3d pt2,
  166.     out Point3d pt3,
  167.     out Point3d pt4)
  168. {
  169.     ads_name name = new ads_name();
  170.  
  171.     int result = acdbGetAdsName(
  172.         ref name,
  173.         dbText.ObjectId);
  174.  
  175.     ResultBuffer rb = new ResultBuffer();
  176.  
  177.     Interop.AttachUnmanagedObject(
  178.         rb,
  179.         acdbEntGet(ref name), true);
  180.  
  181.     double[] point1 = new double[3];
  182.     double[] point2 = new double[3];
  183.  
  184.     // Вызываем импортированную arx-функцию
  185.     acedTextBox(rb.UnmanagedObject, point1, point2);
  186.  
  187.     pt1 = new Point3d(point1);
  188.     pt2 = new Point3d(point2);
  189.  
  190.     // Создаём матрицу поворота
  191.     Matrix3d rotMat = Matrix3d.Rotation(
  192.         dbText.Rotation,
  193.         dbText.Normal,
  194.         pt1);
  195.  
  196.     // Точки, которые вернула функция acedTextBox, нужно
  197.     // преобразовать следующим образом
  198.     pt1 = pt1.TransformBy(rotMat).Add(dbText.Position.GetAsVector());
  199.     pt2 = pt2.TransformBy(rotMat).Add(dbText.Position.GetAsVector());
  200.  
  201.     Vector3d rotDir = new Vector3d(
  202.         -Math.Sin(dbText.Rotation),
  203.         Math.Cos(dbText.Rotation), 0);
  204.  
  205.     Vector3d linDir = rotDir.CrossProduct(dbText.Normal);
  206.  
  207.     double actualWidth =
  208.         Math.Abs((pt2.GetAsVector() - pt1.GetAsVector())
  209.             .DotProduct(linDir));
  210.  
  211.     pt3 = pt1.Add(linDir * actualWidth);
  212.     pt4 = pt2.Subtract(linDir * actualWidth);
  213. }

Ну а вот и скриншот результатов работы этого кода!

 

Источник: http://adndevblog.typepad.com/autocad/2013/10/mirroring-a-dbtext-entity.html

 

Обсуждение: http://adn-cis.org/forum/index.php?topic=288

Опубликовано 26.10.2013