Статьи > Тестирование статей
AutoCAD .NET API: Реальные габариты MText
alz:
В связи с тем, что стандартный метод .GeometricExtents в случае с MText возвращает собственно окно в котором этот текст расположен, а сам текст в этом окне может располагаться достаточно свободно пришлось поискать варианты определения реального положения текста, а то были проблемы с определением местоположения текста относительно других объектов, когда текст вроде как внутри какого то контура, а программно определяется что снаружи.
Для решения этой проблемы можно воспользоваться такими параметрами MText как .ActualHeight и .ActualWidth, но просто так их использовать не получится, так как текст у нас все же в пространстве а так же может быть развернут относительно каких либо осей, поэтому было решено использовать немного векторной геометрии. Для начала определяем вектора оси X и оси Y плоскости текста, потом в зависимости от положения текста относительно точки вставки определяем положение минимальной точки через вектор соответствующей оси и реальную высоту/ширину текста, и собственно используя эти же параметры возвращаем и максимальную точку.
На изображении показаны границы: голубым цветом(возвращаемые .GeometricExtents ) зеленым цветом(вычисленные)
Текст функции
--- Код - C# [Выбрать] --- /// <summary> /// возвращаем реальный габарит MText /// </summary> /// <param name="mText"></param> /// <returns></returns> private Extents3d? MtextRealExtents(MText mText) { if (mText != null) { //получаем точку вставки текста Point3d point = mText.Location; //получаем вектора оси Х и Y в плоскости текста Plane plane = new Plane(point, mText.Normal); Vector3d vx = plane.Normal.GetPerpendicularVector().GetNormal(); Vector3d vy = vx.TransformBy(Matrix3d.Rotation(Math.PI / 2, plane.Normal, point)).GetNormal(); //получаем габариты текста double h = mText.ActualHeight; double w = mText.ActualWidth; //получаем нижний левый угол текста switch (mText.Attachment) { case AttachmentPoint.TopLeft: point = point - vy*h; break; case AttachmentPoint.MiddleCenter: point = point - vy*h/2 - vx*w/2; break; case AttachmentPoint.TopCenter: point = point - vy * h - vx * w / 2; break; case AttachmentPoint.TopRight: point = point - vy * h - vx * w; break; case AttachmentPoint.MiddleLeft: point = point - vy * h / 2; break; case AttachmentPoint.MiddleRight: point = point - vy * h/2 - vx * w; break; case AttachmentPoint.BottomLeft: break; case AttachmentPoint.BottomCenter: point = point - vx * w/2; break; case AttachmentPoint.BottomRight: point = point - vx * w; break; } //возвращаем новые габариты return new Extents3d(point, point + vx*w + vy*h); } return null; }
alz:
Хмм, при более углубленных тестах оказалось что не учет поворот текста, пришлось немного переделать, теперь вроде бы все учтено. Жаль нельзя свои сообщения редактировать
--- Код - C# [Выбрать] --- /// <summary> /// возвращаем реальный габарит MText /// </summary> /// <param name="mTextId"></param> /// <returns></returns> private Extents3d? MtextRealExtents(MText mText) { if (mText != null) { Point3d point = mText.Location; Plane plane = new Plane(point, mText.Normal); Vector3d vx = plane.Normal.GetPerpendicularVector().TransformBy(Matrix3d.Rotation(mText.Rotation, plane.Normal, point)).GetNormal(); ; Vector3d vy = vx.TransformBy(Matrix3d.Rotation(Math.PI / 2, plane.Normal, point)).GetNormal(); double h = mText.ActualHeight; double w = mText.ActualWidth; //получаем нижний левый угол текста switch (mText.Attachment) { case AttachmentPoint.TopLeft: point = point - vy * h; break; case AttachmentPoint.MiddleCenter: point = point - vy * h / 2 - vx * w / 2; break; case AttachmentPoint.TopCenter: point = point - vy * h - vx * w / 2; break; case AttachmentPoint.TopRight: point = point - vy * h - vx * w; break; case AttachmentPoint.MiddleLeft: point = point - vy * h / 2; break; case AttachmentPoint.MiddleRight: point = point - vy * h / 2 - vx * w; break; case AttachmentPoint.BottomLeft: break; case AttachmentPoint.BottomCenter: point = point - vx * w / 2; break; case AttachmentPoint.BottomRight: point = point - vx * w; break; } //получаем точки 4 углов в wcs //достаточно перспективные данные, дают 4 реальных угла текста а не прямоугольник области List<Point3d> points = new List<Point3d> { point, point + vx * w + vy * h, point + vx * w, point + vy * h, }; //получаем все координаты точек List<double> x = new List<double>(); List<double> y = new List<double>(); foreach (Point3d p in points) { x.Add(p.X); y.Add(p.Y); } //возвращаем новые габариты return new Extents3d(new Point3d(x.Min(), y.Min(), 0).Project(plane, Vector3d.ZAxis), new Point3d(x.Max(), y.Max(), 0).Project(plane, Vector3d.ZAxis)); } return null; }
Александр Ривилис:
--- Цитата: alz от 15-03-2023, 15:55:48 ---Жаль нельзя свои сообщения редактировать
--- Конец цитаты ---
Это как раз хорошо. Видна "работа над ошибками". :-)
Владимир Шу:
Я не проверял код, но вот стилистику после 56 строки, что то захотелось поправить... сделать ее более читаемой что ли...
--- Код - C# [Выбрать] --- var points = new List<Gem.Point3d>(); var minX = points.Select(q => q.X).Min(); var minY = points.Select(q => q.Y).Min(); var maxX = points.Select(q => q.X).Max(); var maxY = points.Select(q => q.Y).Max(); var minPoint = new Gem.Point3d(minX, minY, 0).Project(plane, Gem.Vector3d.ZAxis); var maxPoint = new Gem.Point3d(maxX, maxY, 0).Project(plane, Gem.Vector3d.ZAxis); return new Db.Extents3d(minPoint, maxPoint);И я бы еще избавился от скобочек в if (mText != null) {} заменил бы на if (mText == null) return null;
PS/
И еще хотелось бы уточнить, а вот такой вариант точно не работает?
--- Код - C# [Выбрать] --- var ext = new Db.Extents3d(); ext.AddPoint(point.Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w + vy * h).Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w).Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w).Project(plane, Vector3d.ZAxis)); return ext;
alz:
Сделайте скидку на мой опыт в программировании в пол года на шарпе (пара часов видеоуроков по программированию в автокаде а дальше как-то сам по примерам с форумов) и пара месяцев на дельфи лет 10 назад)
var я вообще не использую, задаю предпочитаю сразу задавать нужный тип
Зачем Gem и Db? Вроде программа простейшая и мне хватило этого
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
Разница как я понял вместо использования списков с координатами они просто вытаскиваются из точек через линк но с линком я знаком крайне поверхностно и такие конструкции пока не делал
--- Код - C# [Выбрать] --- var ext = new Db.Extents3d(); ext.AddPoint(point.Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w + vy * h).Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w).Project(plane, Vector3d.ZAxis)); ext.AddPoint((point + vx * w).Project(plane, Vector3d.ZAxis)); return ext;
тут границы определятся конечно правильно, но только в плане - вид сверху, так как по оси Z граница не лежит в плоскости текста но немного переделанный вариант вполне прошел, вот так выдает все вполне корректно
--- Код - C# [Выбрать] ---var ext = new Extents3d(); ext.AddPoint(point); ext.AddPoint((point + vx * w + vy * h)); ext.AddPoint((point + vx * w)); ext.AddPoint((point + vy * h)); return = new Extents3d(ext.MinPoint.Project(plane, Vector3d.ZAxis), ext.MaxPoint.Project(plane, Vector3d.ZAxis));
по поводу - И я бы еще избавился от скобочек в if (mText != null) {} заменил бы на if (mText == null) return null;
тут у меня уже привычка использовать именно такой вариант, поскольку очень много используется транзакций, которые я все же предпочитаю коммитить, так как был у меня пример где я забывал коммитить и программу подвешивало, хотя там был цикл и видимо внутри него транзакция открывалась слишком много раз без закрытия, так что если вариант if (mText == null) return null использовать, то предпочитаю делать так if (mText == null){ tr.commit(); return null;} а что бы не вспоминать внутри транзакции я или снаружи просто начал везде использовать первый вариант, может зря конечно, в программах не автокадовских обычно да, использую твой вариант с ретурном.
Навигация
Перейти к полной версии