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.
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:
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.
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.
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.
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
Postar um comentário