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

ADN Club => AutoCAD .NET API => Тема начата: Владимир Шу от 05-05-2024, 10:39:30

Название: Как найти координаты поля в тексте
Отправлено: Владимир Шу от 05-05-2024, 10:39:30
При проверке файлов, нормоконтролер помечает (обводит) неправильные фрагменты, к таким фрагментам относятся, в том числе, и сломанные поля.
И если найти все поля в чертеже не проблема, найти сломанные поля, так же не сложно, найти внутри каких объектов находятся поля так же не сложно, то вот как найти координаты самих полей, вот тут у меня затык.
К сожалению координаты и границы объекта внутри которого находится сломанное поле не подходят, так как это может быть MText, с портянкой на 2-3 страницы.

Собственно вопрос в заголовке темы, как найти координаты поля или как найти координаты любой буквы в тексте

P.S.
Я порылся в методах и свойствах как самого класса Field, так и его родителя DBObject, но все что там могло мне помочь, это Bounds, но естественно эти поля не заполнены.

Код - C# [Выбрать]
  1.       App.Document doc = App.Application.DocumentManager.MdiActiveDocument;
  2.       if (doc == null) { return; }
  3.  
  4.       Db.Database db = doc.Database;
  5.       Ed.Editor ed = doc.Editor;
  6.  
  7.  
  8.       var opt = new Ed.PromptEntityOptions("\nSelect an MText object containing field(s): ");
  9.       opt.SetRejectMessage("\nObject must be MText.");
  10.       opt.AddAllowedClass(typeof(Db.MText), false);
  11.  
  12.       Ed.PromptEntityResult res = ed.GetEntity(opt);
  13.  
  14.       if (res.Status != Ed.PromptStatus.OK) { return; }
  15.  
  16.  
  17.       using (Db.Transaction Tx = db.TransactionManager.StartTransaction())
  18.       {
  19.         var mtext = Tx.GetObject(res.ObjectId, Db.OpenMode.ForRead) as Db.MText;
  20.  
  21.         if (!mtext.HasFields)
  22.         {
  23.           ed.WriteMessage("\nObject does not contain fields.");
  24.           return;
  25.         }
  26.  
  27.         Db.ObjectId id = mtext.GetField();
  28.         Db.Field fieldBase = Tx.GetObject(id, Db.OpenMode.ForRead) as Db.Field;
  29.        
  30.         var fields = fieldBase.GetChildren();
  31.         foreach (var field in fields)
  32.         {
  33.           if (field.EvaluationStatus.Status != Db.FieldEvaluationStatus.Success)
  34.           {
  35.             if (field.Bounds != null)
  36.             {
  37.               //он всегда null
  38.               var pnt = field.Bounds.Value.MinPoint;
  39.             }
  40.  
  41.            
  42.             if(field.Drawable.Bounds != null)
  43.             {
  44.               // и этот всегда null
  45.             }
  46.  
  47.             ed.WriteMessage("\nЕсть проблемки!");
  48.  
  49.           }
  50.         }
  51.         Tx.Commit();
  52.       }
Название: Re: Как найти координаты поля в тексте
Отправлено: avc от 05-05-2024, 10:51:50
Серьезная задачка. Я бы попробовал создать новый MText со всем содержимым старого ДО начала кода поля и попытаться понять, где конец текста получился. И еще один MText чисто с кодом неработающего поля для расчета его размеров. Конечно куча проблем вылезет с оборвавшимся форматированием и многострочными текстами...
Название: Re: Как найти координаты поля в тексте
Отправлено: Владимир Шу от 05-05-2024, 12:56:46
я пробовал получать фрагменты MText через mtext.ExplodeFragments( new Db.MTextFragmentCallback(MTextCallback)); с сохранением во внешний список расположение фрагмента, его содержание и размер и с последующим поиском в полученных фрагментах значения поля (string value = field.GetStringValue();), но это так коряво и при наличие множества битых полей не надежно, да и положение получается не отдельного поля, а строки в MTextе

В общем что то не получается =(
Название: Re: Как найти координаты поля в тексте
Отправлено: Привалов Дмитрий от 07-05-2024, 10:31:15
В общем что то не получается =(
Можно попробовать следующее.

не знаю как через API, но при разбивке MText через (_explode)
MText разбивается на строки DBText и вместо поля в DBText вставляется его значение.
Тут важно проверить, знаешь ли ты значение значение в MText "сломанного поля" до разбивки и что при разбивке такого поля происходит, сохраняется ли значение, не происходит ли смещения и т.д.

Если после разбивки на DBText значение поля не изменилось и не сместилось, можно попробовать следующее:
DBText дробится на несколько DBText, если в MText используются теги, например подчеркивание

Экспериментировал с тегом даты:
В MText было: "\A1;{\W1;\Lмая 7, 2024}"
В DbText стало: "%%Uмая 7, 2024"

Т.е. логика такая:
1. находишь значение сломанного поля, например "мая 7, 2024",
2. оборачиваешь поле в тег подчеркивания "\A1;{\W1;\Lмая 7, 2024}". (можно попробовать тег цвета, шрифта и т.д.)
3. Разбиваешь MText
4. Ищешь последние добавленные DbText с нужным значением поля "%%Uмая 7, 2024" или "мая 7, 2024"
5. Определяешь координаты

Название: Re: Как найти координаты поля в тексте
Отправлено: Владимир Шу от 14-05-2024, 08:22:05
Получилось. Публиковать простыню кода не хочется, а внятно сформулировать алгоритм у меня не выходит...
В общем все построено вокруг:
mtextObj.ExplodeFragments(MTextFragmentCallback enumerator, object userData) - для получения строк без форматирования и с координатами начала
Db.Field.FindField(mtext.getMTextWithFieldCodes(), sInt, ref stridx, ref endIdx) - поиска индексов начала и конца поля
Autodesk.AutoCAD.Internal.Utils.GetTextExtents(mtext.TextStyleId, str, mtext.TextHeight) - вычисление смещения от начала строки и поиск размеров самого поля
(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Ficecream.me%2Fuploads%2F2a85690a35a39055f194796b5539c66a.png&hash=acd3e8bb11a9c76648f9c19068450d6b)

Но есть и косяк... mtextObj.ExplodeFragments() теряет пустые строки из-за чего может возникать некоторое смещение координат поля... но для меня это не критично, так что пусть.
Однако, если очень нужно будет, то можно попробовать для очистки текста использовать  Db.TextEditor te = Db.TextEditor.CreateTextEditor(tMtext)
и после очистки пустые строки можно будет учесть