Расчленение вложенных блоков с помощью .NET
Некоторое время назад я написал статью о том, как использовать метод Entity.Explode() чтобы получить те же результаты, что и в команде РАСЧЛЕНИ (_EXPLODE). В комментариях я получил замечание, что с этим лучше справляется метод BlockReference.ExplodeToOwnerSpace.Мне захотелось использовать этот же метод для расчленения вложенных блоков, но так как BlockReference.ExplodeToOwnerSpace() не возвращает список созданных объектов, мне пришлось приспособить событие Database.ObjectAppended для этого и для рекурсивного вызова моей функции ExplodeBlock() со всеми вновь созданными блоками. Мы можем так же удалить оригинальный примитив (или примитивы если функция вызвана рекурсивно).
Как средствами AutoCAD определить расположение точки относительно контура.Автор: Александр Ривилис
Вопрос:
Есть ли встроенные средства для определения как расположена точка относительно контура в AutoCAD .NET API?
Ответ:
Специальных средств для этого нет. Но есть по меньшей мере два способа, которыми можно воспользоваться для этого:
- С использованием BREP .NET API (Autodesk.AutoCAD.BoundaryRepresentation) – Если превратить контур в Region, то можно будет воспользоваться возможностью Brep для определения положения точки внутри Region. Для этого можно воспользоваться методом BrepEntity.GetPointContainment, который возвращает объект-перечисление PointContainment, которое может принимать одно из трёх значений: Inside (внутри), Outside (снаружи), OnBoundary (на самом контуре).
- C использованием класса примитива MPolygon. Обычно этот класс используется в Civil 3D, но так как он есть и в базовом AutoCAD, то мы можем им воспользоваться.
В данной статье мы рассмотрим второй способ. Будем считать, что в качестве контура у нас имеется замкнутая полилиния. В общем случае она может иметь и дуговые сегменты, но не должна быть самопересекающейся – иначе теряется смысл понятия «внутри контура». Ниже пример команды, которая просит пользователя указать точку и полилинию. Обратите внимание на следующие моменты:
Использование потоков (Thread) для фоновой обработки
Вопрос:Внутри моей команды я хочу запустить фоновую задачу для синхронизации с базой данных. Как только эта задача заканчивается я хотел бы при помощи AutoCAD .NET API сделать некоторые изменения в базе данных. Однако, когда я вызываю функции AutoCAD API из этой задачи, они не работают. Например, the MdiActiveDocument равен null.
Ответ:
AutoCAD .NET API не позволяют использовать мультизадачность. Необходимо вызывать функции API из главной задачи.
Если вы находитесь в другой задаче, вам необходимо настроить вызов из главной задачи. Самый простой способ достичь этого – это создать объект System.Windows.Forms.Control в главной задаче и использовать его метод Invoke() для запуска функции которая и выполнит окончательную обработку.
Как удалить неиспользуемые и необработанные ссылки на данные (DataLink)?Автор: Александр Ривилис
Для необработанных ссылок на данные свойство IsValid всегда равно false. А вот с неиспользуемыми ссылками на данные несколько сложнее. Метод DataLink.GetTargets() возвращает коллекцию ObjectId объектов/примитивов, которые используют эту связь. Если таблица (Table) использовала связь, то её ObjectId содержится в коллекции DataLink.GetTargets(). Если эту таблицу стереть, то DataLink.GetTargets() не будет содержать ObjectId таблицы, а будет содержать ObjectId для объекта TableContent (это не примитив, т.е. не является наследником Entity). Таким образом, если DataLink.GetTargets() не содержит ObjectId ни одного примитива, то соответственно он не используется и его можно удалить. Следующий код это и показывает:
Как получить неиспользуемые внешние ссылки, растры и подложки?Автор: Александр Ривилис
Вопрос: Мне нужно средствами AutoCAD .NET API получить неиспользуемые внешние ссылки (XREF), растры (IMAGE), pdf-подложки (PDFUNDERLAY) и dwf-подложки (DWFUNDERLAY). Как это можно сделать?
Ответ: Для внешних ссылок достаточно найти все записи таблицы блоков (BlockTableRecord), свойство XrefStatus которых отлично от NotAnXref и для них справедливо выражение GetBlockReferenceIds(false, true).Count == 0
Для растров и подложек процедура несколько иная. Необходимо найти соответствующую таблицу (ACAD_IMAGE_DICT – для IMAGE, ACAD_PDFDEFINITIONS – для PDFUNDERLAY, ACAD_DWFDEFINITIONS – для DWFUNDERLAY) и получить из неё все ObjectId элементов. После этого достаточно воспользоваться методом Database.Purge(), чтобы получить только те ObjectId элементов, которые не используются.
Импортирование фильтров слоев
Здесь пример кода для импортирования фильтра слоев, включая вложенные фильтры, из другого чертежа. Слои, которые фигурируют в этих фильтрах, также копируются.
А вот пример чертежа, на котором проводились тесты: Загрузить тестовый чертеж
Запись и чтение Lisp-переменных в .NET API
Мы знаем, что записывать и читать lisp-переменные можно при помощи P/Invoke функций acedGetSym/acedPutSym из ObjectARX. Однако начиная с AutoCAD 2013 мы можем воспользоваться методами SetLispSymbol и GetLispSymbol класса Document.В следующем примере мы обратим внимание на запись нескольких фрагментов данных в lisp-переменную. Для этой цели используем тип TypedValue со значением перечисления LispDataType
Установка набора предварительного выбора в .NET API
Вы можете воспользоваться методом Editor.SetImpliedSelection для установки набора предварительного выбора (выбора с ручками). Ниже код команды, которая запрашивает у пользователя выбрать примитивы и устанавливает набор предварительного выбора. Обратите внимание на флаги команды, которые являются обязательными для установки pickfirst :Итерация системных переменных AutoCAD через .NET, часть 2
В предыдущей части был предоставлен код, показывающий реализацию двух доступных механизмов итерации по системным переменным AutoCAD: SystemObects.Variables и новый класс SystemVariableEnumerator.Итерация системных переменных AutoCAD через .NET, часть 1
Просматривая документацию по .NET API AutoCAD (раздел "Что нового"), можно увидеть новый класс SystemVariableEnumerator. Это очень интересно, поскольку уже есть способ получить системные переменные AutoCAD'a, используя коллекции...Вставка блока из другого DWG-файла с помощью .NET
С помощью метода WblockCloneObjects() можно скопировать блок из одного чертежа в другой. Код на C# показывает как можно использовать метод WblockCloneObjects чтобы скопировать определенный блок с именем "test" из чертежа, находящегося по пути "C:\TEMP\test.dwg".
Поиск удаленных примитивов
Чтобы получить запись таблицы блоков, в которой имеются удаленные примитивы, можно воспользоваться методом BlockTableRecord.IncludingErased. Например таким образом можно восстановить удаленные примитивы в блоке, как показано ниже.Установка относительного порядка отрисовки примитивов с помощью .NET
Чтобы установить относительный порядок отрисовки одних примитивов относительно других можно воспользоваться методами DrawOrderTable.MoveAbove или DrawOrderTable.MoveBellow как показано ниже в коде.Ошибка запуска VLIDE во время отладки .NET-сборки
При отладке .NET-сборки далеко не всегда удается вызвать VLIDEИзменение порядка отрисовки примитивов
Каждый блок в AutoCAD содержит информацию о порядке отрисовки примитивов в нём. Порядок отрисовки (DrawOrderTable) хранится в словаре расширения записи таблицы блоков. В .NET можно работать с этим словарем используя метод BlockTableRecord.DrawOrderTableId. Порядок отрисовки (DrawOrderTable), обеспечивает методы, такие как MoveToBottom, MoveToTop, MoveBelow, MoveAbove и так далее, которые позволяют изменить порядок отрисовки примитивов в блоке.
Создание нового слоя и установка его текущим
Следующий код показывает процедуру создания нового слоя. Все слои хранятся в символьной таблице, называемой таблицей слоёв. Чтобы сделать любой слой текущим, нужно установить свойство Clayer объекта Database в идентификатор объекта слоя.Обновление выравнивания текста
В ряде случаев выравнивание текста примитива DBText не выполняется. Для того чтобы заставить выполнится выравнивание используется метод DBText.AdjustAlignment. Этот метод для работы использует рабочую базу данных. Таким образом особенно важно указать ему рабочую базу данных, когда DBText еще не добавлен в рабочую базу данных.Создание анонимного слоя
Чтобы создать анонимный слой необходимо вызвать метод AcDbLayerTableRecord::setIsHidden()как показано ниже в коде. Анонимные слои не видны в диспетчере слоёв и соответственно пользователь не может редактировать/удалить анонимный слой.