| Правила | Регистрация | Пользователи | Поиск | Сообщения за день | Все разделы прочитаны |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > .NET > .NET C#. как извлекать из BlockTable конкретные примитивы?

.NET C#. как извлекать из BlockTable конкретные примитивы?

Ответ
Поиск в этой теме
Непрочитано 03.09.2011, 14:15 #1
.NET C#. как извлекать из BlockTable конкретные примитивы?
Йцукенгшщзхъ
 
Регистрация: 18.08.2011
Сообщений: 7

Есть такой код:

Код:
[Выделить все]
        public static List<DBObject> GetObjects()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                // извлечение объектов из БД чертежа

                BlockTable acBlTbl;
                acBlTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

                BlockTableRecord acBlTblRec;
                acBlTblRec = acTrans.GetObject(acBlTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

                var allObjects = new List<DBObject>();

                try
                {
                    allObjects.AddRange(from ObjectId objectId in acBlTblRec
                                        select acTrans.GetObject(objectId, OpenMode.ForRead));
                }
                catch
                {
                    acDoc.Editor.WriteMessage("Ошибка GetObjects");
                }
                 
                return allObjects;
            }
        }
Не могу разобраться, как из allObjects извлечь конкретные примитивы типа точек, отрезков, окружностей и прочего.
Просмотров: 7068
 
Непрочитано 03.09.2011, 19:48
#2
TararykovDG

Программист-энтузиаст
 
Регистрация: 17.07.2009
Воронеж
Сообщений: 571


Может так: allObjects.ElementAt(<индекс>)
__________________
cadtools
TararykovDG вне форума  
 
Автор темы   Непрочитано 04.09.2011, 10:16
#3
Йцукенгшщзхъ


 
Регистрация: 18.08.2011
Сообщений: 7


Цитата:
Сообщение от TararykovDG Посмотреть сообщение
Может так: allObjects.ElementAt(<индекс>)
А как узнать индекс конкретного примитива?..
Я тут уже решение одно нашел :
Код:
[Выделить все]
 for (int i = 0; i < allObjects.Count; i++)
                {
                    DBPoint pnt = allObjects[i] as DBPoint;
                    if (pnt != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена точка с координатами: " + pnt.Position.ToString());
                    }

                    Line line = allObjects[i] as Line;
                    if (line != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена линия с координатами: начальная точка: " + line.StartPoint.ToString() + ", конечная точка" + line.EndPoint.ToString());
                    }

                    Circle crl = allObjects[i] as Circle;
                    if (crl != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена окружность с координатами: центр точка: " + crl.Center.ToString() + ", радиус" + crl.Radius.ToString());
                    }

                }
Йцукенгшщзхъ вне форума  
 
Непрочитано 04.09.2011, 13:56
#4
TararykovDG

Программист-энтузиаст
 
Регистрация: 17.07.2009
Воронеж
Сообщений: 571


Йцукенгшщзхъ, я то думал что нужно просто перейти от allObjects к объектам содержащимся в нем. Если надо сформировать набор всех точек чертежа или каких-либо других примитивов, то зачем брать все объекты, я потом из них как-то там вытаскивать конкретные, если можно сразу получить набор каких-то конкретных примитивов(точек, полилиний, отрезков, окружностей и т. д.)
Код:
[Выделить все]
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput; 

[CommandMethod("FilterSelectionSet")]
public static void FilterSelectionSet()
{
  // Get the current document editor
  Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor; 

  // Create a TypedValue array to define the filter criteria
  TypedValue[] acTypValAr = new TypedValue[1];
  acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "CIRCLE"), 0); 

  // Assign the filter criteria to a SelectionFilter object
  SelectionFilter acSelFtr = new SelectionFilter(acTypValAr); 

  // Request for objects to be selected in the drawing area
  PromptSelectionResult acSSPrompt;
  acSSPrompt = acDocEd.GetSelection(acSelFtr); 

  // If the prompt status is OK, objects were selected
  if (acSSPrompt.Status == PromptStatus.OK)
  {
      SelectionSet acSSet = acSSPrompt.Value;

      Application.ShowAlertDialog("Number of objects selected: " +
                                  acSSet.Count.ToString());
  }
  else
  {
      Application.ShowAlertDialog("Number of objects selected: 0");
  }
}
Здесь более подробно на английском
P. S. есть еще сайт hwd AutoCAD .Net Laboratory на русском, но сейчас туда почему-то не достучаться, это надо у автора узнавать.
__________________
cadtools

Последний раз редактировалось TararykovDG, 13.09.2011 в 08:29. Причина: Правил ссылки
TararykovDG вне форума  
 
Непрочитано 04.09.2011, 14:05
#5
hwd

C, C++, C#
 
Регистрация: 07.10.2009
С-Пб.
Сообщений: 2,762
Отправить сообщение для hwd с помощью Skype™


Цитата:
Сообщение от Йцукенгшщзхъ Посмотреть сообщение
А как узнать индекс конкретного примитива?..
Я тут уже решение одно нашел :
Код:
[Выделить все]
 for (int i = 0; i < allObjects.Count; i++)
                {
                    DBPoint pnt = allObjects[i] as DBPoint;
                    if (pnt != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена точка с координатами: " + pnt.Position.ToString());
                    }

                    Line line = allObjects[i] as Line;
                    if (line != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена линия с координатами: начальная точка: " + line.StartPoint.ToString() + ", конечная точка" + line.EndPoint.ToString());
                    }

                    Circle crl = allObjects[i] as Circle;
                    if (crl != null)
                    {
                        acDoc.Editor.WriteMessage("\nНайдена окружность с координатами: центр точка: " + crl.Center.ToString() + ", радиус" + crl.Radius.ToString());
                    }

                }
имхо - решение далеко не самое красивое.
Если это терпит 2 недели - подожди (в личку ответил о причинах такого срока). У меня есть готовый код под то, что пишешь. Если будет ещё актуально - вернусь скину.
__________________
Надеюсь, ты не социальный овощ? Это определяется делами! :welcome:
hwd вне форума  
 
Автор темы   Непрочитано 04.09.2011, 18:44
#6
Йцукенгшщзхъ


 
Регистрация: 18.08.2011
Сообщений: 7


Цитата:
Сообщение от TararykovDG Посмотреть сообщение
Если надо сформировать набор всех точек чертежа или каких-либо других примитивов, то зачем брать все объекты
Для приложения нужны вообще все примитивы, где бы они не находились. Преложить юзверю выбрать нужные тут не подходит.

Вообще, нужно выбирать примитивы и редактировать их свойства с последующем изменением на чертеже. То есть выбрать, присвоить значения, записать обратно.
Интересно, что прочитав мануалы и хелпы по .NET API нигде не увидел примеры выборки и редактирования примитивов - только редактирование свойств слоев.
Йцукенгшщзхъ вне форума  
 
Непрочитано 04.09.2011, 20:28
1 | #7
TararykovDG

Программист-энтузиаст
 
Регистрация: 17.07.2009
Воронеж
Сообщений: 571


Цитата:
Сообщение от Йцукенгшщзхъ Посмотреть сообщение
Преложить юзверю выбрать нужные тут не подходит.
Да это просто был пример как выбрать объекты с чертежа. Можно и без запроса у пользователя
Вот пример (именно пример) кода, который перебирает все объекты чертежа (без запроса у пользователя выбора объектов) и некоторым из них меняет свойства (все круги делает зелеными, все полилинии синими, все отрезки красными, остальные объекты не изменяются)
Код:
[Выделить все]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

namespace ChangeObjectProperties
{
    public class Class1
    {
        [CommandMethod("COP")]
        public static void ChangeObjProp()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                PromptSelectionResult acSSPrompt = acDoc.Editor.SelectAll();
                if (acSSPrompt.Status == PromptStatus.OK)
                {
                    SelectionSet acSSet = acSSPrompt.Value;
                    string acEntType;
                    foreach (SelectedObject acSSObj in acSSet)
                    {
                        if (acSSObj != null)
                        {
                            Entity acEnt = acTrans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
                            if (acEnt != null)
                            {
                                // здесь наверное можно как-то практичнее определять тип примитива, но честно говоря не сообразил
                                acEntType = acEnt.ToString();
                                if (acEntType == "Autodesk.AutoCAD.DatabaseServices.Circle")
                                {
                                    acEnt.ColorIndex = 3;
                                }
                                if (acEntType == "Autodesk.AutoCAD.DatabaseServices.Polyline")
                                {
                                    acEnt.ColorIndex = 5;
                                }
                                if (acEntType == "Autodesk.AutoCAD.DatabaseServices.Line")
                                {
                                    acEnt.ColorIndex = 1;
                                }
                            }
                        }
                    }
                    acTrans.Commit();
                }
            }
        }
    }
}
P. S.
Цитата:
Сообщение от Йцукенгшщзхъ Посмотреть сообщение
Интересно, что прочитав мануалы и хелпы по .NET API нигде не увидел примеры выборки и редактирования примитивов - только редактирование свойств слоев.
Все это есть в ссылке которую я указал в посте #4
__________________
cadtools
TararykovDG вне форума  
 
Автор темы   Непрочитано 05.09.2011, 10:09
#8
Йцукенгшщзхъ


 
Регистрация: 18.08.2011
Сообщений: 7


Со всем разобрался, кроме того, какое поле отвечает за "Высоту 3D". Сначала думал, что это DBPoint.Position.Normal.Z, оказалось нет.

Кто-нибудь может подсказать какое поле у примитива отвечает за высоту 3D?
Йцукенгшщзхъ вне форума  
 
Непрочитано 05.09.2011, 11:51
1 | #9
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,405
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Йцукенгшщзхъ Посмотреть сообщение
Кто-нибудь может подсказать какое поле у примитива отвечает за высоту 3D?
Высота или координата? Общего свойства нет. Для высоты есть свойство Thickness у некоторых 2D-примитивов.
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 05.09.2011, 13:54
#10
Йцукенгшщзхъ


 
Регистрация: 18.08.2011
Сообщений: 7


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
Высота или координата? Общего свойства нет. Для высоты есть свойство Thickness у некоторых 2D-примитивов.
Вот это:

Нажмите на изображение для увеличения
Название: heigth.png
Просмотров: 128
Размер:	12.8 Кб
ID:	65720

Действительно, "Высота 3D" в данном случае - свойство Thickness. Большое спасибо, Александр.

Последний раз редактировалось Йцукенгшщзхъ, 05.09.2011 в 14:08.
Йцукенгшщзхъ вне форума  
 
Непрочитано 16.09.2011, 18:44
#11
bargool


 
Регистрация: 16.08.2006
Санкт-Петербург
Сообщений: 508
<phrase 1=


Так получаем набор линий, к примеру
Код:
[Выделить все]
public void GetLines()
{
	Document acadDocument = Application.DocumentManager.MdiActiveDocument;
	Database acadCurDb = acadDocument.Database;
	using (Transaction acadTrans = acadCurDb.TransactionManager.StartTransaction())
	{
		BlockTable blockTable = acadTrans.GetObject(acadCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
		BlockTableRecord blockTableRecord = acadTrans.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
						
		var lines = from ObjectId line in blockTableRecord where acadTrans.GetObject(line, OpenMode.ForRead) is Line select (Line)acadTrans.GetObject(line, OpenMode.ForRead);

		foreach (Line line in lines)
		{
			acadDocument.Editor.WriteMessage("\nДлина: {0}", line.Length);
		}
	}
}
Хотя мне кажется, тоже не очень решение.
hwd, ждём!

TararykovDG, Если твоим методом выделять определённые примитивы, то можно использовать фильтр, который неоднократно помогал и при обычной работе с автокадом..
Код:
[Выделить все]
//Выделять будем только линии и полилинии. Создаем фильтр
TypedValue[] acadFilterValues = new TypedValue[4];
acadFilterValues.SetValue(new TypedValue((int)DxfCode.Operator, "<OR"),0);
acadFilterValues.SetValue(new TypedValue((int)DxfCode.Start, "LINE"),1);
acadFilterValues.SetValue(new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),2);
acadFilterValues.SetValue(new TypedValue((int)DxfCode.Operator, "OR>"),3);
SelectionFilter acadSelFilter = new SelectionFilter(acadFilterValues);
//Выделяем ВСЕ линии и полилинии на незамороженных слоях
SelectionSet selectionSet = acadDocument.Editor.SelectAll(acadSelFilter).Value;
//Проходим по получившемуся выделению
foreach (SelectedObject selectedObj in selectionSet)
{
//Ну и так далее..

Последний раз редактировалось bargool, 16.09.2011 в 18:51.
bargool вне форума  
 
Непрочитано 17.09.2011, 20:17
1 | #12
hwd

C, C++, C#
 
Регистрация: 07.10.2009
С-Пб.
Сообщений: 2,762
Отправить сообщение для hwd с помощью Skype™


Я в подобных случаях выполняю группировку результата. На переделанном примере топикстартера это выглядит так:
Код:
[Выделить все]
...
        //Все идентификаторы объектов, находящихся в пространстве модели, сгруппированы по их типу
        public Dictionary<string, List<ObjectId>> GetObjects() {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) {
                BlockTable acBlTbl = (BlockTable) acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead);
                BlockTableRecord acBlTblRec = (BlockTableRecord) acTrans.GetObject(acBlTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                Dictionary<string, List<ObjectId>> dict = new Dictionary<string, List<ObjectId>>();

                foreach (ObjectId item in acBlTblRec) {
                    if (item.IsValid && !item.IsErased)
                        if (!dict.Keys.Contains(item.ObjectClass.Name))
                            dict.Add(item.ObjectClass.Name, new List<ObjectId>() { item });
                        else
                            dict[item.ObjectClass.Name].Add(item);
                }
                return dict;
            }
        }

        /// <summary>
        /// Работаем с имеющимися в пространстве модели, не удалёнными объектами
        /// </summary>
        [CommandMethod("Sample", CommandFlags.Modal)]
        public void Sample() {
            Document dwg = acad.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;
            Database db = dwg.Database;

            Dictionary<string, List<ObjectId>> dict = GetObjects();

            //Поскольку в словаре все идентификаторы сгруппированы, нет нужны проверять тип - 
            //можно сразу выполнять приведение (см. далее)

            using (Transaction t = db.TransactionManager.StartTransaction()) {
                //Получить все таблицы:
                foreach (ObjectId item in dict["AcDbTable"]) {
                    Table table = (Table) t.GetObject(item, OpenMode.ForRead);
                    //далее нужный тебе код
                }

                //Получить все однострочные тексты:
                foreach (ObjectId item in dict["AcDbText"]) {
                    DBText text = (DBText) t.GetObject(item, OpenMode.ForRead);
                    //далее нужный тебе код
                }

                //Получить все многострочные тексты:
                foreach (ObjectId item in dict["AcDbMText"]) {
                    MText mtext = (MText) t.GetObject(item, OpenMode.ForRead);
                    //далее нужный тебе код
                }
                //ну и т.д.
            }            
        }
...
Теперь по поводу этого:
Цитата:
Сообщение от Йцукенгшщзхъ
Для приложения нужны вообще все примитивы, где бы они не находились. Преложить юзверю выбрать нужные тут не подходит.

Вообще, нужно выбирать примитивы и редактировать их свойства с последующем изменением на чертеже. То есть выбрать, присвоить значения, записать обратно.
Интересно, что прочитав мануалы и хелпы по .NET API нигде не увидел примеры выборки и редактирования примитивов - только редактирование свойств слоев.
Выкладываю тестовый проект, в котором мною написана небольшая библиотека, точнее её самостоятельный фрагмент (это можно воспринимать как некоторое дополнение к AutoCAD .Net API) и примеры её использования. Весь код детально комментирован. Там же прилагаются и два dwg-файла (один из них умышленно раздут до 50 метров, чтобы на нём продемонстрировать скорость работы) - на них тестировал код.
Если что будет непонятно по коду - спрашивай.

п.с. проект MS VS 2010; AutoCAD 2009 x86
__________________
Надеюсь, ты не социальный овощ? Это определяется делами! :welcome:

Последний раз редактировалось hwd, 21.09.2011 в 11:03.
hwd вне форума  
 
Непрочитано 21.09.2011, 11:02
#13
hwd

C, C++, C#
 
Регистрация: 07.10.2009
С-Пб.
Сообщений: 2,762
Отправить сообщение для hwd с помощью Skype™


Обновил содержимое ссылки, обозначенной мною в #12.
Изменения, внесённые в библиотеку:
1. Исправлен ряд ошибок в коде
2. Внесены изменения в сигнатуры некоторых методов
3. Исправлены ошибки, найденные в комментариях
4. Внесены некоторые изменения в код тестовых команд
5. Добавлены новые тесты
6. Некоторые методы переименованы (дабы их назначение было более понятным)
7. Добавлен ряд новых методов расширений (для Database, Transaction, Editor, SymbolTable).

п.с. это не окончательная версия библиотеки - она будет продолжать тестироваться и отлаживаться в случае обнаружения ошибок. В ближайшее время в неё будут добавлены менеджеры управления стилями (текстовый/размерный/мультивыносок/таблиц), реализующие единый программный интерфейс (interface). Исходный код подробно комментирован, однако, тем не менее в ближайшее время планирую выполнить генерацию справочной системы под библиотеку.

п.с.2 Замечания и пожелания по существу (я о библиотеке) - приветствуются.
__________________
Надеюсь, ты не социальный овощ? Это определяется делами! :welcome:

Последний раз редактировалось hwd, 21.09.2011 в 11:12.
hwd вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > .NET > .NET C#. как извлекать из BlockTable конкретные примитивы?

Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск