Главная »Статьи »AutoCAD и Delphi » |
Открытая истина делается проста. Появление MLeaders (Multileaders, мультивыносок) в AutoCAD расширило его возможности, но и, к сожалению, добавило хлопот их, подчас, непредсказуемым поведением. С программной точки зрения также не все просто. Ситуацию усугубляет невнятная документация и терминология. Поэтому с нее и начнем.
MLeader состоит из кластеров и содержимого. MLeader может содержать только 1 или 2 кластера (leader) — левый и правый. Соответственно их индексы 0 и 1. Каждый кластер может содержать неограниченное количество выносок (leaderLine). Каждая выноска может иметь полку (DogLeg) и неограниченное количество узлов. Содержимое (Content) может отсутствовать, быть MText-ом или блоком (в т.ч. пользовательским). Стили MLeader AutoCAD хранит в словаре ACAD_MLEADERSTYLE. Пример получения списка стилей в lbMLeaderStyles: TListBox: . . . var MLeaderDictionary, MLeaderStyle: OleVariant; i, N, C: Integer; CurrStyle, S: String; begin // Список стилей try MLeaderDictionary:= Acad.ActiveDocument.Dictionaries.Item('ACAD_MLEADERSTYLE'); except raise EOleError.Create('Стили MultiLeader не обнаружены!'); end; // Текущий стиль CurrStyle:= Acad.ActiveDocument.GetVariable('CMLEADERSTYLE'); // Получить и показать список стилей MultiLeader lbMLeaderStyles.Clear; lbMLeaderStyles.Items.BeginUpdate; try N:= MLeaderDictionary.Count; // Количество элементов в словаре for i:= 0 to N - 1 do // Перебор всех элементов begin // Если имя объекта = 'AcDbMLeaderStyle' - этот элемент есть стиль MLeader if MLeaderDictionary.Item(i).ObjectName = 'AcDbMLeaderStyle' then begin MLeaderStyle:= MLeaderDictionary.Item(i); S:= MLeaderStyle.Name; if AnsiCompareText(S, CurrStyle) = 0 then // Это текущий стиль? C:= 1 // Да - установить метку "Текущий стиль" else C:= 0; // Сохранить вместе с меткой "Текущий стиль" lbMLeaderStyles.Items.AddObject(S, TObject(C)); end; end; finally lbMLeaderStyles.Items.EndUpdate; end; end; Как видно из этого примера, AutoCAD хранит имя текущего стиля в системной переменной CMLEADERSTYLE. Соответственно изменение текущего стиля производится записью в эту переменную нужного имени: Acad.ActiveDocument.SetVariable('CMLEADERSTYLE', 'Test'); Стиль с указанным именем должен существовать, иначе попытка установки приведет к ошибке "Error setting system variable". Для создания нового стиля в словарь ACAD_MLEADERSTYLE добавляется новый объект AcDbMLeaderStyle: . . . var MLeaderDictionary, MLeaderStyle: OleVariant; begin . . . // Создать новый стиль MLeaderStyle:= MLeaderDictionary.AddObject('Test', 'AcDbMLeaderStyle'); // Указать имя текстового стиля MLeaderStyle.TextStyle:= Acad.ActiveDocument.ActiveTextStyle.Name; // Установить другие свойства при необходимости MLeaderStyle.LeaderLineType:= acSplineLeader; end; Примечания:
С параметрами стиля MLeader можно ознакомиться по прилагаемому примеру, в котором считываются и демонстрируются все свойства указанного стиля. Получение информации о геометрии MLeaderПолезные свойства и методы MLeader: // Возвращает количество кластеров property LeaderCount: SYSINT; // Возвращает индексы массива выносок кластера leaderIndex function GetLeaderLineIndexes(leaderIndex: SYSINT): OleVariant; // Возвращает массив 3D-координат выноски leaderLineIndex function GetLeaderLineVertices(leaderLineIndex: SYSINT): OleVariant; Все выноски всех кластеров хранятся в одном массиве. В следующем примере в командную строку AutoCAD выводится количество кластеров и координаты всех узлов выносок указанной MLeader: . . . const fmtClusterCount = #13#10'Количество кластеров = %d.'#13#10; fmtClusterInfo = #13#10'Кластер = %d. Количество выносок = %d. Координаты узлов X, Y, Z:'#13#10; var BasePnt, Entity, LineIndexes, Coords: OleVariant; Obj: IDispatch; i, j, k, LeaderLineCounter, LeaderCount, iLBnd, iHBnd, cLBnd, cHBnd: Longint; S: String; begin try // Указать объект Acad.ActiveDocument.Utility.GetEntity(Obj, BasePnt, #13'Выделите MLeader: '); Entity:= Obj; except Exit; end; // Если это не MLeader - на выход if Entity.EntityType <> acMLeader then Exit; LeaderCount:= Entity.LeaderCount; // Количество кластеров Acad.ActiveDocument.Utility.Prompt(Format(fmtClusterCount, [LeaderCount])); // Перебираем кластеры LeaderLineCounter:= 0; for i:= 0 to LeaderCount - 1 do begin // Индексы выносок i-го кластера. Количество выносок = (iHBnd - iLBnd) + 1 LineIndexes:= Entity.GetLeaderLineIndexes(i); iLBnd:= VarArrayLowBound(LineIndexes, 1); iHBnd:= VarArrayHighBound(LineIndexes, 1); // Выводим заголовок информации по кластеру Acad.ActiveDocument.Utility.Prompt(Format(fmtClusterInfo, [i, (iHBnd - iLBnd) + 1])); // Перебираем выноски i-го кластера for j:= iLBnd to iHBnd do begin // Получаем массив 3D-координат текущей выноски Coords:= Entity.GetLeaderLineVertices(LeaderLineCounter); cLBnd:= VarArrayLowBound(Coords, 1); cHBnd:= VarArrayHighBound(Coords, 1); // Перебираем массив координат выноски и выводим их S:= ''; for k:= cLBnd to cHBnd do S:= S + Format('%8.3f', [Double(Coords[k])]); Acad.ActiveDocument.Utility.Prompt(S + #13#10); // Увеличиваем счетчик отработанных выносок Inc(LeaderLineCounter); end; end; end; Пример для MLeader с одним кластером: Количество кластеров = 1. Кластер = 0. Количество выносок = 2. Координаты узлов X, Y, Z: 0,000 50,000 0,000 30,000 70,000 0,000 5,000 50,000 0,000 30,000 70,000 0,000 Пример для MLeader с двумя кластерами: Количество кластеров = 2. Кластер = 0. Количество выносок = 3. Координаты узлов X, Y, Z: 0,000 50,000 0,000 30,000 70,000 0,000 5,000 50,000 0,000 30,000 70,000 0,000 10,000 50,000 0,000 30,000 70,000 0,000 Кластер = 1. Количество выносок = 1. Координаты узлов X, Y, Z: 83,000 50,000 0,000 76,667 70,000 0,000 Построение MLeaderMLeader строится текущим стилем методом AddMLeader коллекций AcadModelSpace, AcadPaperSpace, AcadBlock. // В функцию передается массив 3-D координат узлов выносок. // Возвращает объект AcadMLeader и индекс кластера function AddMLeader(PointsArray: OleVariant; out leaderLineIndex: SYSINT): OleVariant; Массив PointsArray должен содержать координаты не менее 2-х точек, т.е. иметь число элементов не менее 6-ти. Простая MLeader с текстом: . . . var P1, P2, V, Leader: OleVariant; N: Integer; begin // Запрос точек P1:= Acad.ActiveDocument.Utility.GetPoint(, 'Начальная точка: '); P2:= Acad.ActiveDocument.Utility.GetPoint(P1, 'Конечная точка: '); // Массив координат (2 точки MLeader, следовательно 6 элементов в массиве) V:= VarArrayCreate([0, 5], varDouble); V[0]:= P1[0]; V[1]:= P1[1]; V[2]:= P1[2]; V[3]:= P2[0]; V[4]:= P2[1]; V[5]:= P2[2]; // Добавляем MLeader. Если мы хотим добавить MLeader с текстом, то текущим // стилем должен быть стиль у которого контент настроен на MText Leader:= Acad.ActiveDocument.ModelSpace.AddMLeader(V, N); // Настраиваем свойства Leader.TextString:= '555-555'; // собственно текст (может быть многострочным) Leader.ArrowheadType:= acArrowDefault; // обычная залитая стрелка Leader.ArrowheadSize:= 4; // длина стрелки Leader.DogLegged:= False; // без горизонтальной полки Leader.DoglegLength:= 0; // длина полки = 0 Leader.LandingGap:= 2; // отступ текста от полки по-горизонтали // Подчеркиваем 1-ю строку текста - получается как бы текст над полкой Leader.TextLeftAttachmentType:= acAttachmentBottomOfTopLine; Leader.TextRightAttachmentType:= acAttachmentBottomOfTopLine; Leader.TextFrameDisplay:= False; // текст без рамки Leader.TextBackgroundFill:= False; // текст без заливки фона Leader.TextDirection:= acLeftToRight; // текст слева-направо Leader.TextHeight:= 3.5; // высота текста Leader.TextWidth:= 0; // ширина текста (используется для переноса текста по словам) Leader.TextJustify:= acAttachmentPointBottomCenter; // выравнивание текста end; Простая MLeader с блоком: . . . var P1, P2, V, Leader: OleVariant; N: Integer; begin // Запрос точек P1:= Acad.ActiveDocument.Utility.GetPoint(, 'Начальная точка: '); P2:= Acad.ActiveDocument.Utility.GetPoint(P1, 'Конечная точка: '); // Массив координат (2 точки MLeader, следовательно 6 элементов в массиве) V:= VarArrayCreate([0, 5], varDouble); V[0]:= P1[0]; V[1]:= P1[1]; V[2]:= P1[2]; V[3]:= P2[0]; V[4]:= P2[1]; V[5]:= P2[2]; // Добавляем MLeader. Если мы хотим добавить MLeader с блоком, то текущим // стилем должен быть стиль у которого контент настроен на блок Leader:= Acad.ActiveDocument.ModelSpace.AddMLeader(V, N); // Настраиваем свойства Leader.ContentBlockType:= acBlockBox; // тип блока (рамка) Leader.LeaderType:= acStraightLeader; // линия стрелки - прямая (не сплайн) Leader.ArrowheadType:= acArrowDefault; // обычная залитая стрелка Leader.ArrowheadSize:= 4; // длина стрелки Leader.DogLegged:= True; // с горизонтальной полкой Leader.DoglegLength:= 5; // длина полки = 5 end; Для добавления новых выносок служит метод: // В функцию передается индекс кластера (0 или 1) и массив 3-D координат узлов выносок. // Возвращаемое значение - индекс созданной выноски function AddLeaderLine(leaderIndex: SYSINT; pointArray: OleVariant): SYSINT; Массив координат должен содержать не менее 6-ти элементов, т.е. 2-х точек. Чтобы новая выноска имела более чем 1 сегмент (например ломаная) необходимо задать массив координат из 9-ти и более элементов. Пример построения MLeader с 2-мя выносками: ... var P1, P2, V, Leader: OleVariant; N: Integer; begin // Запрос точек P1:= Acad.ActiveDocument.Utility.GetPoint(, 'Начальная точка: '); P2:= Acad.ActiveDocument.Utility.GetPoint(P1, 'Конечная точка: '); // Массив координат (2 точки MLeader, следовательно 6 элементов в массиве) V:= VarArrayCreate([0, 5], varDouble); V[0]:= P1[0]; V[1]:= P1[1]; V[2]:= P1[2]; V[3]:= P2[0]; V[4]:= P2[1]; V[5]:= P2[2]; // Добавляем MLeader. Она содержит только 1 кластер с индексом 0 Leader:= Acad.ActiveDocument.ModelSpace.AddMLeader(V, N); // Массив координат для второй выноски V[0]:= V[0] + 5; // Координату X начальной точки смещаем вправо на 5 // Добавляем вторую выноску в нулевой кластер Leader.AddLeaderLine(0, V); // Настраиваем остальные свойства Leader.TextString:= edTextString.Text; end; Для добавления кластера используется метод: // Возвращаемое значение - индекс нового кластера function AddLeader: SYSINT; Пример построения двух-кластерной MLeader: ... var P1, P2, V, Leader: OleVariant; N: Integer; begin // Запрос точек P1:= Acad.ActiveDocument.Utility.GetPoint(, 'Начальная точка: '); P2:= Acad.ActiveDocument.Utility.GetPoint(P1, 'Конечная точка: '); // Массив координат (2 точки MLeader, следовательно 6 элементов в массиве) V:= VarArrayCreate([0, 5], varDouble); V[0]:= P1[0]; V[1]:= P1[1]; V[2]:= P1[2]; V[3]:= P2[0]; V[4]:= P2[1]; V[5]:= P2[2]; // Добавляем MLeader. Она содержит только 1 кластер Leader:= Acad.ActiveDocument.ModelSpace.AddMLeader(V, N); // Добавляем второй кластер N:= Leader.AddLeader; // Массив координат для второго кластера (используем тот же, что для основной) V[0]:= V[0] + 5; // Координату X начальной точки смещаем вправо на 5 Leader.AddLeaderLine(N, V); // Добавляем второй кластер // Настраиваем остальные свойства Leader.TextString:= edTextString.Text; AddLeader можно использовать многократно, добавляя все новые кластеры, но количество кластеров более 2-х не корректно.
Метод AddLeaderLineEx. // В функцию передается 3-D массив координат узлов выносок. // Возвращаемое значение - индекс созданной выноски function AddLeaderLineEx(pointArray: OleVariant): SYSINT; Этот метод стоит несколько особняком, потому что позволяет не только добавить новую выноску, но и создает, при необходимости, новый кластер. Если выноска располагается ближе к стороне с имеющимся кластером, она просто добавляется к этому кластеру. Если же выноска располагается ближе к стороне противоположного кластера (даже если он в данный момент еще не существует), она добавится к этому кластеру, а сам кластер создается автоматически. В прилагаемом примере создан интерфейс, позволяющий при построении настроить все параметры MLeader. Внимание! Если добавляется MLeader с блоком, то текущим стилем должен быть стиль, у которого контент настроен на блок, если добавляется MLeader с текстом — текущий стиль должен быть настроен на MText. Иначе при попытке установки свойств, присущих только тому или другому типу контента возникает исключение: "EOleException with message "Неопознанная ошибка". К статье прилагается пример на Delphi 7. Внимание! Запрещается воспроизведение
данной статьи или ее части без согласования с автором. Если вы желаете разместить
эту статью на своем сайте или издать в печатном виде, свяжитесь с автором. |