Редактирование и создание файла DWG без открытия его в среде AutoCAD

Автор Тема: Редактирование и создание файла DWG без открытия его в среде AutoCAD  (Прочитано 11887 раз)

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

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

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Использую RealDWG для редактирования DWG файла.
Все работает нормально, кроме одного - создание в базе данных элементов DBText. Тексты успешно добавляются в базу данных, но вот когда я задаю программно выравнивание, например «середина по центру», то при открытии файла в AutoCAD тексты выровнены как нужно, но физическое их отображение на экране с выравниванием по умолчанию. Команды регенерации не помогают. Пользователю обязательно приходится что называется «втряхнуть» чертеж, например перенести примитивы из т. 0,0 в 0,0 и только тогда AutoCAD сделает перерисовку текстов и они примут вид в соотв. заданным выравниванием. Пробовал и клонировать готовый текст в шаблоне dwt методом clone – не помогает. Вот код проекта:

Код - vb.net [Выбрать]
  1. Imports Autodesk.AutoCAD.DatabaseServices
  2. Imports Autodesk.AutoCAD.ApplicationServices
  3. Imports Autodesk.AutoCAD.Runtime
  4. Imports Autodesk.AutoCAD.EditorInput
  5. Imports Autodesk.AutoCAD.ApplicationServices.Application
  6. Imports Autodesk.AutoCAD.DatabaseServices.LineWeight
  7.  
  8. Public Class acad_commands
  9.  
  10.     ' ТЕСТОВАЯ КОМАНДА ГЕНЕРАЦИИ ФАЙЛА
  11.     <CommandMethod("TEST_T")> _
  12.     Public Sub Add_DWG_FILE()
  13.         ' 0. ПРОВЕРКА НАЛИЧИЯ ФАЙЛА ШАБЛОНА
  14.         Dim NameTemplate As String = "C:\2\mytempl.dwt" ' мой шаблон
  15.         Dim fsn = New FileIO.FileSystem
  16.         If Not fsn.FileExists(NameTemplate) Then
  17.             MsgBox("Файл шаблона " & NameTemplate & " не найден.")
  18.             Exit Sub
  19.         End If
  20.         Dim db As New Database(false, true) ' 2014.10.23 добавил аргументы
  21.         ' 1. ЧИТАЕМ БАЗУ ДАННЫХ ИЗ ШАБЛОНА DWT
  22.         Try
  23.             db.ReadDwgFile(NameTemplate, IO.FileShare.ReadWrite, False, Nothing)
  24.         Catch ex As System.Exception
  25.             MsgBox("Файл шаблона " & NameTemplate & vbCrLf & "создан в более новой версии AutoCAD" & vbCrLf & _
  26.                    ex.Message)
  27.             db.Dispose()
  28.             Exit Sub
  29.         End Try
  30.         ' 2. ДОБАВЛЯЕМ КОЛЕЕКЦИЮ ents ПРИМИТИВОВ В БАЗУ ТЕКСТОМ
  31.         Dim ents = New List(Of Entity)
  32.         Dim tCnt As Integer = 1 '  кол-во добавляемых текстов
  33.         For i As Integer = 0 To tCnt - 1
  34.             Dim newTxt As DBText = acadnet_Create_DBText(New pnt2d(10 * i, 10 + i), "строка", 1, 0)
  35.             ents.Add(newTxt)
  36.         Next
  37.         ' 3. ДОБАВЛЕНИЕ ПРИМИТИВОВ В БАЗУ ДАННЫХ ЧЕРТЕЖА
  38.         Append_images(ents, db)
  39.  
  40.         db.CloseInput(True) ' 2014.10.23 ' Переставил эту строчку сюда, т.к ей не место после Finally оператора try
  41.  
  42.         ' 4. СОЗДАЕМ НОВЫЙ ФАЙЛ С ЗАПОЛНЕННОЙ БАЗОЙ ДАННЫХ
  43.  
  44.         Try
  45.             Dim FullFileName As String = "C:\2\mynewfile.dwg"
  46.             db.SaveAs(FullFileName, Autodesk.AutoCAD.DatabaseServices.DwgVersion.AC1015)  ' соотв. формату acad 2004
  47.             If fsn.FileExists(FullFileName) Then
  48.                 MsgBox("Создан файл " & FullFileName)
  49.             End If
  50.         Catch ex As System.Exception
  51.             MsgBox("Ошибка записи в файл " & vbCrLf & ex.Message)
  52.         Finally
  53.             ' 5. ЗАВЕРШАЮЩИЕ ПРОЦЕДУРЫ
  54.             db.Dispose()
  55.         End Try
  56.     End Sub
  57.  
  58.     ' Добавление примитивов ents в базу данных db
  59.     Public Shared Sub Append_images(ByVal ents As List(Of Entity), _
  60.                                     ByVal db As Database)
  61.         Using tr As Transaction = db.TransactionManager.StartTransaction()
  62.             Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForWrite)
  63.             Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
  64.             For i As Integer = 0 To ents.Count - 1
  65.                 Try
  66.                     ' добавляем примитив
  67.                     Dim id = btr.AppendEntity(ents.Item(i))
  68.                     tr.AddNewlyCreatedDBObject(ents.Item(i), True)
  69.                     ' выравниванием примитив, если текст
  70.                     acadnet_primitive_SetAlignText_ByEnt(ents.Item(i), _
  71.                                                          TextHorizontalMode.TextCenter, _
  72.                                                          TextVerticalMode.TextVerticalMid)
  73.                 Catch ex As System.Exception
  74.                 End Try
  75.             Next
  76.             tr.Commit()
  77.             tr.Dispose()
  78.         End Using
  79.     End Sub
  80.     ' выравнивание текста Ent
  81.     Public Shared Sub acadnet_primitive_SetAlignText_ByEnt(ByRef Ent As Entity, _
  82.                                                            ByVal horMode As TextHorizontalMode, _
  83.                                                            ByVal vertMode As TextVerticalMode)
  84.         If Not TypeOf Ent Is DBText Then Exit Sub
  85.         Ent.UpgradeOpen()
  86.         With DirectCast(Ent, DBText)
  87.             .HorizontalMode = horMode
  88.             .VerticalMode = vertMode
  89.             .AlignmentPoint = .Position
  90.         End With
  91.     End Sub
  92.     ' создает пимитив DBText
  93.     Public Shared Function acadnet_Create_DBText(ByVal pos As pnt2d, _
  94.                                                  ByVal s As String, _
  95.                                                  ByVal H As Double, _
  96.                                                  ByVal rot As Double) As DBText
  97.         Dim txt = New DBText
  98.         txt.TextString = s
  99.         txt.Height = H
  100.         txt.WidthFactor = 1
  101.         txt.Rotation = rot
  102.         txt.Position = New Autodesk.AutoCAD.Geometry.Point3d(pos.x, pos.y, 0)
  103.         Return txt
  104.     End Function
  105.     Public Class pnt2d
  106.         Public x As Double
  107.         Public y As Double
  108.         Public Sub New(ByVal _x As Double, ByVal _y As Double)
  109.             Me.x = _x
  110.             Me.y = _y
  111.         End Sub
  112.     End Class
  113. End Class
  114.  
« Последнее редактирование: 23-10-2014, 21:21:55 от Алексей (IdeaSoft) »

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
 Добрый день и приветствую на форуме!
 Специально вчера перевёл статью по этому поводу: Обновление выравнивания текста
 Основные моменты этой статьи и дополнительные соображения:
1) Для того чтобы выравнивание работало как следует необходимо вызвать метод DBText.AdjustAlignment, и передать ему в качестве параметра указатель на базу (Database), в которой это DBText находится или будет находится после добавления.
2) Необходимо переключить рабочую базу данных на ту базу данных, в которой будет DBText на время вызова DBText.AdjustAlignment, т.е. что-то такое:
Код - vb.net [Выбрать]
  1. Database prevWorkingDb = HostApplicationServices.WorkingDatabase
  2. HostApplicationServices.WorkingDatabase = db
  3. dbText.AdjustAlignment(db)
  4. HostApplicationServices.WorkingDatabase = prevWorkingDb
3) Перед тем как устанавливать параметры выравнивания необходимо, чтобы DBText указывал на существующий в базе текстовый стиль. Один из вариантов, это вызов dbText.SetDatabaseDefaults(db), где db – база данных в которой содержится (или будет содержаться) dbText.
 
Попробуй. Если не получится, то результирующий исходный код выложи здесь снова.

P.S.: Вспомнил, что сохранение в формате AutoCAD 2004 может портить выравнивание. Попробуй сохранять в текущей версии AutoCAD.
 
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Супер! Ура! Вот изменил как ты сказал и все заработало.
При открытии файла текст нарисован в соотв. с заданным выравниванием.
Большое спасибо!
Что касается формата результирующего файла, то можно и AutoCAD 2004 - это не влияет.
Вот измененный код функции Append_images:


Код - vb.net [Выбрать]
  1.     Public Shared Sub Append_images(ByVal ents As List(Of Entity), _
  2.                                                        ByVal db As Database)
  3.         Using tr As Transaction = db.TransactionManager.StartTransaction()
  4.             Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForWrite)
  5.             Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
  6.             For i As Integer = 0 To ents.Count - 1
  7.                 Try
  8.                     ' добавляем примитив
  9.                     Dim id = btr.AppendEntity(ents.Item(i))
  10.                     tr.AddNewlyCreatedDBObject(ents.Item(i), True)
  11.                     ' выравниванием примитив, если текст
  12.                     acadnet_primitive_SetAlignText_ByEnt(ents.Item(i), _
  13.                                                          TextHorizontalMode.TextCenter, _
  14.                                                          TextVerticalMode.TextVerticalMid)
  15.                     ' << ДОБАВЛЕННЫЙ КОД от 2014.06.11
  16.                     Dim prevWorkingDb As Database = HostApplicationServices.WorkingDatabase
  17.                     HostApplicationServices.WorkingDatabase = db
  18.                     DirectCast(ents.Item(i), DBText).AdjustAlignment(db)
  19.                     HostApplicationServices.WorkingDatabase = prevWorkingDb
  20.                     ' ДОБАВЛЕННЫЙ КОД >>
  21.                 Catch ex As System.Exception
  22.                 End Try
  23.             Next
  24.             tr.Commit()
  25.             tr.Dispose()
  26.         End Using
« Последнее редактирование: 12-06-2014, 09:14:21 от IdeaSoft »

Отмечено как Решение Александр Ривилис 03-09-2015, 12:22:57

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Отлично. Я позволил себе немного улучшить код:
1) Зачем переключатся между рабочими базами на каждом из добавляемых примитивов если это можно сделать один раз
2) tr.Dispose() - это лишнее, т.к. Using tr As Transaction ... выполняет в конце тоже самое.
Код - vb.net [Выбрать]
  1. Public Shared Sub Append_images(ByVal ents As List(Of Entity), _
  2.                                                    ByVal db As Database)
  3.     ' << ДОБАВЛЕННЫЙ КОД от 2014.06.11
  4.     Dim prevWorkingDb As Database = HostApplicationServices.WorkingDatabase
  5.     HostApplicationServices.WorkingDatabase = db
  6.     ' ДОБАВЛЕННЫЙ КОД >>    
  7.     Using tr As Transaction = db.TransactionManager.StartTransaction()
  8.         Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForWrite)
  9.         Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
  10.         For i As Integer = 0 To ents.Count - 1
  11.             Try
  12.                 ' добавляем примитив
  13.                 Dim id = btr.AppendEntity(ents.Item(i))
  14.                 tr.AddNewlyCreatedDBObject(ents.Item(i), True)
  15.                 ' выравниванием примитив, если текст
  16.                 acadnet_primitive_SetAlignText_ByEnt(ents.Item(i), _
  17.                                                      TextHorizontalMode.TextCenter, _
  18.                                                      TextVerticalMode.TextVerticalMid)
  19.                 DirectCast(ents.Item(i), DBText).AdjustAlignment(db)
  20.             Catch ex As System.Exception
  21.             End Try
  22.         Next
  23.         tr.Commit()
  24.     End Using
  25.     ' << ДОБАВЛЕННЫЙ КОД от 2014.06.11
  26.     HostApplicationServices.WorkingDatabase = prevWorkingDb
  27.     ' ДОБАВЛЕННЫЙ КОД >>
  28. End Sub

И еще на форуме есть теги [code=vbnet]...код...[/code], которые резко улучшают читабельность кода.  :)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Забыл упомянуть версию AutoCAD.
Этот код реально тестировался с AutoCAD 2012 64 bit
Но реально должен работать в AutoCAD 2011,2012,2013,2014,2015 для 32 bit 64 bit

И вот еще нужно вставить проверку на то, что Entity это DBText
в теле цикла функции Append_images внутри функции acadnet_primitive_SetAlignText_ByEnt
такая проверка есть
Код - vb.net [Выбрать]
  1.         For i As Integer = 0 To ents.Count - 1
  2.             Try
  3.                 ' добавляем примитив
  4.                 Dim id = btr.AppendEntity(ents.Item(i))
  5.                 tr.AddNewlyCreatedDBObject(ents.Item(i), True)
  6.                 ' выравниванием примитив, если текст
  7.                 acadnet_primitive_SetAlignText_ByEnt(ents.Item(i), _
  8.                                                      TextHorizontalMode.TextCenter, _
  9.                                                      TextVerticalMode.TextVerticalMid)
  10.                 If TypeOf ents.Item(i).Ent Is DBText Then ' 2014.06.12
  11.                     DirectCast(ents.Item(i), DBText).AdjustAlignment(db)
  12.                 End If
  13.             Catch ex As System.Exception
  14.             End Try
  15.         Next
  16.  
« Последнее редактирование: 16-06-2014, 18:38:32 от IdeaSoft »

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

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

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
В принципе у меня тоже была в голове такая идея. Все верно. Зачем переключать бызы при каждой итерации в цикле.
Если можно сделать вначале и в конце. Я проверю как это будет работать. Думаю все должно быть ok.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
В принципе "ДА" этот код работает в AutoCAd 2006 только проверил
подключив к проекту сборки из AutoCAD 2006 я проверял.


Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Единственное что важно, то что в для AutoCAd 2006 нужно проект собирать на платформе NET 3.5 или 3.0
Если собрать NET 4.5, то acad 2006 не загрузит сборку командой netload.
 

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Единственное что важно, то что в для AutoCAd 2006 нужно проект собирать на платформе NET 3.5 или 3.0
Если собрать NET 4.5, то acad 2006 не загрузит сборку командой netload.
 
тынц 1
тынц 2.

Цитировать
Забыл упомянуть версию AutoCAD.
Этот код реально тестировался с AutoCAD 2012 64 bit
Но реально должен работать в AutoCAD 2011,2012,2013,2014,2015 для 32 bit 64 bit
При соответствующем подходе, компилировать решение (solution) можно нажатием F6 сразу под все версии AutoCAD, с попутной генерацией необходимой CHM документации. Это позволяет добавлять возможность компилирования под очередную версию AutoCAD (2016-2020) буквально за несколько минут: создание нового проекта, настройка его свойств и линковка его посредством ссылок к уже существующим файлам исходного кода и ресурсов.
« Последнее редактирование: 11-06-2014, 17:36:05 от Андрей Бушман »

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Если мне нужно, к примеру сделать 2 сборки одного проекта для 2 разных версий AutoCAD,
то мне приходиться в референсах для каждого AutoCAD поочередно подключать сборки для
каждой версии AutoCAD и таки 2 раза компилировать проект.

На сколько я понял в Visual Studio есть возможность (написать макрос или еще как-то), 
и автоматически будут делаться сразу за одно F5 несколько Релизов для каждого AutoCAD.

Только вот я еще не пробовал возможно ли так сделать?
   

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Если мне нужно, к примеру сделать 2 сборки одного проекта для 2 разных версий AutoCAD,
то мне приходиться в референсах для каждого AutoCAD поочередно подключать сборки для
каждой версии AutoCAD и таки 2 раза компилировать проект.
Неправильный подход. Я могу тебе для наглядности скинуть пример (solution). Только для того, чтобы его открыть, тебе нужна будет VS 2013, т.к. solution создан именно в этой версии. Дополнительный нюанс заключается в том, что я использую удалённую отладку, как уже писал здесь. Соответственно результат компиляции формируется не на той машине, где установлены IDE и прочие инструменты разработчика, но на машинке с установленными AutoCAD, предназначенной для тестирования. Всё это легко настраивается в свойствах проектов.

Кроме того, поскольку в составе решения присутствует проект,выполняющий компиляцию документации для Release версии, то тебе понадобится установить это. Обращаю внимание на то, что оно применяется только к тому профилю Windows, из под которого устанавливалось. Возможно на время установки тебе придётся назначить твоему профилю административные права.

Рефакторинго пока не выполнен. В частности, ещё предстоит выполнить отделение локализаций от программного кода (но это не долго). Unit тесты под этот проект пока так же не написаны, т.к. сейчас занят несколько другими делами.

Цитировать
На сколько я понял в Visual Studio есть возможность (написать макрос или еще как-то), 
и автоматически будут делаться сразу за одно F5 несколько Релизов для каждого AutoCAD.

Только вот я еще не пробовал возможно ли так сделать?
Да возможно. Я именно так и делаю.

P.S. Да и, если надумаешь, то обозначь мыло, на которое скидывать ссылку.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Единственное что важно, то что в для AutoCAd 2006 нужно проект собирать на платформе NET 3.5 или 3.0
Вообще-то AutoCAD 2006 скомпилирован с .NET 1.1 :)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
В принципе это понятно что 1.1
Я использую VS 2012  в ней минимум сборка идет под .NET 2.0
И потом хочется использовать linq, а он начинается вроде как с . NET 3.0
Конечно можно в VS 2008 собрать под .NET 1.1 но зачем же мне возвращаться на 10 лет назад.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
На сколько я понял в Visual Studio есть возможность (написать макрос или еще как-то), 
и автоматически будут делаться сразу за одно F5 несколько Релизов для каждого AutoCAD.

Только вот я еще не пробовал возможно ли так сделать?


Да возможно. Я именно так и делаю.

P.S. Да и, если надумаешь, то обозначь мыло, на которое скидывать ссылку.
Можно скинуть almakarenko@mail.ru