Тема: Сохранение листов в отдельный файл

Здравствуйте!

Подскажите пожалуйста как сделать автоматизированное сохранения отдельных листов (не в модели, а иммено листов) в отдельный файл-чертеж использую AutoCAD 2010?
Т.е. есть один dwg-чертеж в нем например 10 листов (не в моделе) их требуется сохранить в отдельный файл, т.о на выходе должны быть получены 10 файлов, т.е на каждый лист приходится по одному файлу-чертежу.

В какую сторону копать и есть ли готовые родные AutoCAD API для выполнения такой задачи?

Re: Сохранение листов в отдельный файл

Покопался в AutoCAD 2010  и нашел в нем такую функцию EXPORTLAYOUT она позволяет текущий лист сохранить в отдельный файл.

Пока удалось получить имя текущего Лист, в качестве которого будет исползоваться имя файла, теперь собственно главный момент остался как вызвать эту функцию EXPORTLAYOUT для сохранения листа в отдельный файл?

Код:

        [CommandMethod("GRF", "SaveLayouts", "MyCommandLocal", CommandFlags.Modal)]
        public static void SaveLayouts() {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) {
                LayoutManager acLayoutManager = LayoutManager.Current;

                for (Int32 i = 0; i < acLayoutManager.LayoutCount; i++) {
                    Layout acLayout = acTrans.GetObject(acLayoutManager.GetLayoutId(acLayoutManager.CurrentLayout), OpenMode.ForRead) as Layout;
                    acDoc.Editor.WriteMessage("\nCurrent lyaout: " + acLayout.LayoutName);
                    
                    String fileName = acLayout.LayoutName;
                }
            }
            // Put your command code here
        }

Re: Сохранение листов в отдельный файл

Думаю можно сделать примерно по следующему алгоритму:
1) Открыть нужный файл.
2) Запустить цикл по листам. Внутри цикла запоминает имя листа, сохраняем файл со названием листа функцией saveas. Далее открываем файл функцией readdwgfile, далее удаляем все листы не равные названию файла. И так пробежаться по всем листам.
както так вообщем, сам такую задачу не решал, это то что в голову первое пришло, может Александр Ривилис что-то более грамотное предложит.

Re: Сохранение листов в отдельный файл

Еще как вариант, если такое возможно:
1. Программного вызвать функцию EXPORTLAYOUT
2. Передать ей имя файла для сохранения в стандартном диалоговом окне (который как-то надо получить)
3. Сохранить.

Общий вопрос как программно вызвать ту или иную функцию, например все туже EXPORTLAYOUT?
Пробывал использовать объект PromptResult, но он принимает ввод, а мне нужно подминить ввод, т.е. сделать демонстрацию ввода, но без участия пользователя.

Re: Сохранение листов в отдельный файл

Вообще из всех возможных способов решения задачи программный вызов команды самый кривой вариант. Если что программный вызов команды можно делать через sendcommand.

Re: Сохранение листов в отдельный файл

Владимир Петров пишет:

Думаю можно сделать примерно по следующему алгоритму:

1) Открыть нужный файл.

2) Запустить цикл по листам. Внутри цикла запоминает имя листа, сохраняем файл со названием листа функцией saveas. Далее открываем файл функцией readdwgfile, далее удаляем все листы не равные названию файла. И так пробежаться по всем листам.

както так вообщем, сам такую задачу не решал, это то что в голову первое пришло, может Александр Ривилис что-то более грамотное предложит.

Не самый оптимальный в плане быстродействия, но IMHO самый простой в плане реализации.

Антон пишет:

Общий вопрос как программно вызвать ту или иную функцию, например все туже EXPORTLAYOUT?

Не функцию, а команду - изучай терминологию AutoCAD. Один из вариантов описан здесь: https://www.caduser.ru/forum/post262203.html#p262203

Re: Сохранение листов в отдельный файл

Вы правы команду, учту терминологию AutoCAD :)

Александр Ривилис пишет:

Не самый оптимальный в плане быстродействия, но IMHO самый простой в плане реализации.

Если я правильно понимаю, то при удалении листа, в пространстве модели все равно остаются объекты отраженные в листе?

Т.е. такой вариант не очень подходит, т.к. лист останется один, а в модели огрыхзки от удаленных листов.

Re: Сохранение листов в отдельный файл

Я тогда не понял чего ты добиваешься. Если тебе не нужны примитивы в пространстве модели, а нужны только те, которые были нарисованы в пространстве листа, то удали всё в пространстве модели.

Re: Сохранение листов в отдельный файл

Александр Ривилис пишет:

Я тогда не понял чего ты добиваешься. Если тебе не нужны примитивы в пространстве модели, а нужны только те, которые были нарисованы в пространстве листа, то удали всё в пространстве модели.

Прощу прощения, если не корректно объяснил суть проблемы.
1. Требуется разбить один чертеж состоящий из несколько листов на отдельные файлы.
2. Сейчас это делается путь использования новой команды AutoCAD 2010 EXPORTLAYOUT, эта команда сохраняет активный лист в новый файл, причем сохраняет в пространство модели. В итоге получается в новом файле сохранены объекты листа, других объектов нет.
3. Требуется для каждого листа вызвать команду EXPORTLAYOUT и сохранить в отдельный файл.
4. В AIP .NET AutoCAD я не нашел как вызвать эту команду и передать ее в качестве параметра имя листа для файла. Частично получилось за счет использования SendStringToExecute.

[CommandMethod("GRF", "SaveLayouts", "MyCommandLocal", CommandFlags.Modal)]
        public static void SaveLayouts() {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) {
                LayoutManager acLayoutMgr = LayoutManager.Current;
                Layout acLayout = acTrans.GetObject(acLayoutMgr.GetLayoutId(acLayoutMgr.CurrentLayout), OpenMode.ForRead) as Layout;

                String filename = @"D:\" + acLayout.LayoutName;
                // Output the name of the current layout and its device
                acDoc.Editor.WriteMessage("\nПоптыка сохранить лист: " + acLayout.LayoutName);
                acDoc.SendStringToExecute("._FILEDIA 0 ", true, false, true);
                acDoc.SendStringToExecute("._EXPORTLAYOUT " + filename, true, false, false);
                //acDoc.SendStringToExecute("._EXPORTLAYOUT ", true, false, false);                
                //acDoc.SendStringToExecute("._FILEDIA 1 ", true, false, true);
            }
        }

При использовании этого кода есть один побочный эффект, а имменно, когда выполянется код, то AutoCAD показывает окно для ввода пусткой команды, если в ней ввести просто ввод тогда отрабатывает сохраняет лист куда надо.

Я так понял что " " пробел в конце вызова команды означает ее выполнение, хотелось бы вызвать команду EXPORTLAYOUT с параметром места сохранения листа в отдельный файл, но либо команда EXPORTLAYOUT не иммет параметров (собственно для этого изменяю режим FILEDIA), либо я что-то делаю не так.

(изменено: Александр Ривилис, 11 марта 2010г. 14:37:38)

Re: Сохранение листов в отдельный файл

Я посмотрел как работает команда EXPORTLAYOUT. Там несколько иначе. Все примитивы, которые попадают в текущий LAYOUT (т.е. и те которые нарисованы в нем, и те которые туда попадают из пространства модели) попадают в итоговом чертеже в пространство модели. Чтобы не мудрить воспользуйся этой командой, но не через  SendStringToExecute, т.к. она выполняется ассинхронно, а через https://www.caduser.ru/forum/post262203.html#p262203

P.S.: Желательно в пути доступа к имени файла заменть все "\\" на "/"

Re: Сохранение листов в отдельный файл

Александр Ривилис пишет:

Чтобы не мудрить воспользуйся этой командой, но не через SendStringToExecute, т.к. она выполняется ассинхронно, а через https://www.caduser.ru/forum/post262203.html#p262203

Большое спасибо, помогло.
Еще вопрос как перебать все Листы?
В API вижу только LayoutManager и Layout, у LayoutManager есть свойство LayoutCount, перебрать его спомощью foreach не получается так он не поддерживает нужные для этого интерфейсы.

Через что их можно перебрать?

(изменено: Александр Ривилис, 11 марта 2010г. 17:29:31)

Re: Сохранение листов в отдельный файл

А поиск на что? https://www.caduser.ru/forum/post151959.html#p151959
И скорее всего у тебя сразу появится вопрос "как переключиться на нужный LAYOUT". Это сюда: https://www.caduser.ru/forum/post149815.html#p149815

Re: Сохранение листов в отдельный файл

Александр Ривилис пишет:

А поиск на что? https://www.caduser.ru/forum/post151959.html#p151959
И скорее всего у тебя сразу появится вопрос "как переключиться на нужный LAYOUT". Это сюда: https://www.caduser.ru/forum/post149815.html#p149815

Огромное спасибо, поиском не успел воспользоваться :oops:

Re: Сохранение листов в отдельный файл

По первой ссылки получилось перебрать все Листы, вот по второй сслыки не совсем понято что происходит в коде для установки текущего Листа.

В своем коде делаю так:

        [CommandMethod("GRF", "SaveLayouts", "MyCommandLocal", CommandFlags.Modal)]
        public static void SaveLayouts() {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Editor acEditor = acDoc.Editor;
            Database acCurDb = acDoc.Database;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) {
                DBDictionary layoutDict = (DBDictionary)acTrans.GetObject(acCurDb.LayoutDictionaryId, OpenMode.ForWrite);

                Int32 iLayout = 0;
                foreach (DictionaryEntry id in layoutDict) {
                    
                    // При второй итерайии вылетает ошибка на этой строчке....
                    // С сообщением: Операция является недопустимой из-за текущего состояния объекта.
                    //
                    // Режим поменял на OpenMode.ForWrite но эффекта нет...
                    Layout ltr = (Layout)acTrans.GetObject((ObjectId)id.Value, OpenMode.ForWrite);

                    if (ltr.LayoutName.ToLower() != "model") {
                        acEditor.WriteMessage("\nLayout N{0} = {1}", ++iLayout, ltr.LayoutName);
                        LayoutManager.Current.CurrentLayout = ltr.LayoutName;
                        
                        // При первой итерации происходит установка текущего Листа
                        acTrans.Commit();
                    }
                }
            }
        }

При просмотре свойств объекта Layout вижу что есть свойство TabSelected предполагаю что оно отвечает за то, является Лист (или точнее вкладка) выбранной или нет. Пробую ему задать значение True, но эффекта никакого.

(изменено: Александр Ривилис, 12 марта 2010г. 13:13:13)

Re: Сохранение листов в отдельный файл

Сейчас нет времени детально проверять, но IMHO ошибка в том, что ты пытаешься переключить LAYOUT внутри транзакции. Сначала получи все имена LAYOUT, а потом в цикле переключайся на очередной. И еще одно замечание. Зачем ты открываешь для записи (OpenMode.ForWrite) если не меняешь? Открывай для чтения (OpenMode.ForRead)

(изменено: Антон, 12 марта 2010г. 16:34:36)

Re: Сохранение листов в отдельный файл

Александр Ривилис пишет:

Сейчас нет времени детально проверять, но IMHO ошибка в том, что ты пытаешься переключить LAYOUT внутри транзакции

Вы абсолютно правы, переделал с учетом Ваших замечаний в итоге получился такой код:

        [CommandMethod("GRF", "ExportL", "MyCommandLocal", CommandFlags.Modal)]
        public static void ExportLayouts() {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Editor acEditor = acDoc.Editor;
            Database acCurDb = acDoc.Database;
            String[] layouts = null;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) {
                DBDictionary layoutDict = (DBDictionary)acTrans.GetObject(acCurDb.LayoutDictionaryId, OpenMode.ForRead);

                Int32 iLayout = 0;
                layouts = new string[layoutDict.Count];

                foreach (DictionaryEntry id in layoutDict) {
                    Layout ltr = (Layout)acTrans.GetObject((ObjectId)id.Value, OpenMode.ForRead);
                    if (ltr.LayoutName.ToLower() != "model") {
                        layouts[++iLayout] = ltr.LayoutName;
                    }
                }
            }

            LayoutManager acLayoutManager = null;
            foreach (String layout in layouts) {

                if (layout != null) {
                    acLayoutManager = LayoutManager.Current;
                    acLayoutManager.CurrentLayout = layout;
                    //Проверка на корректность имен файла опущена 
                    CommandLine.Export(@"D:\" + layout);
                }
            }        }

(изменено: Александр Ривилис, 12 марта 2010г. 16:47:30)

Re: Сохранение листов в отдельный файл

Интуиция однако! smile
P.S.: Проверка  if (ltr.LayoutName.ToLower() != "model")  мягко говоря не корректная. Какое имя будет в локализованной версии AutoCAD?

(изменено: Андрей Бушман, 12 марта 2010г. 16:59:06)

Re: Сохранение листов в отдельный файл

2 Антон

А если попробовать так (для .Net Framework 3.5 SP1):

        [CommandMethod("GRF", "ExportL", "MyCommandLocal", CommandFlags.Modal)]
        public static void ExportLayouts()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Editor acEditor = acDoc.Editor;
            Database acCurDb = acDoc.Database;
            String[] layouts = null;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                DBDictionary layoutDict = (DBDictionary)acTrans.GetObject(acCurDb.LayoutDictionaryId, OpenMode.ForRead);

                layoutDict.Cast<DictionaryEntry>().Select(n => (Layout)acTrans.GetObject((ObjectId)n.Value, OpenMode.ForRead))
                    .Where(n => n.LayoutName.ToLower() != "model").Select(n => { if (n != null) { LayoutManager.Current.CurrentLayout = n.LayoutName; 
                        CommandLine.Export(Path.Combine("D:", n.LayoutName)); } return n;}).ToArray();
            }            
        }

так гораздо компактнее имхо. У меня нет твоего метода Export, поэтому код я не тестировал.

(изменено: Антон, 15 марта 2010г. 10:08:45)

Re: Сохранение листов в отдельный файл

Андрей Бушман пишет:

А если попробовать так (для .Net Framework 3.5 SP1):

Согласен так, компактнее, спасибо :)

Re: Сохранение листов в отдельный файл

Александр Ривилис пишет:

Интуиция однако! 
P.S.: Проверка if (ltr.LayoutName.ToLower() != "model") мягко говоря не корректная. Какое имя будет в локализованной версии AutoCAD?

Написал так, потому что в русской версии AutoCAD 2010 модель иммено так как "model" и зашита, в отладчике видел.

(изменено: Melx, 7 ноября 2012г. 17:16:44)

Re: Сохранение листов в отдельный файл

Добрый день! Помогите разобраться с представленным выше кодом. За который отдельное спасибо.

Вопросы следующие:
1. Возможно обращаться к коллекции листов через ID, а не имя (через IList<T>)? model всегда имеет ID=0?

2. Как заставить принимать автокад значения имени файла (полного) по умолчанию? Иными словами, как мне сымитировать пользовательское нажатие enter при вызове exportlayout?
3. Иногда при использовании ExportLayout вылетает ошибка, с вылетом автокада, причин ошибки выявить мне пока не удалось. При этом нужный файл все же создается. Вопрос возможно заставить акад писать лог работы какой-либо своей команды во внешний файл? И как это сделать, если возможно?

ExportLayout (в autocad 2011) переносит таблицы с разрывами целиком, включая те области, которые в лист не попадают. Это просто в копилку сведений о работе ExportLayout...

Буду благодарен за помощь.