Проверка типа объекта DBObject

Автор Тема: Проверка типа объекта DBObject  (Прочитано 14163 раз)

0 Пользователей и 6 Гостей просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Есть объект типа DBObject
взятый, к примеру, из коллекции:

Dim dbObjColl As CAD_DBS.DBObjectCollection = transaction.GetAllObjects

1. Как проверить что он является графическим примитивом
2. Проверить что этот примитив к примеру отрезок (Line)

Для класса Entity проверку сделать не проблема
делаю так:
Код - vb.net [Выбрать]
  1. If typeOf Entity is Autodesk.AutoCAD.DatabaseServices.Line Then
  2. ...
  3. End If
  4.  
« Последнее редактирование: 18-03-2016, 08:53:08 от Алексей (IdeaSoft) »

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Проверка типа объекта DBObject
« Ответ #1 : 17-03-2016, 22:30:50 »
Например, можно его открыть как Line, и если открытый объект не будет равен null, то это линия.
Причем, это как ни странно, работает быстрее всяких проверок, типа rxclass.
Ну, т.е. что-то типа var line = dbo as Line

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Проверка типа объекта DBObject
« Ответ #2 : 17-03-2016, 22:33:11 »
Хорошо, попробую так сделать. Посмотрю что будет.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Проверка типа объекта DBObject
« Ответ #3 : 17-03-2016, 22:40:34 »
открыть как Line
Открыть - это означает вызвать метод transaction.GetObject(...)?
Потому как просто приравнять не получается - выдается исключение.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Проверка типа объекта DBObject
« Ответ #4 : 17-03-2016, 22:49:06 »
var line = dbo as Line
Нет так не получается, т.к. не возможно преобразовать объект BlockTableRecord в Line

Отмечено как Решение Алексей (IdeaSoft) 18-03-2016, 08:35:28

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 475
  • Карма: 63
Re: Проверка типа объекта DBObject
« Ответ #5 : 17-03-2016, 23:07:59 »
Код - Visual Basic [Выбрать]
  1.          
  2.             Using tr As Transaction = acDoc.Database.TransactionManager.StartTransaction
  3.                 Try
  4.                     For Each objId As ObjectId In objIdArray
  5.                         dbObj = tr.GetObject(objId, OpenMode.ForRead)
  6.                         'Сортируем полученные объекты
  7.                        Select Case True
  8.                             Case TypeOf dbObj Is Line
  9.                                 wList.Add(dbObj)
  10.                             Case TypeOf dbObj Is Polyline
  11.                                 wList.AddRange(MyTable.PolyToLine(dbObj))
  12.                             Case TypeOf dbObj Is DBText
  13.                                 wTList.Add(dbObj)
  14.                             Case TypeOf dbObj Is MText
  15.                                 wMTList.Add(dbObj)
  16.                         End Select
  17.                     Next
  18.                     tr.Commit()
  19.                 Catch ex As Exception
  20.                     ed.WriteMessage(ex.ToString())
  21.                     tr.Abort()
  22.                 End Try
  23.             End Using
https://habrahabr.ru/post/278765/

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Проверка типа объекта DBObject
« Ответ #6 : 18-03-2016, 08:35:24 »
Да именно и через GetObject у меня и получилось.
Только вот в коде выше (в сообщ. от участника форума trir) не понятно возникновение переменной objIdArray?
Не указано из какой именно таблицы базы данных взят набор objIdArray.
Вот мой фрагмент кода
Код - vb.net [Выбрать]
  1. Imports CAD_DBS = Autodesk.AutoCAD.DatabaseServices
  2. ' ...
  3.             Using tr As CAD_DBS.Transaction = db.TransactionManager.StartTransaction
  4.                 Dim bt As CAD_DBS.BlockTable = tr.GetObject(db.BlockTableId, CAD_DBS.OpenMode.ForRead)
  5.                 Dim btr As CAD_DBS.BlockTableRecord = tr.GetObject(bt.Item(CAD_DBS.BlockTableRecord.ModelSpace), CAD_DBS.OpenMode.ForRead)
  6.                 For Each id As CAD_DBS.ObjectId In btr
  7.                     Dim dbObj As CAD_DBS.DBObject = tr.GetObject(id, CAD_DBS.OpenMode.ForRead)
  8.                     If dbObj Is Nothing Then
  9.                         If TypeOf dbObj Is CAD_DBS.Line Then
  10.                             '...
  11.                         End If
  12.                     End If
  13.                 Next
  14.                 tr.Commit()
  15.             End Using
  16.  

И тут у меня другой вопрос. Функция
tr.GetObject(id, CAD_DBS.OpenMode.ForRead)
всегда отработает без сбоев?
Или все же есть вероятность, что в базе
данных может быть ошибка и объект не будет возвращен.
Решил все же вставить проверку на DbObj. 

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 475
  • Карма: 63
Re: Проверка типа объекта DBObject
« Ответ #7 : 18-03-2016, 09:12:08 »
Цитировать
Только вот в коде выше (в сообщ. от участника форума trir) не понятно возникновение переменной objIdArray?
Не указано из какой именно таблицы базы данных взят набор objIdArray.
однако я специально дал ссылку на habr, где можно было найти ссылку на github

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Проверка типа объекта DBObject
« Ответ #8 : 18-03-2016, 09:15:30 »
Теперь понятно откуда берется объект objIdArray

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 475
  • Карма: 63
Re: Проверка типа объекта DBObject
« Ответ #9 : 18-03-2016, 09:16:52 »
174 Public Shared Function CrTbl(acDoc As MyAcAs.Document) As MyTable

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Проверка типа объекта DBObject
« Ответ #10 : 18-03-2016, 11:52:19 »
Как проверить что он является графическим примитивом
Код - C# [Выбрать]
  1. DBObject dbObj ....
  2. if (dbObj is Entity)
проверка гарантирует, что объект - графический примитив.

2. Проверить что этот примитив к примеру отрезок (Line)
Проверка конкретных типов примитивов уже не столь однозначна.
Код - C# [Выбрать]
  1. if (dbObj is DBText)
гарантирует, что объект относится к типу DBText, но не гарантирует что сам объект DBText.

Это связанно с иерархией наследования:
специально приведу пример-исключение чтобы было понятно, что исключений мало, но они есть!
AttributeReference : DBText : Entity : DBObject

Для объекта AttributeReference, все проверки вернут true:
Код - C# [Выбрать]
  1. if (dbObj is AttributeReference )
  2. if (dbObj is DBText)
  3. if (dbObj is Entity)
  4. if (dbObj is DBObject)
т.е. выискивая DBText ты зацепишь AttributeReference

В связи с этим для 95% уверенности получаю имя класса примитива и сравниваю.
Код - C# [Выбрать]
  1. Entity entity ....
  2. Type type = entity.GetType();
  3. string typeName = type.Name;
  4. if (typeName == "DBText" )
...такая проверка гарантирует, что тип этого объекта точно не AttributeReference.

..однако не гарантирует, что этот объект относится именно к классу
Autodesk.AutoCAD.DatabaseServices.DBText
а не вашему классу с аналогичным именем MyNewObjects.Entity.DBText

..и если хочешь убедиться на 100%
Код - C# [Выбрать]
  1. Entity entity ....
  2. Type type = entity.GetType();
  3. string fullTypeName = type.ToString();
  4. if (fullTypeName == "Autodesk.AutoCAD.DatabaseServices.DBText" )
...надежнее, но читается не очень

проверки со стрингами(string) не оптимальны по производительности.
В конретном случае если хочешь получить именно DBText, то:
Код - C# [Выбрать]
  1. if ((dbText is DBText) && !(dbText is AttributeReference))
такая проверка должна быть быстрее, но менее универсальна и менее надежна.

Так что выбирай сам, что и когда использовать ;-)

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Проверка типа объекта DBObject
« Ответ #11 : 18-03-2016, 11:56:59 »
а как удалить лишнее сообщение?)
« Последнее редактирование: 18-03-2016, 15:01:13 от Привалов Дмитрий »

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Проверка типа объекта DBObject
« Ответ #12 : 18-03-2016, 16:06:25 »
Я обычно использую RXClass для проверки типа объекта:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace AcadTests
  7. {
  8.     public class DBObjectTest
  9.     {
  10.         [CommandMethod("DBObjectTest")]
  11.         public void Run()
  12.         {
  13.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.             Database db = adoc.Database;
  15.             Editor ed = adoc.Editor;
  16.  
  17.             PromptEntityResult entRes = ed.GetEntity("\nВыберите объект: ");
  18.             if (entRes.Status != PromptStatus.OK) return;
  19.  
  20.             bool isText;
  21.  
  22.             using (Transaction tr = db.TransactionManager.StartTransaction())
  23.             {
  24.                 DBObject obj = tr.GetObject(entRes.ObjectId, OpenMode.ForRead);
  25.  
  26.                 RXClass dbTextRx = RXClass.GetClass(typeof(DBText));
  27.  
  28.                 isText = obj.GetRXClass().Equals(dbTextRx);
  29.  
  30.                 tr.Commit();
  31.             }
  32.  
  33.             ed.WriteMessage("\nЭто {0}.", isText ? "текст" : "не текст");
  34.         }
  35.     }
  36. }

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Проверка типа объекта DBObject
« Ответ #13 : 18-03-2016, 17:03:26 »
 
Я обычно использую RXClass для проверки типа объекта:
Тоже хороший вариант. И возможно более правильный
Попозже проверю для интереса что быстрее.


...проверил 10 замеров каждого теста. Искал объекты DbText в чертеже 30 мБт
время перебора всех объектов, без проверок типа взял за 100%
100% - перебор всех блоков/объектов в них.
100,24%  - if (!(obj is AttributeReference) && (obj is DBText)) AttrCount++;
108,95% - if (obj.GetType().Name == "DBText") AttrCount++;
125,70% - if (obj.GetRXClass() == dbTextRxClass) AttrCount++;

1й почти не сказывается на производительности, но вернул не правильное значение, 20178 вместо 20064 копаться не буду, что за объект наследованный от DbText в чертеже, для примерочной оценки это незначительно.
2й +9% терпимо и результат поиска совпадает с 3м вариантом
3й самый медленный оказался, +25% скорее всего obj.GetRXClass() работает медленно!

доп. инфа автокад 2008..возможно в новых версиях GetRXClass() быстрее ;-)
« Последнее редактирование: 21-03-2016, 12:52:50 от Привалов Дмитрий »

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Проверка типа объекта DBObject
« Ответ #14 : 21-03-2016, 14:48:00 »
125,70% - if (obj.GetRXClass() == dbTextRxClass) AttrCount++;
Вот не верю я в это, ИМХО Вы что то не так сделали, вся прелесть RXClass в том, что для его получения не нужно получать и открывать объект, достаточно ObjectId, соответственно скорость должна быть намного выше.
Код - C# [Выбрать]
  1.     Db.ObjectId objectId = Db.ObjectId.Null;
  2.     // ...
  3.     Rt.RXClass dimenClass = Rt.RXObject.GetClass(typeof(Db.Dimension));
  4.     if(objectId.ObjectClass.IsDerivedFrom(dimenClass)) {
  5.       // ...
  6.     }
Как видно и транзакция то не нужна...

Вы не могли бы код опубликовать?