Как получить размеры динамического блока с помощью чистого NET? (без COM)

Автор Тема: Как получить размеры динамического блока с помощью чистого NET? (без COM)  (Прочитано 38009 раз)

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

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

Оффлайн WindcastleАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 58
  • Карма: 0
Задача: на чистом NET API AutoCAD написать код для определения размеров динамического блока (файл прилагается).

1. Имеется чертеж с динамическим блоком внутри.
2. Требуется определить его габаритные размеры с помощью AutoCAD NET и вывести с помощью MessageBox на экран.

Файл прикрепляю!

1. Раньше бы я решил этот вопрос с помощью метода GetBoundingBox, предварительно создав взорванную копию данного блока и пропарсил бы все объекты, входящие в копию! Но с учетом того, что от меня требуют именно NET код, то прошу помочь разобраться с чего начать:
     - Какие библиотеки подключить?
     - Что делать дальше?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
В NET можно (и проще всего, и правильнее, на мой взгляд) сделать то же самое. Берем блок, взрываем, определяем габариты осколков и по ним определяем общий габарит. По поводу остального -  материалов по этим вопросам в интернете много.

Оффлайн Пашин Евгений

  • ADN PRO
  • *
  • Сообщений: 662
  • Карма: 12
  • Skype: pashin.evgeniy
Я так уже делал через COM объект с помощью GetBoundingBox, предварительно взрывая блоки Object.Explode и перебирая их!

Но мне сказали, что это не правильно!

А нужно правильно!

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Мне лично почти все равно кто там и что сказал  8)
Я к такому выводу пришел самостоятельно, путем довольно долгих поисков и натыканий на различного рода грабли. Если у кого-то есть другое обоснованное мнение на этот счет - с удовольствием выслушаю.

Оффлайн German

  • ADN Club
  • **
  • Сообщений: 84
  • Карма: 13
Это динамический блок. В нем есть параметры, которые управляют геометрией блока. Их можно считать. Код есть и на этом форуме.
Только нужно знать, что это за параметры. Для этого нужно "поковыряться" в блоке.

Увидел, что образец прикреплен. Однозначно, взрывать!
Off-Topic: показать
А еще лучше сделать свой динамический блок, отвечающий за рамку печати.

Оффлайн Пашин Евгений

  • ADN PRO
  • *
  • Сообщений: 662
  • Карма: 12
  • Skype: pashin.evgeniy
Дмитрий Загорулькин, спасибо за ответ! Мне Ваше решение тоже кажется простым и изящным, но мне скоро по рукам будут бить... мне нужна помощь в освоении именно NET технологии.

Оффлайн Doublefish

  • ADN Club
  • ****
  • Сообщений: 288
  • Карма: 10
  • AutoCAD Civil 3D
Либо иметь в блоке в параметрах операций два параметра - высоту и ширину и соответственно считывать свойства этих параметров из блока (т.е. не через видимость переключение, а через параметры).
Я правда не совсем понял зачем в блоке под каждую видимость перечертивать объекты вместо того чтобы использовать параметры где и указать размеры.

Оффлайн Пашин Евгений

  • ADN PRO
  • *
  • Сообщений: 662
  • Карма: 12
  • Skype: pashin.evgeniy
Я не задаюсь таким вопросом - это стандарт предприятия.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Но мне сказали, что это не правильно!
Это намёк на меня? Тогда ты не понял о чём я писал. В AutoCAD его AutoCAD .NET API значительно мощнее и гибче, чем его же COM/ActiveX. Поэтому раз ты уже ушел от VBA в VB.NET (хотя я бы рекомендовал C#), то есть возможность (не обязанность) использовать более мощные средства.
Пример, разницы между AutoCAD .NET API и COM/ActiveX. В COM метод Explode для примитива (в частности вставки блока) создаёт кучу новых примитивов и сразу добавляет их в чертеж. Поэтому после их обработки тебе придётся их удалить, а это кроме того что займёт лишнее время, так еще и приведёт к утечке памяти. В AutoCAD .NET API метод Explode не добавляет получающиеся примитивы в чертеж (они только в оперативной памяти) и их не нужно удалять из чертежа - только использовать метод Dispose() для очистки памяти. Это один из простейших примеров.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Если у кого-то есть другое обоснованное мнение на этот счет - с удовольствием выслушаю.
Если у вставки блока различные масштабные коэффициенты по осям X, Y, Z - метод Explode в большинстве случаев не сработает.
А ведь здесь задача значительно проще. Необходимо отобрать только видимые примитивы, получить их Extents, получить крайние точки и выполнить преобразование по матрице BlockTransform. Вроде бы ничего не забыл.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Пашин Евгений

  • ADN PRO
  • *
  • Сообщений: 662
  • Карма: 12
  • Skype: pashin.evgeniy
Это намёк на меня?

А Вы тут ни при чем! Хотя Ваши слова и слова моего начальника похожи.

В AutoCAD его AutoCAD .NET API значительно мощнее и гибче, чем его же COM/ActiveX

Да-к покажите как это сделать.

Если у вставки блока различные масштабные коэффициенты по осям X, Y, Z

Это ж кому придет в голову еще и коэффициенты  менять?



Разница VBA от NET AutoCAD! Простыми словами сможете объяснить? Или опять меня куда-нибудь пошлете, чего-нибудь почитать ))))

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Если у вставки блока различные масштабные коэффициенты по осям X, Y, Z - метод Explode в большинстве случаев не сработает.
Надо перепроверить, но вроде бы, если память не изменяет, работает хорошо и при масштабах разных и при повороте блока и пр.
Необходимо отобрать только видимые примитивы, получить их Extents, получить крайние точки и выполнить преобразование по матрице BlockTransform.
И получите не те границы, которые нужны, если блок повернут. Это мы уже проходили.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Да-к покажите как это сделать.
Смотри. Только с C# на VB.NET перепишешь сам. Для этого можешь воспользоваться одним из конвертеров: http://www.developerfusion.com/tools/convert/csharp-to-vb/
Надо перепроверить, но вроде бы, если память не изменяет, работает хорошо и при масштабах разных и при повороте блока и пр.
Проверь. Очень удивишься. Особенно если в блоке присутствуют дуги и/или полилинии с дугами.

Пока простейший код без обработки ошибок. Кстати вроде и с повернутыми блоками работает:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. #pragma warning disable 618
  9.  
  10. [assembly: CommandClass(typeof(Rivilis.BlockExtents))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class BlockExtents
  15.   {
  16.     [CommandMethod("BlockExt")]
  17.     public void BlockExt()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.       Editor ed = doc.Editor;
  22.       PromptEntityOptions enOpt =
  23.         new PromptEntityOptions("\nВыберите вставку блока:");
  24.       enOpt.SetRejectMessage("Это не вставка блока");
  25.       enOpt.AddAllowedClass(typeof(BlockReference), true);
  26.       PromptEntityResult enRes = ed.GetEntity(enOpt);
  27.       if (enRes.Status == PromptStatus.OK)
  28.       {
  29.         Extents3d blockExt = new Extents3d(Point3d.Origin, Point3d.Origin);
  30.         using (BlockReference bref = enRes.ObjectId.Open(OpenMode.ForRead) as BlockReference)
  31.         {
  32.           Matrix3d mat = bref.BlockTransform;
  33.           using (BlockTableRecord btr = bref.BlockTableRecord.Open(OpenMode.ForRead) as BlockTableRecord)
  34.           {
  35.             foreach (ObjectId id in btr)
  36.             {
  37.               using (DBObject obj = id.Open(OpenMode.ForRead) as DBObject)
  38.               {
  39.                 Entity en = obj as Entity;
  40.                 if (en != null && en.Visible == true)
  41.                 {
  42.                   Extents3d ext = en.GeometricExtents;
  43.                   ext.TransformBy(mat);
  44.                   if (blockExt.MinPoint == Point3d.Origin && blockExt.MaxPoint == Point3d.Origin)
  45.                     blockExt = ext;
  46.                   else
  47.                     blockExt.AddExtents(ext);
  48.                 }
  49.               }
  50.             }
  51.           }
  52.         }
  53.         string s =
  54.           "MinPoint: " + blockExt.MinPoint.ToString() + " " +
  55.           "MaxPoint: " + blockExt.MaxPoint.ToString();
  56.         ed.WriteMessage(s);
  57.       }
  58.     }
  59.   }
  60. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Решил сам воспользоваться конвертером. Практически ничего не пришлось править:

Код - vb.net [Выбрать]
  1. Imports Autodesk.AutoCAD.Runtime
  2. Imports Autodesk.AutoCAD.ApplicationServices
  3. Imports Autodesk.AutoCAD.DatabaseServices
  4. Imports Autodesk.AutoCAD.Geometry
  5. Imports Autodesk.AutoCAD.EditorInput
  6.  
  7. <Assembly: CommandClass(GetType(Rivilis.BlockExtents))>
  8.  
  9. Namespace Rivilis
  10.     Public Class BlockExtents
  11.         <CommandMethod("BlockExt")> _
  12.         Public Sub BlockExt()
  13.             Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  14.             If doc Is Nothing Then
  15.                 Return
  16.             End If
  17.             Dim ed As Editor = doc.Editor
  18.             Dim enOpt As New PromptEntityOptions(vbLf & "Выберите вставку блока:")
  19.             enOpt.SetRejectMessage("Это не вставка блока")
  20.             enOpt.AddAllowedClass(GetType(BlockReference), True)
  21.             Dim enRes As PromptEntityResult = ed.GetEntity(enOpt)
  22.             If enRes.Status = PromptStatus.OK Then
  23.                 Dim blockExt__1 As New Extents3d(Point3d.Origin, Point3d.Origin)
  24.                 Using bref As BlockReference = _
  25.                       TryCast(enRes.ObjectId.Open(OpenMode.ForRead), BlockReference)
  26.                     Dim mat As Matrix3d = bref.BlockTransform
  27.                     Using btr As BlockTableRecord = _
  28.                           TryCast(bref.BlockTableRecord.Open(OpenMode.ForRead), BlockTableRecord)
  29.                         For Each id As ObjectId In btr
  30.                             Using obj As DBObject = TryCast(id.Open(OpenMode.ForRead), DBObject)
  31.                                 Dim en As Entity = TryCast(obj, Entity)
  32.                                 If en IsNot Nothing AndAlso en.Visible = True Then
  33.                                     Dim ext As Extents3d = en.GeometricExtents
  34.                                     ext.TransformBy(mat)
  35.                                     If blockExt__1.MinPoint = Point3d.Origin _
  36.                                           AndAlso blockExt__1.MaxPoint = Point3d.Origin Then
  37.                                         blockExt__1 = ext
  38.                                     Else
  39.                                         blockExt__1.AddExtents(ext)
  40.                                     End If
  41.                                 End If
  42.                             End Using
  43.                         Next
  44.                     End Using
  45.                 End Using
  46.                 Dim s As String = "MinPoint: " & blockExt__1.MinPoint.ToString() & " " & _
  47.                     "MaxPoint: " & blockExt__1.MaxPoint.ToString()
  48.                 ed.WriteMessage(s)
  49.             End If
  50.         End Sub
  51.     End Class
  52. End Namespace
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение