ADN Open CIS
Сообщество программистов Autodesk в СНГ

12/05/2015

Реализация мультикопирования объектов с изюминкой

В недавнем запросе, разработчик упомянул о поведении команды _COPY в AutoCAD , которое, как я думаю, немного отличается от того, как ведут себя остальные команды. В команде _COPY, когда выбран режим мультикопирования, выбраны примитивы для копирования и после указания базовой точки AutoCAD размещает копии выбранных объектов. Но если нажать Enter, то мы как правило ожидаем прекращения команды, как и в большинстве других команд AutoCAD. Но в случае с командой _COPY , нажатие на клавишу Enter трактуется как "использовать первую точку в качестве смещения" и появляется новая копия до завершения команды.

Если вас не устраивает такое поведение, то возможно вам потребуется создать свою команду для копирования нескольких примитивов. Вот пример кода, который реализует это с помощью ObjectARX API и предоставляется в качестве Lisp-функции. Кроме того, при перетаскивании объектов позиция ограничена по оси X так же, как и координатный фильтр .YZ для родной команды _COPY.

Вот код:

Код - C++: [Выделить]
  1. // Глобальная переменная, так что мы сможем использовать её
  2. // в функции обратного вызова DragGen...
  3. AcGePoint3d basePt;
  4.  
  5. // Здесь фунция обратного вызова
  6. static  int  dragGenCallback(ads_point pt,ads_matrix mt)
  7. {
  8.   //AcGeVector3d vec(pt[0]-basePt[0], 
  9.   // pt[1]-basePt[1], pt[2]-basePt[2]);
  10.  
  11.   // Ограничиваем движение только осью X
  12.   AcGeVector3d vec(pt[0]-basePt[0], 0, 0);
  13.  
  14.   AcGeMatrix3d mat;
  15.   // Устанавливаем матрицу для преобразования координат
  16.  
  17.   mat.setToTranslation(vec);
  18.   // Помещаем результаты в mt
  19.   for (int  c=0;c<4;c++)
  20.   {
  21.     for (int  cd=0;cd<4;cd++)
  22.       mt[c][cd]=mat(c,cd);
  23.   }
  24.   return  RTNORM;
  25. }
  26.  
  27. int  CopyMultipleEntitiesFunc()
  28. {
  29.   ads_name ss;  
  30.  
  31.   // Выбираем примитивы
  32.   acedSSGet(NULL, NULL, NULL, NULL, ss);
  33.  
  34.   // Указываем базовую точку длякопирования...
  35.   acedGetPoint(NULL,
  36.     L"Укажите базовую точку: " ,
  37.     asDblArray(basePt));
  38.   long  len;
  39.   acedSSLength(ss,&len);
  40.  
  41.   int  ret = 0;
  42.   do
  43.   {
  44.     // Значение последней точки 
  45.     // после того как пользователь закончил
  46.     // перетаскивание набора
  47.     AcGePoint3d final_pt;
  48.  
  49.     // Вызываем DragGen с функцией обратного вызова
  50.     ret = acedDragGen(ss,
  51.       L"\nУкажите вторую точку" ,
  52.       0,
  53.       dragGenCallback,
  54.       asDblArray(final_pt));
  55.  
  56.     if (ret == RTNONE || ret == RTCAN)
  57.     {// Нажато ENTER или ESC
  58.       break ;
  59.     }
  60.  
  61.     // Получаем итоговую мтрицу и выполняем копирование
  62.     // используя значение final_pt 
  63.     AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
  64.     AcDbObjectIdArray idArr;
  65.     {
  66.       long  l=0, lNumber=0;
  67.       ads_sslength(ss, &lNumber);
  68.       idArr.setPhysicalLength(lNumber);
  69.       for  (; l<lNumber; ++l)
  70.       {
  71.         ads_name ent;
  72.         ads_ssname(ss, l, ent);
  73.         AcDbObjectId idEnt;
  74.         if  (Acad::eOk == acdbGetObjectId(idEnt,ent))
  75.         {
  76.           idArr.append(idEnt);
  77.         }
  78.       }
  79.  
  80.       AcDbIdMapping idMapping;
  81.       AcDbObjectId idOwner = acdbSymUtil()->blockModelSpaceId (pDb);
  82.       Acad::ErrorStatus es =
  83.         curDoc()->database()->deepCloneObjects(idArr, idOwner, idMapping);
  84.  
  85.       if (es == Acad::eOk)
  86.       {
  87.         AcDbIdMappingIter iter2 (idMapping) ;
  88.         AcDbIdPair idPair2 ;
  89.         for  ( iter2.start ();
  90.           !iter2.done ();
  91.           iter2.next () )
  92.         {
  93.           if  ( !iter2.getMap (idPair2) )
  94.             continue  ;
  95.  
  96.           if  ( !idPair2.isCloned () )
  97.             continue  ;
  98.  
  99.           AcDbObjectId keyId = idPair2.key();
  100.           AcDbObjectId valueId = idPair2.value();
  101.  
  102.           // Трансформируем клоны согласно матрицы
  103.  
  104.           // Открываем для записи
  105.           AcDbEntity *pEnt;
  106.           acdbOpenAcDbEntity(pEnt, valueId, AcDb::kForWrite);
  107.  
  108.           AcGeMatrix3d dispmat = AcGeMatrix3d::kIdentity;
  109.           dispmat.setToTranslation(
  110.             AcGeVector3d(final_pt[0]-basePt[0], 0, 0));
  111.           pEnt->transformBy(dispmat);
  112.           pEnt->close();
  113.         }
  114.       }
  115.     }
  116.   }while (TRUE);
  117.  
  118.   ads_ssfree(ss);
  119.  
  120.   return  0;
  121. }
  122.  
  123. class  CMyTest1App : public  AcRxArxApp
  124. {
  125. public :
  126.   CMyTest1App () : AcRxArxApp ()
  127.   {
  128.   }
  129.  
  130.   virtual  AcRx::AppRetCode On_kInitAppMsg (void  *pkt)
  131.   {
  132.     AcRx::AppRetCode retCode
  133.       =AcRxArxApp::On_kInitAppMsg (pkt) ;
  134.     acedDefun(_T("CopyMultiple" ), 1000);
  135.     acedRegFunc(CopyMultipleEntitiesFunc, 1000);
  136.     return  (retCode) ;
  137.   }
  138.  
  139.   virtual  AcRx::AppRetCode On_kUnloadAppMsg (void  *pkt)
  140.   {
  141.     AcRx::AppRetCode retCode  = AcRxArxApp::On_kUnloadAppMsg (pkt) ;
  142.     acedUndef(_T("CopyMultiple" ),1000);
  143.     return  (retCode) ;
  144.   }
  145.  
  146.   virtual  void  RegisterServerComponents()
  147.   {
  148.   }
  149. };

 

Так это выгдядит:

 

 

Источник: http://adndevblog.typepad.com/autocad/2015/04/implementing-copy-multiple-entities-with-a-twist-.html

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

Обсуждение: http://adn-cis.org/forum/index.php?topic=2697

Опубликовано 12.05.2015