Клонирование или копирование листа (layout)

Автор Тема: Клонирование или копирование листа (layout)  (Прочитано 13780 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн NurGeoАвтор темы

  • ADN OPEN
  • Сообщений: 31
  • Карма: 1
Всем привет.
После 4-5 часов тщетных попыток, я сдался. Как сделать полную копию существующего листа? Метод CloneLayout и CopyLayout добавляют лист, но такое ощущение что оба листа ссылаются на один и тот же BlockTableRecord, по крайней мере, если после создания редактировать в одном листе атрибут, то на втором он точно такой же. Пытался клонировать и запись блока, но(((, в общем ничего.

Код - vb.net [Выбрать]
  1. Sub CloneLayout(CurrentLayoutName As String, NewName As String)
  2.  
  3.         Using AcTr As Transaction = AcDb.TransactionManager.StartTransaction
  4.  
  5.             Dim lytDict As DBDictionary = AcTr.GetObject(AcDb.LayoutDictionaryId, OpenMode.ForRead)
  6.             'Смортим есть ли такой лист уже в чертеже
  7.             If lytDict.Contains(NewName) Then
  8.                 AcEd.WriteMessage(vbLf & "Лист " & NewName & " уже есть в чертеже. ")
  9.                 Return
  10.             End If
  11.  
  12.             'Считываем текущий лист
  13.             Dim LytMgr As LayoutManager = LayoutManager.Current()
  14.             Dim CurLayoutId As ObjectId = LytMgr.GetLayoutId(CurrentLayoutName)
  15.             Dim CurrLayout As Layout = AcTr.GetObject(CurLayoutId, OpenMode.ForRead)
  16.             Dim CurTabOrder As Short = CurrLayout.TabOrder
  17.             'Создаем новый лист
  18.             LytMgr.CloneLayout(CurrentLayoutName, NewName, CurTabOrder + 1)
  19.             Dim NewlayoutID As ObjectId = LytMgr.GetLayoutId(NewName)
  20.             Dim Newlayout As Layout = AcTr.GetObject(NewlayoutID, OpenMode.ForRead)            
  21.  
  22.             AcTr.Commit()
  23.         End Using
  24.     End Sub

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus


Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
NurGeo, в общем все ссылки указывают только на одну строку, которая по идее вам нужна:
Код - vb.net [Выбрать]
  1. newLayout.CopyFrom(layout)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Как сделать полную копию существующего листа?
Знать бы еще что ты понимаешь под полной копией.
Метод CloneLayout и CopyLayout добавляют лист, но такое ощущение что оба листа ссылаются на один и тот же BlockTableRecord, по крайней мере, если после создания редактировать в одном листе атрибут, то на втором он точно такой же.
Какой BlockTableRecord? Какой атрибут? ;)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
У меня все работает, лист создается, наполнение листа копируется.

ЗЫ.
Тут проверок и обработок ошибок не хватает, но как идея пойдет

Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. using App = Autodesk.AutoCAD.ApplicationServices;
  8. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  9. using Db = Autodesk.AutoCAD.DatabaseServices;
  10. using Ed = Autodesk.AutoCAD.EditorInput;
  11. using Gem = Autodesk.AutoCAD.Geometry;
  12. using Rtm = Autodesk.AutoCAD.Runtime;
  13.  
  14. [assembly: Rtm.CommandClass(typeof(tmp_cloneLayout.Commands))]
  15.  
  16. namespace tmp_cloneLayout
  17. {
  18.     public class Commands
  19.     {
  20.         [Rtm.CommandMethod("CloneLayout")]
  21.         static public void AddLine()
  22.         {
  23.             CloneLayout("A4", "A4_001");
  24.         }
  25.  
  26.         private static void CloneLayout(string CurrentLayoutName, string NewName)
  27.         {
  28.             // Получение текущего документа и базы данных
  29.             App.Document acDoc = App.Application.DocumentManager.MdiActiveDocument;
  30.             Db.Database acCurDb = acDoc.Database;
  31.             Ed.Editor acEd = acDoc.Editor;
  32.             // старт транзакции
  33.             using (Db.Transaction acTrans = acCurDb.TransactionManager.StartOpenCloseTransaction())
  34.             {
  35.  
  36.                 Db.LayoutManager LytMgr = Db.LayoutManager.Current;
  37.                 Db.ObjectId newLayoutId = LytMgr.CreateLayout(NewName);
  38.                 Db.Layout newLayout = acTrans.GetObject(newLayoutId, Db.OpenMode.ForWrite) as Db.Layout;
  39.                 if (newLayout == null)
  40.                 {
  41.                     acEd.WriteMessage("\nError 1");
  42.                     return;
  43.                 }        
  44.                
  45.                 Db.ObjectId CurLayoutId = LytMgr.GetLayoutId(CurrentLayoutName);
  46.                 Db.Layout CurrLayout = acTrans.GetObject(CurLayoutId, Db.OpenMode.ForRead) as Db.Layout;
  47.                 if (CurrLayout == null)
  48.                 {
  49.                     acEd.WriteMessage("\nError 2");
  50.                     return;
  51.                 }
  52.  
  53.                 newLayout.CopyFrom(CurrLayout);
  54.  
  55.                 Db.BlockTableRecord blkTableRec = acTrans.GetObject(CurrLayout.BlockTableRecordId, Db.OpenMode.ForRead) as Db.BlockTableRecord;
  56.                 if (blkTableRec == null)
  57.                 {
  58.                     acEd.WriteMessage("\nError 3");
  59.                     return;
  60.                 }
  61.                 Db.ObjectIdCollection objIdCol =new Db.ObjectIdCollection();
  62.                 foreach (Db.ObjectId objId in blkTableRec)
  63.                 {
  64.                     objIdCol.Add(objId);
  65.                 }
  66.  
  67.                 Db.IdMapping idMap = new Db.IdMapping();
  68.                 acCurDb.DeepCloneObjects(objIdCol,
  69.                     newLayout.BlockTableRecordId,
  70.                     idMap,
  71.                     false);
  72.  
  73.                 acDoc.Editor.Regen();
  74.                 acTrans.Commit();
  75.             }
  76.         }
  77.     }
  78. }
  79.  

Оффлайн NurGeoАвтор темы

  • ADN OPEN
  • Сообщений: 31
  • Карма: 1
В общем у меня два кода теперь. Один  CloneLayout и второй Copylayout. Первый вроде создает листы, но листы как то странно ведут себя. Прошу протетстить.
Второй код проходит нормально, без запинок. Но листов нету.
Для работы: Имя листа-числовой (префиксы и суффиксы пока не тестил). Запрашиваемое число должно быть больше чем значение текущего листа.

Знать бы еще что ты понимаешь под полной копией
Полная копия = копия листа со всей информацией относящийся к печати + полный набор объектов чертежа которая находятся в данном листе.

Отмечено как Решение NurGeo 01-12-2015, 14:21:03

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Несколько исправлений. Остальное не смотрел:
Код - vb.net [Выбрать]
  1. Sub CopyLayoutSub()
  2.     If Not GetCivilObject() Then Exit Sub
  3.     If LCase(GetCurrentLayoutName) = "model" Then
  4.         AcEd.WriteMessage(vbLf & "Необходимо открыть лист которую хотите копировать ")
  5.         Exit Sub
  6.     End If
  7.  
  8.     Dim AcLayoutMng As LayoutManager = LayoutManager.Current
  9.     Dim AcLayoutName As String = AcLayoutMng.CurrentLayout
  10.     'Dim CurLayoutNumber As Short =
  11.     Dim BlockNameArr() As String
  12.     Dim Delimiter As String = "_"
  13.     Dim Prefix As String = ""
  14.     Dim Suffix As String = ""
  15.     Dim StartSheetNumber As Short
  16.     Dim EndSheetNumber As Short
  17.  
  18.     Dim PrIntOpt As PromptIntegerOptions = New PromptIntegerOptions(vbLf & "Введите конечный номер листа: ")
  19.     PrIntOpt.Keywords.Add("Разделитель")
  20.     PrIntOpt.AppendKeywordsToMessage = True
  21.     PrIntOpt.AllowZero = False
  22.     PrIntOpt.AllowNegative = False
  23.  
  24.     Do
  25.         Dim PrIntRes As PromptIntegerResult = AcEd.GetInteger(PrIntOpt)
  26.         If PrIntRes.Status = PromptStatus.OK Then
  27.             EndSheetNumber = PrIntRes.Value
  28.             Exit Do
  29.         ElseIf PrIntRes.Status = PromptStatus.Keyword Then
  30.             Dim PrStrRes As PromptResult = AcEd.GetString(vbLf & "Введите разделитель префикса или суффикса '" &
  31.                                                           Delimiter & "' ")
  32.             If PrStrRes.Status = PromptStatus.OK Then
  33.                 If Len(PrStrRes.StringResult) <> 1 Then
  34.                     AcEd.WriteMessage(vbLf & "Разделитель должен состоять из одного символа. Оставлен разделитель по умолчанию. ")
  35.                 Else
  36.                     Delimiter = PrStrRes.StringResult
  37.                 End If
  38.             End If
  39.         Else
  40.             Exit Sub
  41.         End If
  42.     Loop
  43.  
  44.     'Далее получаем номер текущего листа и определяем есть ли у него префикс или суффикс
  45.     BlockNameArr = GetNumberPrefixSuffix(AcLayoutName, Delimiter)
  46.     If IsNumeric(BlockNameArr(0)) Then 'Если в имени листа есть номер      
  47.         StartSheetNumber = BlockNameArr(0)
  48.         If BlockNameArr(1) <> "" Then
  49.             Prefix = BlockNameArr(1)  'Номеру листа предшествует префикс
  50.         ElseIf BlockNameArr(2) <> "" Then
  51.             Suffix = BlockNameArr(2) 'После номера есть суффикс
  52.         End If
  53.     Else
  54.         AcEd.WriteMessage(vbLf & "Имя данного листа не содержит номера или имя слишком сложное. ")
  55.         Exit Sub
  56.     End If
  57.  
  58.     If StartSheetNumber > EndSheetNumber Then
  59.         AcEd.WriteMessage(vbLf & "Номер введенного конечного листа меньше чем значение данного листа. ")
  60.         Exit Sub
  61.     End If
  62.  
  63.  
  64.     For i = StartSheetNumber To EndSheetNumber
  65.         Dim NewlayoutName As String
  66.         If Prefix <> "" Then
  67.             NewlayoutName = Prefix & i
  68.         ElseIf Suffix <> "" Then
  69.             NewlayoutName = i & Suffix
  70.         Else
  71.             NewlayoutName = i
  72.         End If
  73.  
  74.         Copylayout(AcLayoutName, NewlayoutName)
  75.         AcLayoutName = NewlayoutName
  76.     Next
  77.  
  78. End Sub
  79.  
  80.  
  81. Sub Copylayout(OldName As String, NewName As String)
  82.  
  83.     Using AcTr As Transaction = AcDb.TransactionManager.StartTransaction()
  84.  
  85.         Dim lytDict As DBDictionary = AcTr.GetObject(AcDb.LayoutDictionaryId, OpenMode.ForRead)
  86.         'Смортим есть ли такой лист уже в чертеже
  87.         If lytDict.Contains(NewName) Then
  88.             AcEd.WriteMessage(vbLf & "Лист " & NewName & " уже есть в чертеже. ")
  89.             AcTr.Commit()
  90.             Return
  91.         End If
  92.         AcTr.Commit()
  93.     End Using
  94.  
  95.     Dim LytMgr As LayoutManager = LayoutManager.Current()
  96.     Dim NewLayoutId As ObjectId = LytMgr.CreateLayout(NewName)
  97.  
  98.     Using AcTr As Transaction = AcDb.TransactionManager.StartTransaction()
  99.         Dim NewLayout As Layout = AcTr.GetObject(NewLayoutId, OpenMode.ForWrite)
  100.  
  101.         Dim OldlayoutId As ObjectId = LytMgr.GetLayoutId(OldName)
  102.         Dim OldLayout As Layout = AcTr.GetObject(OldlayoutId, OpenMode.ForRead)
  103.         NewLayout.CopyFrom(OldLayout)
  104.         NewLayout.TabOrder = OldLayout.TabOrder + 1
  105.  
  106.         Dim blkTableRec As BlockTableRecord = AcTr.GetObject(OldLayout.BlockTableRecordId, OpenMode.ForRead)
  107.  
  108.         Dim objIdCol As New ObjectIdCollection()
  109.         For Each objId As ObjectId In blkTableRec
  110.             objIdCol.Add(objId)
  111.         Next
  112.  
  113.         Dim idMap As IdMapping = New IdMapping()
  114.         AcDb.DeepCloneObjects(objIdCol, NewLayout.BlockTableRecordId,
  115.                 idMap, False)
  116.  
  117.         AcTr.Commit()
  118.     End Using
  119.     AcDoc.Editor.Regen()
  120.  
  121. End Sub
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн NurGeoАвтор темы

  • ADN OPEN
  • Сообщений: 31
  • Карма: 1
Александр Ривилис
Вы волшебник! Вроде в коде ничего особенного и не изменилось, а работает. Было бы интересно услышать, что у меня было не так.
Для сравнения, другим, ложу мой вариант (чтобы видеть как не надо делать!!!) .
Внимание! Код не работает!
Код - vb.net [Выбрать]
  1.     Sub Copylayout(OldName As String, NewName As String)
  2.  
  3.         Using AcTr As Transaction = AcDb.TransactionManager.StartTransaction()
  4.  
  5.             Dim lytDict As DBDictionary = AcTr.GetObject(AcDb.LayoutDictionaryId, OpenMode.ForRead)
  6.             'Смортим есть ли такой лист уже в чертеже
  7.             If lytDict.Contains(NewName) Then
  8.                 AcEd.WriteMessage(vbLf & "Лист " & NewName & " уже есть в чертеже. ")
  9.                 Return
  10.             End If
  11.  
  12.             Dim LytMgr As LayoutManager = LayoutManager.Current()
  13.             Dim NewLayoutId As ObjectId = LytMgr.CreateLayout(NewName)
  14.             Dim NewLayout As Layout = AcTr.GetObject(newLayoutId, OpenMode.ForWrite)
  15.  
  16.             Dim OldlayoutId As ObjectId = LytMgr.GetLayoutId(OldName)
  17.             Dim OldLayout As Layout = AcTr.GetObject(OldlayoutId, OpenMode.ForRead)
  18.             NewLayout.CopyFrom(OldLayout)
  19.             'NewLayout.TabOrder = OldLayout.TabOrder + 1
  20.  
  21.             Dim blkTableRec As BlockTableRecord = AcTr.GetObject(OldLayout.BlockTableRecordId, OpenMode.ForRead)
  22.  
  23.             Dim objIdCol As New ObjectIdCollection()
  24.             For Each objId As ObjectId In blkTableRec
  25.                 objIdCol.Add(objId)
  26.             Next
  27.  
  28.             Dim idMap As IdMapping = New IdMapping()
  29.             AcDb.DeepCloneObjects(objIdCol, NewLayout.BlockTableRecordId,
  30.                     idMap, False)
  31.            
  32.             AcDoc.Editor.Regen()
  33.  
  34.             AcTr.Commit()
  35.         End Using
  36.  
  37.     End Sub

Часть кода вызывающей процедуры.
Код - vb.net [Выбрать]
  1.     For i = EndSheetNumber To StartSheetNumber + 1 step -1
  2.         Dim NewlayoutName As String
  3.         If Prefix <> "" Then
  4.             NewlayoutName = Prefix & i
  5.         ElseIf Suffix <> "" Then
  6.             NewlayoutName = i & Suffix
  7.         Else
  8.             NewlayoutName = i
  9.         End If
  10.  
  11.         Copylayout(AcLayoutName, NewlayoutName)        
  12.     Next

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Было бы интересно услышать, что у меня было не так.
Самое существенное, почему не работало. Вот этот код не должен быть внутри транзакции:
Код - vb.net [Выбрать]
  1. Dim NewLayoutId As ObjectId = LytMgr.CreateLayout(NewName)
Поэтому у меня в коде две транзакции. Ну а остальное - это декоративные исправления для того, чтобы листы последовательно (согласно нумерации) располагались сразу при их создании.
« Последнее редактирование: 01-12-2015, 18:10:35 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн D_TRex

  • ADN OPEN
  • ***
  • Сообщений: 104
  • Карма: 0
Доброго времени суток, а можно в двух строках код копирования листа, мне проверка имени не нужна, так как я выбираю из открытого документа шаблон, проверка имён пока тоже не к чему, мне просто и коротко CopyFrom если можно либо тут больше подходит CopyObjects, но тоже "тёмный лес". Спасибо

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
а можно в двух строках код копирования листа
Нет конечно. В отмеченном решении есть функция Copylayout. Вот она и выполняет копирование. Если тебе нужно тоже самое на C#, то воспользуйся бесплатным конвертером VB.NET->C#
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн D_TRex

  • ADN OPEN
  • ***
  • Сообщений: 104
  • Карма: 0
А подробнее путь к Copylayout?

Оффлайн D_TRex

  • ADN OPEN
  • ***
  • Сообщений: 104
  • Карма: 0
Полистал книгу и если я правильно понял, от
Код - vb.net [Выбрать]
  1. CadDoc.CopyObjects(что тут должно быть) 'вот тут можно скопировать лист, но мне пишет "Не верный массив объектов"
  2. CadLayot.CopyFrom(Ну или может быть тут) 'вот это я так понял копирует настройки шаблона, пока не попробую, уже глубокая ночь и код по созданию листов в отдельном проекте

В примере выше Вы полностью новую процедуру написали именем CopyFrom. Ну либо если без вариантов, то я конечно скопирую всё и буду построчно разбирать, но у меня Using видимо не находит ссылку
« Последнее редактирование: 20-04-2022, 22:12:47 от D_TRex »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
D_TRex,
Через COM/ActiveX этот код работать не будет. Этот код использует AutoCAD .NET API.
Вроде то, что тебе нужно здесь: https://adn-cis.org/forum/index.php?topic=2943.0
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение