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() { var doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; var db = doc.Database; var ed = doc.Editor; // Obtém o nome do primeiro bloco para mesclar var pr = ed.GetString("\nEnter name of first block"); if (pr.Status != PromptStatus.OK) return; string first = pr.StringResult.ToUpper(); using (var tr = doc.TransactionManager.StartTransaction()) { var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); // Verifique se o primeiro bloco existe if (bt.Has(first)) { // Obtém o nome do segundo bloco para mesclar pr = ed.GetString("\nEnter name of second block"); if (pr.Status != PromptStatus.OK) return; string second = pr.StringResult.ToUpper(); // Verifique se o segundo bloco existe if (bt.Has(second)) { // Obtém o nome do novo bloco pr = ed.GetString("\nEnter name for new block"); if (pr.Status != PromptStatus.OK) return; string merged = pr.StringResult.ToUpper(); // Verifique se o novo bloco ainda não existe if (!bt.Has(merged)) { // Precisamos pegar as coleções dois dois blocos var ids = new ObjectIdCollection(); // Open the two blocks to be merged var btr1 = tr.GetObject(bt[first], OpenMode.ForRead) as BlockTableRecord; var btr2 = tr.GetObject(bt[second], OpenMode.ForRead) as BlockTableRecord; // Use o LINQ para obter IEnumerable <ObjectId> para os blocos var en1 = btr1.Cast<ObjectId>(); var en2 = btr2.Cast<ObjectId>(); // Adicione o conteúdo completo à nova coleção for (int i = 0; i < en1.ToArray<ObjectId>().Count(); i++ ) { ids.Add(en1.ToArray<ObjectId>()[i]); } for (int i = 0; i < en2.ToArray<ObjectId>().Count(); i++) { ids.Add(en2.ToArray<ObjectId>()[0]); } // Create a new block table record for our merged block var btr = new BlockTableRecord(); btr.Name = merged; //Adicione-o à tabela de blocos e à transação bt.UpgradeOpen(); var btrId = bt.Add(btr); tr.AddNewlyCreatedDBObject(btr, true); // clona o conteudo var idMap = new IdMapping(); db.DeepCloneObjects(ids, btrId, idMap, false); ed.WriteMessage("\nBloco \"{0}\" criado com sucesso!.", merged); } else { ed.WriteMessage( "\nO desenho já tem o bloco com o nome \"{0}\".", merged ); } } else { ed.WriteMessage("\nBloco \"{0}\" não encontrado.", second); } } else { ed.WriteMessage("\nBloco \"{0}\" não encontrado.", first); } // executa a Transferência de Ações tr.Commit(); } } } }
Basicamente o que o código faz é reunir dois blocos e seus atributos visíveis e invisíveis em um único bloco. Para isso utilizamos as coleções do Windows tipo Linq.
Outra coisa que utilizamos é o DeepCloneObjects(). Podemos usar DeepCloneObjects() aqui porque estamos no mesmo desenho: se quisermos mover o novo bloco entre os bancos de dados, por algum motivo, usaremos WblockCloneObjects () seguido de Insert(). Essa última abordagem garante que todas as referências sejam seguidas e o conteúdo copiado também: algo que não precisamos ao trabalhar no mesmo banco de dados.
Aqui está o comando MB trabalhando com alguns blocos complexos com varias linhas e unindo-os em um único objeto:
Aqui está o comando MB trabalhando com alguns blocos complexos com varias linhas e unindo-os em um único objeto:
Espero ter ajudado!
Comentários
Postar um comentário