Статьи > Тестирование статей

AutoCAD .NET API: Реальные габариты MText

(1/2) > >>

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;} а что бы не вспоминать внутри транзакции я или снаружи просто начал везде использовать первый вариант, может зря конечно, в программах не автокадовских обычно да, использую твой вариант с ретурном.

Навигация

[0] Главная страница сообщений

[#] Следующая страница

Перейти к полной версии