Главная »Статьи »AutoCAD и Delphi »Блоки
Блоки

Блок это особый тип объетов AutoCAD, содержимое которого сохраняется в таблице определений блоков файла DWG. Програмный доступ к определениям блоков осуществляется через коллекцию Blocks. Блок в рисунок вставляется в виде ссылки (BlockReference) на его имя в таблице определений и точки вставки.

Ниже приведена функция, возвращающая имена всех блоков в документе:

function EnumBlockNames(Items: TStrings; IncludeSpecial: Boolean = False): Integer;
var
  i, BlocksCount: Integer;
  BlkName: string;
begin
  Result:= -1;
  if not VarIsClear(Acad) then
  begin
    with Items do
    begin
      BeginUpdate;
      try
        Clear;
        BlocksCount:= Acad.ActiveDocument.Blocks.Count;
        for i:= 0 to BlocksCount - 1 do
        begin
          BlkName:= Acad.ActiveDocument.Blocks.Item(i).Name;
          if (not IncludeSpecial) and (BlkName[1] <> '*') or IncludeSpecial then
            Add(BlkName);
        end;
      finally
        EndUpdate;
      end;
      Result:= Count;
    end;
  end;
end;

Здесь надо обратить внимание на условие:

if (not IncludeSpecial) and (BlkName[1] <> '*') or IncludeSpecial then

задающее включить ли в список имена спецблоков, под которыми понимаются коллекции объектов пространства модели (*MODEL_SPACE) и листа (*PAPER_SPACE). Имена спецблоков начинаются с символа *, что и используется в условии.

Если блок с именем *MODEL_SPACE может быть только один, то блоков *PAPER_SPACE столько, сколько Layout. Их имена обозначаются по формуле: *PAPER_SPACEn, где n целое, начиная с 0, но для блока, отражающего текущее пространство листа имя всегда *PAPER_SPACE.

Метод создания:

// Возвращаемое значение объект AcadBlock
function Add(InsertionPoint: OleVariant; const Name: WideString): OleVariant;

Пример использования:

var
  BlockName: string;
  Block, BlkRef: OleVariant;
begin
  if not VarIsClear(Acad) then
  begin
    BlockName:= 'New Block';
    // Добавить новый блок в коллекцию блоков
    Block:= Acad.ActiveDocument.Blocks.Add(AcadPoint(0, 0), BlockName);
    // Добавить во вновь созданный блок графические объекты
    Block.AddLine(AcadPoint(0, 0), AcadPoint(10, 10));
    Block.AddLine(AcadPoint(10, 10), AcadPoint(-10, 10));
    Block.AddLine(AcadPoint(-10, 10), AcadPoint(0, 0));
    // Отобразить список блоков в lbBlkNames: TListBox 
    EnumBlockNames(lbBlkNames.Items, ckbIncSpecBlocks.Checked);
  end;
end;

В результате выполнения приведенного примера в файл будет добавлен новый блок с именем "New Block". Теперь его можно вставить в чертеж с помощью метода:

// Возвращаемое значение объект AcadBlockReference
function InsertBlock(InsertionPoint: OleVariant; const Name: WideString; Xscale, Yscale, Zscale: Double;
         Rotation: Double): OleVariant;

Пример использования — вставка блока с именем из списка lbBlkNames:

var
  BlockName: string;
  BlkRef, InsPnt: OleVariant;
begin
  if not VarIsClear(Acad) and (lbBlkNames.ItemIndex >= 0) then
  begin
    InsPnt:= Acad.ActiveDocument.Utility.GetPoint(, 'Укажите первую точку: ');
    with lbBlkNames do
      BlockName:= Items[ItemIndex];
    BlkRef:= Acad.ActiveDocument.ModelSpace.InsertBlock(InsPnt, BlockName, 1, 1, 1, 0);
    BlkRef.Update;
  end;
end;

Замечательной особенностью блоков является возможность добавлять в них атрибуты, значения которых затем могут быть изменены или извлечены. Атрибут подобен обычному однострочному тексту. Для вставки атрибута в блок используется метод:

// Возвращаемое значение объект AcadAttribute
function AddAttribute(Height: Double; Mode: AcAttributeMode; const Prompt: WideString; 
         InsertionPoint: OleVariant; const Tag: WideString; const Value: WideString): OleVariant;

Параметры метода в основном аналогичны задаваемым в диалоге Attribute Definition:

Чтобы извлечь атрибуты вставленного блока надо для начала узнать есть ли они у него, для чего проверить значение его свойства HasAttributes типа WordBool. Далее вызовом метода GetAttributes получаем ссылку на вариантный массив со всеми атрибутами блока. В приведенном ниже примере после выбора пользователем блока, его атрибуты извлекаются в ini-подобный файл:

procedure ExtractBlkRefAttr(ABlkRef: OleVariant; AFileName: string);
var
  AttrArray, AttrRef: OleVariant;
  i, LBnd, HBnd: Integer;
  lst: TStringList;
begin
  if ABlkRef.HasAttributes then
  begin
    lst:= TStringList.Create;
    try
      lst.Add(Format('[%s]', [ABlkRef.Name]));
      AttrArray:= ABlkRef.GetAttributes;
      LBnd:= VarArrayLowBound(AttrArray, 1);
      HBnd:= VarArrayHighBound(AttrArray, 1);
      for i:= LBnd to HBnd do
      begin
        AttrRef:= AttrArray[i];
        lst.Add(Format('%s=%s', [AttrRef.TagString, AttrRef.TextString]));
      end;
      lst.SaveToFile(AFileName);
    finally
      lst.Free;
    end;
  end else
    raise Exception.CreateFmt('Блок "%s" не имеет атрибутов', [ABlkRef.Name]);
end;

procedure ExtractSameBlockAttr(AFileName: string);
var
BasePnt, BlkRef: OleVariant;
Entity: IDispatch;
begin
if not VarIsClear(Acad) then
begin
try
Acad.ActiveDocument.Utility.GetEntity(Entity, BasePnt, 'Укажите блок: ');
BlkRef:= Entity;
except
raise Exception.Create('Действие отменено');
end;
ExtractBlkRefAttr(BlkRef, AFileName);
end;
end;

Для извлечения атрибутов из всех блоков в чертеже можно использовать такую процедуру:

procedure ExtractBlockAttr(AFileName: string; Space: TWorkSpace = wsModelSpace);
var
  BlkRef: OleVariant;
  BlkName: string;
  i, ObjCount: Integer;
  lst: TStringList;
begin
  if not VarIsClear(Acad) then
  begin
    lst:= TStringList.Create;
    try
      if Space = wsModelSpace then
        ObjCount:= Acad.ActiveDocument.ModelSpace.Count
      else
        ObjCount:= Acad.ActiveDocument.PaperSpace.Count;
      for i:= 0 to ObjCount - 1 do
      begin
        if Space = wsModelSpace then
          BlkRef:= Acad.ActiveDocument.ModelSpace.Item(i)
        else
          BlkRef:= Acad.ActiveDocument.PaperSpace.Item(i);
        if BlkRef.ObjectName = 'AcDbBlockReference' then
        begin
          if BlkRef.HasAttributes then
          begin
            ExtractBlkRefAttr(BlkRef, lst);
          end;
        end;
      end;
      lst.SaveToFile(AFileName);
    finally
      lst.Free;
    end;
  end;
end;

Атрибуты извлекаются из блоков в пространстве модели или листа. В цикле перебираются все объкты заданного пространства. Условие if BlkRef.ObjectName = 'AcDbBlockReference' служит для идентификации типа объекта (блок/не блок). Конечно это не идеальное решение, но работает.

К статье прилагаются примеры на Delphi 7.


Внимание! Запрещается воспроизведение данной статьи или ее части без согласования с автором. Если вы желаете разместить эту статью на своем сайте или издать в печатном виде, свяжитесь с автором.
Автор статьи: Вершинин И.В.

 
Используются технологии uCoz