Pular para o conteúdo principal

Operando com Imagens Georreferenciadas no AutoCAD - Ortofotos

A coisa mais desagradável para quem trabalha com documentos em DWG com ortofotos ( fotos aéreas georreferenciadas) é quando se recebe o documento e a ortofoto não é carregada.



Uma linha de transmissão onde a plotagem da estruturas é feita em um documento combinado de planta e perfil. Na área da planta é feito pela topografia um serviço de recorte e renderização das imagens em formato de ortofoto na região do desenho.



Como a linha de transmissão a projeção é feita sempre linear na planta observando os vértices uma mesma ortofoto pode ser representada várias vezes numa mesma folha em um enjanelamento diferente.


Tratamento de Ortofotos no AutoCAD - EXTERNALREFERENCES

As ortofotos no AutoCAD são tratadas como referências a objetos externos. Isso é bom porque cada ortofoto pode ter de poucos kb até Gb de tamanho. Se for parte integrante do DWG poderia deixa-lo grande de mais para ser manipulado.

Cada projeção no documento funciona como uma imagem projetada em uma janela interia recortada pela indicação do usuário. 

Esse janelamento está disponível do complemento do AutoCAD conhecido como Raster. Para os usuários que não possem Raster é permitido realizar a edição apenas das opções da referência externa através do comando EXTERNALREFERENCES.


O problema

A topografia fez com o AutoCAD Civil e coloca os arquivos de imagem em uma pasta dentro do sistema deles. Dessa pasta são associadas as linhas de um mesmo lote. Geralmente dezenas de linhas compartilham as mesmas ortofotos.
Então assim nós temos centenas de arquivos de imagem georreferenciadas, com outras centenas de documentos DWG fazendo referência a dez documentos de imagem por vez.

Um caos completo. Por questões de organização não é aceitável colocar todos os documentos de ortofotos na mesma pasta que os documentos DWG mesmo isso sendo uma solução paliativa uma vez que se o AutoCAD não encontra a ortofoto no destino especificado no Saved Path do External References ele busca na pasta onde está o DWG.

O ideal é ter um comando que possa realizar sistematicamente a associação dos arquivos DWG com as ortofotos colocando-os num lugar único separado das demais. Além disso separar apenas as ortofotos que são utilizadas.

O Comando

A solução para o problema foi fazer um comando novo dedicado para essa finalidade.
Na verdade fiz alguns comandos personalizados para realizar essa tarefa.

Comando EXTREF_LIST_IN_FILES

Este comando foi feito para listar os arquivos que estão sendo associados com os documentos. O comando utiliza um OpenFileDialog do Windows para selecionar os documentos que serão analisados.

Cada documento a ser analisado é aberto no modo leitura e o código "lê" todos os objetos referenciados e os que forem imagem são listados em duas listas como um string contínuo.


[CommandMethod("EXTERNALREFERENCES_LIST_IN_FILES", CommandFlags.Modal)]
public void externalreferences_list_in_files() // This method can have any name
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    
    try
    {

    //Selecionando os arquivos para listar as referências
    System.Windows.Forms.OpenFileDialog openFileDialogDWGs = new System.Windows.Forms.OpenFileDialog();
    openFileDialogDWGs.Multiselect = true;
    openFileDialogDWGs.Filter = "dwg files (*.dwg)|*.dwg|All files (*.*)|*.*";
    openFileDialogDWGs.FilterIndex = 1;
    openFileDialogDWGs.RestoreDirectory = true;
    openFileDialogDWGs.Title = "Selecione os arquivos que serão analisados";


    //Validação dos arquivos abertos
    if (openFileDialogDWGs.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
    if (openFileDialogDWGs.FileNames.Length < 1) return;

   
        //Global
        String txtOuput = "";
        String txtOuputReferenceList = "";
        
        //Para cada arquivo, faça:
        foreach (String dwgfile in openFileDialogDWGs.FileNames)
        {
            txtOuput += "Arquivo\t" + Path.GetFileName(dwgfile) + "\r\n";
            using (Database db = new Database(false, true))
            {
                db.ReadDwgFile(dwgfile, FileShare.ReadWrite, false, String.Empty);
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    ObjectId dictId = RasterImageDef.GetImageDictionary(db);
                    if (!dictId.IsNull)
                    {
                        DBDictionary dict1 = (DBDictionary)tr.GetObject(dictId, OpenMode.ForRead);
                        foreach (DBDictionaryEntry entry in dict1)
                        {
                            ed.WriteMessage(".");

                            if (entry.GetType() == typeof(UnderlayDefinition))
                            {
                                UnderlayDefinition def = (UnderlayDefinition)tr.GetObject(entry.Value, OpenMode.ForRead);
                            }
                            else
                            {
                                RasterImageDef img = (RasterImageDef)tr.GetObject(entry.Value, OpenMode.ForRead);
                                txtOuput += Path.GetFileName(img.SourceFileName) + "\t" + img.SourceFileName + "\t" + img.ActiveFileName + "\r\n";

                                //Lista apenas os nomes dos documentos
                                if (!txtOuputReferenceList.Contains(Path.GetFileName(img.SourceFileName)))
                                {
                                    txtOuputReferenceList += Path.GetFileName(img.SourceFileName) + "\r\n";
                                }

                            }
                        }
                    }
                }
            }
        }

        WindowsForms_ReportOutput frm = new WindowsForms_ReportOutput();
        frm.txt.Text = txtOuput;
        frm.Show();

        WindowsForms_ReportOutput frm1 = new WindowsForms_ReportOutput();
        frm1.txt.Text = txtOuputReferenceList;
        frm1.Show();


    }
    catch (Autodesk.AutoCAD.Runtime.Exception ex)
    {
        ed.WriteMessage(ex.Message.ToString());
    }            
}


Um dos strings, txtOutput, funciona como um relatório de saída onde se reporta todos os arquivos o caminho do arquivo e o nome e de qual arquivo DWG ele foi listado.

No outro string, txtOuputReferenceList, são listados só os nomes dos arquivos de forma que é possível saber se todos os arquivos que estão numa determinada pasta de ortofotos realmente pertencem a linha.

Esse comando usa a estrutura de tratamento try(){}catch(){} que toma um erro e o coloca sem dar erro no AutoCAD. Isso é útil para depuração e para aplicações mais profissionais porque você não "trava" o AutoCAD e você perde o desenho se houver algum erro.

O Comando de Readequação

Além de um comando para analise fiz também um comando para realmente ajustar as Ortofotos associadas com os desenhos e ainda separa-las numa pasta.


[CommandMethod("EXTERNALREFERENCES_REDEFINE_IN_FILES")]
        public void externalreferences_redefine_in_files()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            try
            {

                ed.WriteMessage("Selecionar os arquivos DWG que serão alterados");
                //Selecionando os arquivos para listar as referências
                System.Windows.Forms.OpenFileDialog openFileDialogDWGs = new System.Windows.Forms.OpenFileDialog();
                openFileDialogDWGs.Multiselect = true;
                openFileDialogDWGs.Filter = "dwg files (*.dwg)|*.dwg|All files (*.*)|*.*";
                openFileDialogDWGs.FilterIndex = 1;
                openFileDialogDWGs.RestoreDirectory = true;
                openFileDialogDWGs.Title = "Selecionar os arquivos DWG que serão alterados";
                //Validação dos arquivos abertos
                if (openFileDialogDWGs.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
                if (openFileDialogDWGs.FileNames.Length < 1) return;
                

                
                //Selecione a pasta onde estão os arquivos corretos
                ed.WriteMessage("Selecionar a pasta onde estão as Ortofotos");
                System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1;
                folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog();
                folderBrowserDialog1.Tag = "Pasta das ortofotos";
                folderBrowserDialog1.Description = "Selecionar a pasta onde ficarão as ortofotos";
                //Validação
                if (folderBrowserDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
                if (folderBrowserDialog1.SelectedPath == null) return;

                

                //Selecione a pasta onde estão os arquivos corretos
                ed.WriteMessage("Selecionar a pasta onde ficarão os arquivos DWG corrigidos");
                System.Windows.Forms.FolderBrowserDialog folderBrowserDialog2;
                folderBrowserDialog2 = new System.Windows.Forms.FolderBrowserDialog();
                folderBrowserDialog2.Tag = "Pasta de destino dos DWG corrigidos";
                folderBrowserDialog2.Description = "Selecionar a pasta onde ficarão os arquivos DWG corrigidos";
                //Validação
                if (folderBrowserDialog2.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
                if (folderBrowserDialog2.SelectedPath == null) return;


                //Selecione a pasta onde estão os arquivos corretos
                ed.WriteMessage("Selecionar a pasta onde estão as Ortofotos corrigidas");
                System.Windows.Forms.FolderBrowserDialog folderBrowserDialog3;
                folderBrowserDialog3 = new System.Windows.Forms.FolderBrowserDialog();
                folderBrowserDialog3.Tag = "Selecionar a pasta onde estão as Ortofotos corrigidas";
                folderBrowserDialog3.Description = "Selecionar a pasta onde estão as Ortofotos corrigidas";
                //Validação
                if (folderBrowserDialog3.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
                if (folderBrowserDialog3.SelectedPath == null) return;



                //Global
                String txtOuput = "";

                //Para cada arquivo, faça:
                foreach (String dwgfile in openFileDialogDWGs.FileNames)
                {
                    txtOuput += "\n ----------------------------------------------------- \n Processando arquivo " + Path.GetFileName(dwgfile) + "\r\n";
                    using (Database db = new Database(false, true))
                    {
                        db.ReadDwgFile(dwgfile, FileShare.ReadWrite, false, String.Empty);
                        using (Transaction tr = db.TransactionManager.StartTransaction())
                        {
                            ObjectId dictId = RasterImageDef.GetImageDictionary(db);
                            if (!dictId.IsNull)
                            {
                                DBDictionary dict1 = (DBDictionary)tr.GetObject(dictId, OpenMode.ForWrite);
                                foreach (DBDictionaryEntry entry in dict1)
                                {

                                    if (entry.GetType() == typeof(UnderlayDefinition))
                                    {
                                        UnderlayDefinition def = (UnderlayDefinition)tr.GetObject(entry.Value, OpenMode.ForWrite);
                                    }
                                    else
                                    {
                                        RasterImageDef img = (RasterImageDef)tr.GetObject(entry.Value, OpenMode.ForWrite);
                                        txtOuput += "Localizado referência a " + Path.GetFileName(img.SourceFileName) + "\t" + img.SourceFileName + "\t" + img.ActiveFileName + "\r\n";

                                        if (img.SourceFileName != Path.Combine(folderBrowserDialog1.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName)))
                                        {
                                            try
                                            {

                                                if (!File.Exists(Path.Combine(folderBrowserDialog3.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName))))
                                                {
                                                    if (File.Exists(Path.Combine(folderBrowserDialog1.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName))))
                                                    {
                                                        File.Copy(Path.Combine(folderBrowserDialog1.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName)),
                                                            Path.Combine(folderBrowserDialog3.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName)));
                                                    }
                                                    else
                                                    {
                                                        txtOuput += "Erro! O arquivo " + Path.GetFileName(img.SourceFileName) + "não existe na pasta " + folderBrowserDialog3.SelectedPath.ToString() + ". A pasta"
                                                                   + " seá modificada para a pasta de saida mas o arquivo não foi localizado\r\n";
                                                    }
                                                }

                                                
                                                txtOuput += "Modificando a pasta para " + Path.Combine(folderBrowserDialog3.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName)) + "\r\n";
                                                img.SourceFileName = Path.Combine(folderBrowserDialog3.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName));
                                                img.ActiveFileName = Path.Combine(folderBrowserDialog3.SelectedPath.ToString(), Path.GetFileName(img.SourceFileName));
                                                img.Load();
                                               


                                              
                                                ed.WriteMessage(".");
                                            }
                                            catch (System.Exception ex)
                                            {
                                                if (!File.Exists(Path.Combine(folderBrowserDialog1.SelectedPath.ToString())))
                                                {
                                                    txtOuput += "!!!!!! ERRO !!!!!!  O arquivo " + Path.Combine(folderBrowserDialog1.SelectedPath.ToString()) + " não existe na pasta!\r\n";
                                                }
                                                else
                                                {
                                                    txtOuput += "!!!!!! ERRO !!!!!! Ocorreu um erro geral \r\n " + ex.Message.ToString() + "\r\n";
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            tr.Commit();
                        }

                        db.SaveAs(Path.Combine(folderBrowserDialog2.SelectedPath, Path.GetFileName(dwgfile)), DwgVersion.Newest);
                    }
                }

                WindowsForms_ReportOutput frm = new WindowsForms_ReportOutput();
                frm.txt.Text = txtOuput;
                frm.Show();


            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                ed.WriteMessage(ex.Message.ToString());
            }
        }


Basicamente o que a função faz é abrir cada documento individualmente, verificar as ortofotos associadas como Objeto Image Raster/External Reference e renomear o seu caminho de pasta para um caminho previamente definido.

Se a imagem existe no caminho especificado, esse arquivo de imagem é transferido para o caminho de saída caso contrário um log de eventos mostra um erro dizendo que o arquivo não foi localizado pelo programa.

Dessa forma fica fácil identificar quais arquivos não foram corrigidos.


Para fazer o Download da Ferramenta já compilada clique aqui. Se quiser o código fonte clique aqui.

Espero ter ajudado mais uma vez com esse comando personalizado.

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 () {...