Рисовать в Autocad с помощью c++

Автор Тема: Рисовать в Autocad с помощью c++  (Прочитано 22726 раз)

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

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

Оффлайн Nevermind.qqqАвтор темы

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Добрый день, написал программу на c++ и теперь для нее нужно сделать, чтобы после расчета открывался AutoCAD и по полученным из расчета данным рисовало чертеж. Однако в ObjectARX не разбираюсь, возможно есть какие-то примеры(ну в папке с objectarx sdk что-то есть, но как их запустить я так и не понял)? VS2013 , AutoCAD2014

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #1 : 17-09-2014, 13:27:52 »
Приветствую на форуме!
VS2013 , AutoCAD2014
Читаем внимательно (!!!) документацию:
Цитировать
Microsoft Visual Studio 2010 with Service Pack 1 should be used when compiling projects for use with AutoCAD 2014.
И никак иначе. Т.е. для того, чтобы создать ObjectARX приложение для AutoCAD 2014 у тебя должно быть установлено VS 2010 SP1 (не Express)
После того как VS 2010 SP1 будет установлен ты сможешь построить любой из примеров ObjectARX SDK и загрузить его в AutoCAD (например, при помощи команды _APPLOAD или _ARX или вызова lisp-функции (arxload "путь к arx-файлу") )
В качестве примера можешь посмотреть samples\database\ents_dg из состава ObjectARX SDK. Он показывает как создать простейшие примитивы AutoCAD (т.е. поместить их в чертеж).


Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #2 : 17-09-2014, 13:39:51 »
Забыл еще уточнить, что для AutoCAD 2014 необходим ObjectARX SDK 2014 (можно использовать и 2013), но не ObjectARX 2015. Ну и никакие другие версии тоже не подходят.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Nevermind.qqqАвтор темы

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Re: Рисовать в Autocad с помощью c++
« Ответ #3 : 17-09-2014, 13:52:10 »
спасибо , с этим понятно, возможно я не совсем правильно сформулировал, но я видел приложение на VBA: там  вписываются числа , далее кнопка "Построить" -> открывается AutoCAD (та версия которая есть, там только библиотеку другую выбрать нужно), создается новый чертеж и на нем по введенным числам строится эпюра(т.е. в AutoCADe вводить ничего не нужно,программа сама все делает). Так вот меня интересует создание подобной программы только на C++. Хотелось бы знать ObjectARX это то, что мне нужно?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #4 : 17-09-2014, 14:00:36 »
Так вот меня интересует создание подобной программы только на C++. Хотелось бы знать ObjectARX это то, что мне нужно?
Нет. Это называется AutoCAD ActiveX/COM API:
http://images.autodesk.com/adsk/files/autocad_2013_activex_help.zip
Там всё применительно к VBA, но перевести на C++ можно.

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #5 : 17-09-2014, 19:24:04 »
Я подготовил небольшой пример, который показывает как запустить AutoCAD (через COM/ActiveX), создать новый документ, нарисовать в нем отрезок и несколько окружностей, сохранить его и выйти из AutoCAD. Имей в виду что в коде минимальное количество проверок на ошибки:
Код - C++ [Выбрать]
  1. #import "acax19enu.tlb" raw_interfaces_only no_namespace
  2.  
  3. HRESULT PointToVariant(const double pt[3], VARIANT* pVal);
  4.  
  5. void CMFCAcadAppDlg::OnBnClickedStartacad()
  6. {
  7.   // TODO: Add your control notification handler code here
  8.   ::CoInitialize(NULL);
  9.  
  10.   COleMessageFilter* pFilter = AfxOleGetMessageFilter();
  11.   if (pFilter != NULL) {
  12.     DWORD dTimedelay = 1000;
  13.     pFilter->SetMessagePendingDelay(dTimedelay); // Врем ожидания - 1 сек
  14.     dTimedelay = -1;
  15.     pFilter->SetRetryReply(dTimedelay);
  16.     pFilter->EnableBusyDialog(FALSE); // Запрещаем диалог "сервер занят"
  17.     pFilter->EnableNotRespondingDialog(FALSE); // Запрещаем диалог "сервер не отвечает"
  18.   }
  19.   try
  20.   {
  21.     CLSID clsid ;
  22.     // Для AutoCAD 2014 - L"AutoCAD.Application.19.1"
  23.     // Если версия AutoCAD не важна, то можно L"AutoCAD.Application"
  24.     _com_util::CheckError(CLSIDFromProgID (L"AutoCAD.Application.19.1", &clsid));
  25.     IAcadApplicationPtr pApp;
  26.      // Если AutoCAD не запущен - попробуем запустить
  27.     if (FAILED(pApp.GetActiveObject(clsid)))
  28.     {
  29.       _com_util::CheckError(pApp.CreateInstance(clsid));
  30.     }
  31.     pApp->put_Visible(VARIANT_TRUE);
  32.     // Получаем список открытых документов AutoCAD
  33.     IAcadDocumentsPtr pDocs;
  34.     _com_util::CheckError(pApp->get_Documents(&pDocs));
  35.     IAcadDocumentPtr pDoc;
  36.     // Создаем новый документ-чертеж (для простоты с шаблоном acadiso.dwt)
  37.     _com_util::CheckError(pDocs->Add(_variant_t(_T("acadiso.dwt")), &pDoc));
  38.     // Будем работать с пространством модели
  39.     IAcadModelSpacePtr pSpace;
  40.     _com_util::CheckError(pDoc->get_ModelSpace(&pSpace));
  41.     // Добавим отрезок с началом в {0 0 0} и концом в {10 10 0}
  42.     IAcadLinePtr pLine;
  43.     _variant_t vStart, vEnd; // Начало и конец отрезка
  44.     const int iMax = 10;
  45.     double p1[3] = {0, 0, 0}, p2[3] = { iMax, iMax, 0};
  46.     _com_util::CheckError(PointToVariant(p1, &vStart));
  47.     _com_util::CheckError(PointToVariant(p2, &vEnd));
  48.     _com_util::CheckError(pSpace->AddLine(/*начало*/ vStart, /*конец*/ vEnd, &pLine));
  49.     _com_util::CheckError(pLine->put_color(acYellow)); // Меняем цвет на желтый
  50.     // Добавим окружности вдоль отрезка с радиусом 1
  51.     IAcadCirclePtr pCircle;
  52.     for (int i = 0; i <= iMax; i++) {
  53.       p1[0] = i; p1[1] = i;
  54.       _com_util::CheckError(PointToVariant(p1, &vStart));
  55.       _com_util::CheckError(pSpace->AddCircle( /*центр*/ vStart, /*радиус*/ 1.0, &pCircle));
  56.       _com_util::CheckError(pCircle->put_color(acGreen)); // Меняем цвет на зеленый
  57.     }
  58.     pDoc->SaveAs(_bstr_t(_T("C:\\test.dwg")));
  59.     pApp->Quit();
  60.   }
  61.   catch(const _com_error e)
  62.   {
  63.     if (e.ErrorMessage()!=NULL) {
  64.       CString msg; msg.Format(_T("Error: %s"),e.ErrorMessage());
  65.       AfxMessageBox(msg,MB_ICONERROR);
  66.     }
  67.   }
  68.   ::CoUninitialize();
  69. }
  70.  
  71. //////////////////////////////////////////////////////////////////////////
  72. //  Функция для преобразования точки double pt[3] в VARIANT
  73. //////////////////////////////////////////////////////////////////////////
  74. HRESULT PointToVariant(const double pt[3], VARIANT* pVal)
  75. {
  76.   pVal->vt = VT_ARRAY | VT_R8;
  77.   SAFEARRAYBOUND rgsaBound;
  78.   rgsaBound.lLbound = 0L;
  79.   rgsaBound.cElements = 3;
  80.   pVal->parray = SafeArrayCreate(VT_R8, 1, &rgsaBound);
  81.   if (!pVal->parray)  return E_OUTOFMEMORY;
  82.   HRESULT hr;
  83.   for (long i = 0; i < 3; i++) {
  84.     if ((hr = SafeArrayPutElement(pVal->parray,&i,(void*)&pt[i])) != S_OK)  return hr;
  85.   }
  86.   return S_OK;
  87. }
Полный проект для VS 2012 приложил.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Nevermind.qqqАвтор темы

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Re: Рисовать в Autocad с помощью c++
« Ответ #6 : 17-09-2014, 22:54:24 »
Большое спасибо, буду разбираться

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #7 : 18-09-2014, 00:37:30 »
Большое спасибо, буду разбираться
Пожалуйста. Будут вопросы - задавай.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Nevermind.qqqАвтор темы

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Re: Рисовать в Autocad с помощью c++
« Ответ #8 : 20-09-2014, 13:12:50 »
Нигде не удалось найти VS12 ultimate или professional , поставил VS13 ultimate,собрал программу(Release, т.к. Debug ошибку выбивает). Диалоговое окно открывается, жму "Запустить AutoCAD", он запускается, появляется Чертеж1(видимо который стандартно при запуске создается), и Чертеж2(видимо созданный программой) - оба пустые, при открытии диалогового окна видно что оно выбило ошибку "Error:вызов был отклонен" .Так же один раз приложение все-таки создало test.dwg - но увы пустой, и только 1 раз.
Компилятор пишет следующее:
First-chance exception at 0x7612C41F (KernelBase.dll) in MFCAcadApp.exe: 0x80010001: Вызов был отклонен.
First-chance exception at 0x7612C41F in MFCAcadApp.exe: Microsoft C++ exception: _com_error at memory location 0x0017F45C.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #9 : 20-09-2014, 14:32:39 »
Ну а теперь тоже самое, только в режиме отладки, пошагово и/или с контрольными точками и посмотри где затык.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Nevermind.qqqАвтор темы

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Re: Рисовать в Autocad с помощью c++
« Ответ #10 : 20-09-2014, 14:51:21 »
Отладка в x64 пишет compapi.cxx not found
Отладка в win32 Вызывает ошибку "Запуск программы невозможен т.к. на компьютере отсутствует  mfc120ud.dll. Попробуйте переустановить программу."

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #11 : 20-09-2014, 15:08:10 »
Ну тут два варианта:
1) Плохо установился VS 2013 (Update 3 установлен?)
2) Произошла ошибка при конвертации проекта из VS 2012 в VS 2013.
Попробуй создать проект с нуля и добавить в обработчик кнопки мой код.
Если после компиляции в режиме отладки будет таже ошибка, то у тебя проблемы с VS 2013
P.S.: Я тестировал в режиме Debug x64
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Александр Ривилис 16-03-2020, 18:22:49

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #12 : 20-09-2014, 22:10:17 »
Я проверил и с VS 2013. Впрочем 0x80010001: Вызов был отклонен. от версии VS не зависит. Тогда, когда AutoCAD занят своими делами, он иногда возвращает код RPC_E_CALL_REJECTED (это как раз и есть "Вызов отклонен"), иногда RPC_E_RETRY, иногда RPC_E_SERVERCALL_RETRYLATER. Во всех этих случаях следует подождать (при помощи функции Sleep) и повторить операцию.
Немного изменил код и он у меня стабильно работает за счет того, что каждая операция проверяется и в случае ошибки повторяется через небольшой интервал времени. Это основная проблема работы с AutoCAD в качестве COM-сервера.
Код - C++ [Выбрать]
  1. #import "acax19enu.tlb" raw_interfaces_only no_namespace
  2.  
  3. #define nRetry (100)
  4. #define mSleep (500)
  5. #define CallAcad(__x__) \
  6. { \
  7.   HRESULT hr; \
  8.   for (int i = 0; i < nRetry; i++) { \
  9.      if (!FAILED(hr = (__x__))) break; \
  10.      if (hr != RPC_E_CALL_REJECTED &&  \
  11.          hr != RPC_E_RETRY && \
  12.          hr != RPC_E_SERVERCALL_RETRYLATER) \
  13.      break; \
  14.      Sleep(mSleep); \
  15.   } \
  16.   _com_util::CheckError(hr); \
  17. }
  18.  
  19. HRESULT PointToVariant(const double pt[3], VARIANT* pVal);
  20.  
  21. IAcadState* pState = NULL;
  22.  
  23. bool checkReady()
  24. {
  25.   if (pState == NULL) return false;
  26.   VARIANT_BOOL bReady = VARIANT_FALSE;
  27.   for (int i = 0; i < nRetry; i++)  {
  28.     if (pState->get_IsQuiescent(&bReady) == S_OK && bReady == VARIANT_TRUE) break;
  29.     Sleep(mSleep);
  30.   }
  31.   return (bReady == VARIANT_TRUE);
  32. }
  33.  
  34. void CMFCAcadAppDlg::OnBnClickedStartacad()
  35. {
  36.   // TODO: Add your control notification handler code here
  37.   ::CoInitialize(NULL);
  38.  
  39.   COleMessageFilter* pFilter = AfxOleGetMessageFilter();
  40.   if (pFilter != NULL) {
  41.     DWORD dTimedelay = 1000;
  42.     pFilter->SetMessagePendingDelay(dTimedelay); // Врем ожидания - 1 сек
  43.     pFilter->SetRetryReply(dTimedelay);
  44.     pFilter->EnableBusyDialog(FALSE); // Запрещаем диалог "сервер занят"
  45.     pFilter->EnableNotRespondingDialog(FALSE); // Запрещаем диалог "сервер не отвечает"
  46.   }
  47.   try
  48.   {
  49.     CLSID clsid ;
  50.     HRESULT hr = S_OK;
  51.     // Для AutoCAD 2014 - L"AutoCAD.Application.19.1"
  52.     // Если версия AutoCAD не важна, то можно L"AutoCAD.Application"
  53.     _com_util::CheckError(CLSIDFromProgID (L"AutoCAD.Application.19.1", &clsid));
  54.     IAcadApplicationPtr pApp;
  55.     CallAcad(pApp.CreateInstance(clsid)); // Запускаем AutoCAD
  56.     pState = NULL;
  57.     CallAcad(pApp->GetAcadState(&pState));
  58.     // Делаем AutoCAD видимым, если в этом есть необходимость
  59.     if (checkReady()) CallAcad(pApp->put_Visible(VARIANT_TRUE));
  60.     // Получаем список открытых документов AutoCAD
  61.     IAcadDocumentsPtr pDocs;
  62.     if (checkReady()) CallAcad(pApp->get_Documents(&pDocs));
  63.     IAcadDocumentPtr pDoc;
  64.     // Создаем новый документ-чертеж (для простоты с шаблоном acadiso.dwt)
  65.     if (checkReady()) CallAcad(pDocs->Add(_variant_t(_T("acadiso.dwt")), &pDoc));
  66.     // Будем работать с пространством модели
  67.     IAcadModelSpacePtr pSpace;
  68.     if (checkReady()) CallAcad(pDoc->get_ModelSpace(&pSpace));
  69.     // Добавим отрезок с началом в {0 0 0} и концом в {10 10 0}
  70.     IAcadLinePtr pLine;
  71.     _variant_t vStart, vEnd; // Начало и конец отрезка
  72.     const int iMax = 10;
  73.     double p1[3] = {0, 0, 0}, p2[3] = { iMax, iMax, 0};
  74.     CallAcad(PointToVariant(p1, &vStart));
  75.     CallAcad(PointToVariant(p2, &vEnd));
  76.     if (checkReady()) {
  77.       CallAcad(pSpace->AddLine(/*начало*/ vStart, /*конец*/ vEnd, &pLine));
  78.     }
  79.     if (checkReady()) {
  80.       CallAcad(pLine->put_color(acYellow)); // Меняем цвет на желтый
  81.     }
  82.     // Добавим окружности вдоль отрезка с радиусом 1
  83.     IAcadCirclePtr pCircle;
  84.     for (int i = 0; i <= iMax; i++) {
  85.       p1[0] = i; p1[1] = i;
  86.       PointToVariant(p1, &vStart);
  87.       if (checkReady()) {
  88.         CallAcad(pSpace->AddCircle( /*центр*/ vStart, /*радиус*/ 1.0, &pCircle));
  89.       }
  90.       if (checkReady()) {
  91.         CallAcad(pCircle->put_color(acGreen)); // Меняем цвет на зеленый
  92.       }
  93.     }
  94.     if (checkReady()) CallAcad(pApp->ZoomExtents()); // Показываем границы
  95.     if (checkReady()) CallAcad(pDoc->SaveAs(_bstr_t(_T("C:\\test.dwg"))));
  96.     if (checkReady()) CallAcad(pApp->Quit());
  97.   }
  98.   catch(const _com_error e)
  99.   {
  100.     if (e.ErrorMessage()!=NULL) {
  101.       CString msg; msg.Format(_T("Error: %s"),e.ErrorMessage());
  102.       AfxMessageBox(msg,MB_ICONERROR);
  103.     }
  104.   }
  105.   ::CoUninitialize();
  106. }
  107.  
  108. //////////////////////////////////////////////////////////////////////////
  109. //  Функция для преобразования точки double pt[3] в VARIANT
  110. //////////////////////////////////////////////////////////////////////////
  111. HRESULT PointToVariant(const double pt[3], VARIANT* pVal)
  112. {
  113.   pVal->vt = VT_ARRAY | VT_R8;
  114.   SAFEARRAYBOUND rgsaBound;
  115.   rgsaBound.lLbound = 0L;
  116.   rgsaBound.cElements = 3;
  117.   pVal->parray = SafeArrayCreate(VT_R8, 1, &rgsaBound);
  118.   if (!pVal->parray)  return E_OUTOFMEMORY;
  119.   HRESULT hr;
  120.   for (long i = 0; i < 3; i++) {
  121.     if ((hr = SafeArrayPutElement(pVal->parray,&i,(void*)&pt[i])) != S_OK)  return hr;
  122.   }
  123.   return S_OK;
  124. }
« Последнее редактирование: 22-09-2014, 14:39:22 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Рисовать в Autocad с помощью c++
« Ответ #13 : 22-09-2014, 11:57:39 »
теперь для нее нужно сделать, чтобы после расчета открывался AutoCAD и по полученным из расчета данным рисовало чертеж.
Так уж ли нужно, чтобы при этом открывался AutoCAD? Если требуется автоматически генерировать чертёж, то открывать AutoCAD - это плохой подход. Во первых, сам запуск acad.exe занимает чудовищно много времени (особенно плохо с этим в последних версиях). Как вариант, ты можешь запускать accoreconsole.exe вместо acad.exe (если используешь AutoCAD новее, чем AutoCAD 2013). В этом случае запуск приложения осуществляется за 2-3 секунды, в отличие от запуска acad.exe. Но есть одно "НО": под accoreconsole.exe не существует COM API. Тем не менее, запустив эту утилиту ты можешь указать (посредством передачи параметров exe-файлу) автоматическую загрузку и запуск твоего ARX приложения, которое должно сгенерировать чертёж.

P.S. Насколько я помню, на C++ работать с чертежами можно вообще не запуская AutoCAD (при условии, что он установлен на компьютере). Думаю, что Александр Наумович, при желании, смог бы набросать "Hello World", демонстрирующий такой способ.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Рисовать в Autocad с помощью c++
« Ответ #14 : 22-09-2014, 13:36:42 »
P.S. Насколько я помню, на C++ работать с чертежами можно вообще не запуская AutoCAD (при условии, что он установлен на компьютере). Думаю, что Александр Наумович, при желании, смог бы набросать "Hello World", демонстрирующий такой способ.
Неправильно помнишь. Без запуска AutoCAD это возможно только при использовании RealDWG, а варианты требующие вложений дополнительных средств, как я понимаю, на этом этапе не рассматриваются.
Что касается accoreconsole.exe и arx (точнее crx), то:
1) Нужно отдельно будет решать вопрос с передачей параметров из основного exe-файла в arx.
2) Нужно будет под все используемые версии AutoCAD писать свои arx-файлы, что вероятно потребует нескольких версий VS.
3) Нужно будет изучить ObjectARX, что несколько сложнее, чем изучить AutoCAD ActiveX/COM API в объеме отрисовки нескольких видов примитивов.
Так что в простейшем случае я не вижу в этом необходимости.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение