Pular para o conteúdo principal

Transformando o conteúdo de um Layer em Bloco

Esses dias do fim do ano uma pessoa me procurou por e-mail pedindo uma solução para transformar o conteúdo de um Layer em um bloco.

Resolvi ajuda-lo. Realmente nunca tinha me deparado com esse tipo de problema antes por isso fiz uma pesquisa nos blog’s oficiais da Autodesk por soluções parecidas com as que eu necessitava.

Dividi a busca em duas partes em que eu realmente sabia que iria encontrar: (i) criar um bloco e coloca-lo na tela e (ii) selecionar todos os objetos do Layer.

Buscando, encontrei estes dois artigos:

Creating an AutoCAD block using .NET


Neste post de 2010 Kean Walmsley apresenta um código plenamente funcional para criar alguns objetos na tela e os transforma em um bloco já com entradas personalizadas para um nome do bloco pela linha de comando.

Finding all the AutoCAD entities on a particular layer using .NET

Neste outro post de 2008 Kean Walmsley apresenta uma forma que selecionar todos os objetos de um Layer. Inclusive cirando uma função específica para essa finalidade o que é bem útil.

Executei os dois códigos e tive sucesso em executá-los então parti para a solução de juntar os dois códigos em uma solução: selecionando os objetos do Layer depois transformando-os em um bloco.


    public class Commands
    {

        private static ObjectIdCollection
           GetEntitiesOnLayer(string layerName)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            // Build a filter list so that only entities
            // on the specified layer are selected

            TypedValue[] tvs = new TypedValue[1] { new TypedValue( (int)DxfCode.LayerName, layerName)
          };

            SelectionFilter sf = new SelectionFilter(tvs);
            PromptSelectionResult psr = ed.SelectAll(sf);

            if (psr.Status == PromptStatus.OK)
                return
                  new ObjectIdCollection(psr.Value.GetObjectIds());
            else
                return new ObjectIdCollection();
        }


        [CommandMethod("layer2block")]
        public void CreateBlock()
        {
            Document doc =
              Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            Transaction tr =
              db.TransactionManager.StartTransaction();
            using (tr)
            {
                // Get the block table from the drawing

                BlockTable bt =
                  (BlockTable)tr.GetObject(
                    db.BlockTableId,
                    OpenMode.ForRead
                  );

                // Check the block name, to see whether it's
                // already in use

                PromptStringOptions pso =
                  new PromptStringOptions("\nEntre com o Nome do Bloco: ");
                pso.AllowSpaces = true;

                // A variable for the block's name

                string blkName = "";

                do
                {
                    PromptResult pr = ed.GetString(pso);

                    // Just return if the user cancelled
                    // (will abort the transaction as we drop out of the using
                    // statement's scope)

                    if (pr.Status != PromptStatus.OK)
                        return;

                    try
                    {
                        // Validate the provided symbol table name

                        SymbolUtilityServices.ValidateSymbolName(
                          pr.StringResult,
                          false
                        );

                        // Only set the block name if it isn't in use

                        if (bt.Has(pr.StringResult))
                            ed.WriteMessage("\nEsse bloco já existe.");
                        else
                            blkName = pr.StringResult;
                    }
                    catch
                    {
                        // An exception has been thrown, indicating the
                        // name is invalid

                        ed.WriteMessage("\nNome do bloco Inválido.");
                    }

                } while (blkName == "");


                PromptResult pr1 = ed.GetString("\nEnter name of layer: ");

                ObjectIdCollection ents = GetEntitiesOnLayer(pr1.StringResult);

                // Create our new block table record...

                BlockTableRecord btr = new BlockTableRecord();

                // ... and set its properties

                btr.Name = blkName;

                // Add the new block to the block table

                bt.UpgradeOpen();
                ObjectId btrId = bt.Add(btr);
                tr.AddNewlyCreatedDBObject(btr, true);

                // Add some lines to the block to form a square
                // (the entities belong directly to the block)


                IdMapping mapping = new IdMapping();
                db.DeepCloneObjects(ents, btrId, mapping, false);


                // Add a block reference to the model space

                BlockTableRecord ms =
                  (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                BlockReference br =
                  new BlockReference(Point3d.Origin, btrId);

                ms.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                // Commit the transaction

                tr.Commit();

                // Report what we've done

                ed.WriteMessage(
                  "\nCreated block named \"{0}\" containing {1} entities.",
                  blkName, ents.Count
                );
            }
        }



    }


Mantive exatamente a mesma estrutura inclusive com a solução de utilizar a função GetEntitiesOnLayer que já existia antes.

Criei uma nova entrada do prompt para que o usuário entre com o nome do Layer onde estão os objetos e removi a parte que construía os objetos.

Feito isso, a coleção de objetos do Layer passa para uma varável chamada ents que é adicionada ao BlockTableRecord do bloco criado.

O único inconveniente dessa solução é que DeepCloneObjects faz um clone dos dos objetos selecionados e os associa ao bloco criado com um ponto de base.

A outra forma de fazer isso sem esta função de clonagem seria criar o bloco, incluir os objetos internamente ao bloco e depois colocar uma Block Reference do bloco no desenho com o ponto de base escolhido. Daria bem mais trabalho e para fazer isso teríamos que abrir e fechar o Transaction várias vezes porque a primeira você cria o bloco e para ele aparecer no banco de dados precisa que a Transaction do Banco de Dados (Data Base) seja atualizada. Existe o recurso do Commit da Transaction porém nas versões mais antigas do AutoCAD realizar esses processos sistematicamente causavam colisões e violações de execução até mesmo causando o fechamento do AutoCAD.

A melhor alternativa seria depois de criar o bloco excluir os objetos que estão no Layer mas não encontrei ainda uma solução para isso.

Finalizando, fica então mais um código de referência, espero ter ajudado.

Comentários

Postagens mais visitadas deste blog

Numeração Automática no AutoCAD

Sem dúvida esse é uma ferramenta única que fazia falta a tempos e foi introduzida recentemente no AutoCAD, na última década… Em 2013 tinha feito um programa para criar uma bolinhas de numeração automática usando o conceito de Leader eu fazia um controle dos números dos itens na mão mesmo, depois de um tempo resolvi fazer um menuzinho para controlar o conteúdo do número dos bullets, hoje isso não é mais necessário, existe um comando no próprio AutoCAD para isso e faz parte das Ferramentas Expressas do AutoCAD. Gosto de compartilhar ferramentas e dicas que tendem a ser menos conhecidas ou subutilizadas, mas ainda podem fornecer um impulso para sua produtividade e fluxo de trabalho e que eu mesmo me surpreendi quando as encontrei Hoje, quero apresentar outra ferramenta, a numeração automática. Como o nome indica, o comando Numeração automática permite que você adicione automaticamente um número às etiquetas ou texto em um desenho. Vou mostrar como a numeração automática pode ser usada par...

Alterar a cor de fundo do AutoCAD

Eu sou um adepto do fundo preto, tudo que eu posso mudo a cor do fundo para preto. Nas ultimas versões do AutoCAD tenho notado que não é mais o padrão o fundo preto absoluto, é um cinza escuro. As vezes gosto também de mudar a cor do Layout de branco para preto afinal de contas quando trabalhamos com penas e contraste no model space preto, ver um desenho no layout é impossível.  Você pode mudar sua cor de fundo do AutoCAD para a cor que quiser. Definindo cores personalizadas Primeiro, vá para o menu Opções (botão Aplicativo> Opções), selecione a guia Exibição e clique no botão Cores. Agora você deve ver a caixa de diálogo Cores da janela de desenho: Agora você pode atualizar as cores de qualquer elemento da interface. Isso incluí o plano de fundo em qualquer contexto (selecione Model e Layout). Você pode escolher qualquer uma das predefinições, ou você pode escolher a partir de todo o espectro (basta escolher a opção Selecionar Cor ...). Se você não gost...

Unindo blocos em AutoCAD utilizando .NET

Hoje me deparai com uma necessidade de unir blocos com propriedades então resolvi fazer um comando para realizar esses procedimento. A principio esse procedimento não é tão complexo de ser executado individualmente mas por outro lado gostaria também de analisar um pouco melhor as possibilidades de se manipular blocos utilizando o AutoCAD. Abaixo o código que utilizei: using Autodesk.AutoCAD.ApplicationServices ; using Autodesk.AutoCAD.DatabaseServices ; using Autodesk.AutoCAD.EditorInput ; using Autodesk.AutoCAD.Runtime ; using System.Linq ; // This line is not mandatory, but improves loading performances [assembly: CommandClass(typeof(Merging_AutoCAD_blocks.Comandos))] namespace Merging_AutoCAD_blocks { public class Comandos { /// <summary> /// Uni dois ou mais blocos em um unico bloco. /// </summary> [CommandMethod("MERGBLKS")] public static void UnindoBlocos () {...