Отображение характеристик регионов (Region)

21 апреля 2011

    Сегодня ко мне (уже не в первый раз) обратилось несколько пользователей с проблемой, выражающейся в том, что команда _massprop для некоторых регионов в AutoCAD 2009 SP3 по непонятным причинам показывают не все характеристики (например не показывают момент инерции...). В качестве демонстрации проблемы берём этот чертёж (два проблемных объекта обведены красным кружком, дабы их можно было визуально быстро найти).  Вот эти объекты:



    Если вызвать команду
_massprop на маленьком блоке (том, что слева), вывод в командную строку будет таким:


    Как видим - в отчёте присутствуют далеко не все свойства, которые мы ожидали увидеть... Я написал на .net альтернативную команду, которая должна была бы выводить ту же самую информацию, которая выводится командой
_massprop.

    Результат работы моей команды был следующим:

    Как мы - в процессе выполнения команды возникла ошибка, мол регион не находится в одной плосскости... Данный чертёж моему пользователю прислали извне, однако эти блоки он создал собственноручно и божится, что чертил в одной плосскости...

    Если маленький регион (тот, что выделен маленьким красным кружком) скопировать, и полученную копию взорвать, после чего снова создать на основе полученных линий регионы и вычесть из внешнего контура внутренний, то всё чудесным образом начинает работать как при использовании команды
_massprop, так и при использовании моей команды (ShowRegionProps).

    Но эта же самая операция не проходит для моей команды применительно ко второму региону - я по прежнему получаю ту же ошибку, которая показана на последнем скрине!

    Решение проблемы подсказал Алексей Кулик: у примитивов, входящих в состав региона могут быть разными координаты Z, несмотря на то, что в свойствах у всех показывается ноль (за счёт округления показывается одинаковое значение, но по факту оно может быть разным). Я взорвал проблемный регион, выделил все линии, поменял координаты Z начала и конца с нуля на 1 и затем обратно с 1 на ноль. Собрал регионы, вычел из внешнего внутренние и моя команда заработала!

    Хотелось бы знать, почему для второго региона после повторной сборки команда
_massprop заработала, а моя команда нет... Я предполагаю, что в моём случае отслеживается больше знаков после запятой, в отличие от _massprop, иного объяснения у меня пока нет. В процессе работы этих команд в консоли AutoCAD так же можно видеть, что мой код возвращает гораздо больше знаков после запятой - этот факт косвенно свидетельствует о достоверности моего предположения.

    Ниже привожу свой код, представляющий некую альтернативу команды
_massprop. В коде я показал два варианта получения нужных мне свойств. Тот который закомментирован - это способ получения этих свойств через .Net API - как показала практика он не работает. Пришлось использовать Interop.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using acad = Autodesk.AutoCAD.ApplicationServices.Application;
   6:  using Autodesk.AutoCAD.DatabaseServices;
   7:  using Autodesk.AutoCAD.EditorInput;
   8:  using Autodesk.AutoCAD.Runtime;
   9:  using Autodesk.AutoCAD.Interop;
  10:  using Autodesk.AutoCAD.Geometry;
  11:  using Autodesk.AutoCAD.ApplicationServices;
  12:  using Autodesk.AutoCAD.Interop.Common;
  13:  using Autodesk.AutoCAD.BoundaryRepresentation;
  14:   
  15:  namespace ShowProperties {
  16:      public class Class1 {
  17:          Document dwg;
  18:          Database db;
  19:          Editor ed;
  20:          const string ns = "bush";
  21:   
  22:          void MyInitialize() {
  23:              dwg = acad.DocumentManager.MdiActiveDocument;
  24:              db = dwg.Database;
  25:              ed = dwg.Editor;
  26:          }
  27:   
  28:          [CommandMethod(ns, "ShowRegionProps", CommandFlags.Modal)]
  29:          public void ShowProps() {
  30:              MyInitialize();
  31:              try {
  32:                  PromptSelectionOptions pso = new PromptSelectionOptions();
  33:                  pso.MessageForAdding = "Укажите те объекты REGION, информацию о которых желаете получить";
  34:                  SelectionFilter sf = new SelectionFilter(new TypedValue[] { new TypedValue((int)DxfCode.Start, "REGION") });
  35:                  PromptSelectionResult psr = ed.GetSelection(pso, sf);
  36:                  if (psr.Status == PromptStatus.OK) {
  37:                      using (Transaction tr = db.TransactionManager.StartTransaction()) {
  38:                          foreach (SelectedObject item in psr.Value) {
  39:                              Region region = (Region)tr.GetObject(item.ObjectId, OpenMode.ForRead);
  40:                              ed.WriteMessage(string.Format("\nИнформация о выбранном объекте REGION (ObjectId = {0}):", region.ObjectId));
  41:                              //Использование экземпляра класса Brep, в AutoCAD 2009 на самом деле ничего не даёт - это залепуха, которая не возвращает запрашиваемых данных. Ниже закомментирован код с использованием Brep, но его можно раскомментировать и запустить, посмотрев результаты - будут сплошные нули и неопределённые значения:
  42:                              //Brep bp = new Brep(region);
  43:                              //MassProperties mp = bp.GetMassProperties();
  44:                              //ed.WriteMessage("\nИнформация о REGION, полученная с помощью экземпляра класса Autodesk.AutoCAD.BoundaryRepresentation.Brep:");
  45:                              //ed.WriteMessage(string.Format("\nMass: {0}", mp.Mass));                                       
  46:                              //ed.WriteMessage("\nMoments Of Intertia:");
  47:                              //ed.WriteMessage(string.Format("\nX: {0}", mp.MomentsOfIntertia.X));
  48:                              //ed.WriteMessage(string.Format("\nY: {0}", mp.MomentsOfIntertia.Y));
  49:                              //ed.WriteMessage(string.Format("\nZ: {0}", mp.MomentsOfIntertia.Z));
  50:                              //ed.WriteMessage(string.Format("\nMoments Of Intertia (Length): {0}", mp.MomentsOfIntertia.Length));
  51:                              //ed.WriteMessage(string.Format("\nMoments Of Intertia (LengthSqrd): {0}", mp.MomentsOfIntertia.LengthSqrd));
  52:                              //ed.WriteMessage(string.Format("\nMoments Of Intertia (Largest Element): {0}", mp.MomentsOfIntertia.LengthSqrd));
  53:                              //ed.WriteMessage("\n" + new string('=', 30));
  54:                              //ed.WriteMessage("\nProducts Of Intertia:");
  55:                              //ed.WriteMessage(string.Format("\nX: {0}", mp.ProductsOfIntertia.X));
  56:                              //ed.WriteMessage(string.Format("\nY: {0}", mp.ProductsOfIntertia.Y));
  57:                              //ed.WriteMessage(string.Format("\nZ: {0}", mp.ProductsOfIntertia.Z));
  58:                              //ed.WriteMessage(string.Format("\nProducts Of Intertia (Length): {0}", mp.ProductsOfIntertia.Length));
  59:                              //ed.WriteMessage(string.Format("\nProducts Of Intertia (LengthSqrd): {0}", mp.ProductsOfIntertia.LengthSqrd));
  60:                              //ed.WriteMessage(string.Format("\nProducts Of Intertia (Largest Element): {0}", mp.ProductsOfIntertia.LengthSqrd));
  61:                              //ed.WriteMessage("\n" + new string('=', 30));
  62:                              //ed.WriteMessage("\nRadii Of Gyration:");
  63:                              //ed.WriteMessage(string.Format("\nX: {0}", mp.RadiiOfGyration.X));
  64:                              //ed.WriteMessage(string.Format("\nY: {0}", mp.RadiiOfGyration.Y));
  65:                              //ed.WriteMessage(string.Format("\nZ: {0}", mp.RadiiOfGyration.Z));
  66:                              //ed.WriteMessage(string.Format("\nRadii Of Gyration (Length): {0}", mp.RadiiOfGyration.Length));
  67:                              //ed.WriteMessage(string.Format("\nRadii Of Gyration (LengthSqrd): {0}", mp.RadiiOfGyration.LengthSqrd));
  68:                              //ed.WriteMessage(string.Format("\nRadii Of Gyration (Largest Element): {0}", mp.RadiiOfGyration.LengthSqrd));
  69:                              //ed.WriteMessage("\n" + new string('=', 30));
  70:                              //ed.WriteMessage("\nCentroid:");
  71:                              //ed.WriteMessage(string.Format("\nX: {0}", mp.Centroid.X));
  72:                              //ed.WriteMessage(string.Format("\nY: {0}", mp.Centroid.Y));
  73:                              //ed.WriteMessage(string.Format("\nZ: {0}", mp.Centroid.Z));
  74:                              //ed.WriteMessage("\n" + new string('=', 30));  
  75:   
  76:                              //*******************************************************************************************************
  77:                              //Через Interop информацию получить удаётся, но... Есть проблемы - см. комментарии ниже в коде...
  78:                              ed.WriteMessage("\n" + new string('=', 30));
  79:                              AcadRegion ar = (AcadRegion)region.AcadObject;
  80:                              double area = ar.Area;
  81:                              ed.WriteMessage(string.Format("\nArea: {0}", area));
  82:                              double perimeter = ar.Perimeter;
  83:                              ed.WriteMessage(string.Format("\nPerimeter: {0}", perimeter));
  84:                              ed.WriteMessage("\n" + new string('=', 30));
  85:   
  86:                              double[] momentOfInertia = (double[])ar.MomentOfInertia;//Здесь получаю ошибку (на некоторых объектах Region): System.Runtime.InteropServices.COMException не обработано пользовательским кодом: Region is not on the UCS plane
  87:                              ed.WriteMessage("\nMoments Of Intertia:");
  88:                              ed.WriteMessage(string.Format("\nX: {0}", momentOfInertia[0]));
  89:                              ed.WriteMessage(string.Format("\nY: {0}", momentOfInertia[1]));
  90:                              ed.WriteMessage("\n" + new string('=', 30));
  91:   
  92:                              double productOfInertia = ar.ProductOfInertia;
  93:                              ed.WriteMessage(string.Format("\nProduct Of Inertia: {0}", productOfInertia));
  94:                              ed.WriteMessage("\n" + new string('=', 30));
  95:   
  96:                              double[] radiiOfGyration = (double[])ar.RadiiOfGyration;
  97:                              ed.WriteMessage("\nRadii Of Gyration:");
  98:                              ed.WriteMessage(string.Format("\nX: {0}", radiiOfGyration[0]));
  99:                              ed.WriteMessage(string.Format("\nY: {0}", radiiOfGyration[1]));
 100:                              ed.WriteMessage("\n" + new string('=', 30));
 101:   
 102:                              double[] centroid = (double[])ar.Centroid;
 103:                              ed.WriteMessage("\nCentroid:");
 104:                              ed.WriteMessage(string.Format("\nX: {0}", centroid[0]));
 105:                              ed.WriteMessage(string.Format("\nY: {0}", centroid[1]));
 106:                              ed.WriteMessage("\n" + new string('=', 30));
 107:   
 108:                              double[] principalMoments = (double[])ar.PrincipalMoments;
 109:                              ed.WriteMessage("\nPrincipal Moments:");
 110:                              ed.WriteMessage(string.Format("\nI: {0}", principalMoments[0]));
 111:                              ed.WriteMessage(string.Format("\nJ: {0}", principalMoments[1]));
 112:                              ed.WriteMessage("\n" + new string('=', 30));
 113:   
 114:                              double[] principalDirections = (double[])ar.PrincipalDirections;
 115:                              ed.WriteMessage("\nPrincipal Directions:");
 116:                              ed.WriteMessage(string.Format("\nX: {0}", principalDirections[0]));
 117:                              ed.WriteMessage(string.Format("\nY: {0}", principalDirections[1]));
 118:                              ed.WriteMessage("\n" + new string('=', 30));
 119:   
 120:                              double[] normal = (double[])ar.Normal;
 121:                              ed.WriteMessage("\nNormal (vector):");
 122:                              ed.WriteMessage(string.Format("\nX: {0}", normal[0]));
 123:                              ed.WriteMessage(string.Format("\nY: {0}", normal[1]));
 124:                              ed.WriteMessage(string.Format("\nZ: {0}", normal[2]));
 125:                              ed.WriteMessage("\n" + new string('=', 30));
 126:                              ed.WriteMessage("\n");
 127:                          }
 128:                      }
 129:                  }
 130:              }
 131:              catch (System.Exception ex) {
 132:                  ed.WriteMessage("\nОшибка: {0}\n", ex.Message);
 133:              } 
 134:          }
 135:      }
 136:  }

    Ниже привожу два скрина в случае получения информации из корректных регионов.
    Результат работы команды
_massprop:


Результат работы моей команды:


Вот собственно и всё...


Comments