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

09/10/2014

Получение габаритного контейнера сплайна с помощью ObjectARX

Вопрос:

Я хочу получить габаритный контейнер сплайна, но метод getGeomExtents() дает неточные результаты. Как можно получить точный габаритный контейнер для сплайна?

Ответ:

Для AcDbSpline метод getGeomExtents() возвращает неточный габаритный контейнер, т.к. вычисление точного контейнера сопряжено с временными тратами.

Чтобы получить точный габаритный контейнер вам придется вычислить его самостоятельно. Вы можете воспользоваться методом getPointAtParam() для прохода по сплайну и вычисления максимальных/минимальных координат X и Y. Точность вычисления габаритного контейнера зависит от того насколько частей кривая поделена. Коэффициент  1e6 даёт приемлемую точность и допустимое время для подсчета. Функции показанные ниже показывают как это можно сделать.  Запустите команду SplineBB и выберите сплайн. Команда нарисует два габаритных контейнера. Красный возвращает метод getGeomExtents(), а желтый – это тот, который мы вычислили.

Как-то так:

Код - C++: [Выделить]
  1. ///////////////////////////////////////////////////////////////////////////////////////////////
  2. // Описание: fKeepExtremes
  3. // 1) Функция проверяет минимум и максимум X и Y.
  4. // 2) mPtMin и mPtMax получат минимум/максимум X и Y
  5. ///////////////////////////////////////////////////////////////////////////////////////////////
  6.  
  7. void fKeepExtremes(AcGePoint3d& mPtSample,AcGePoint3d& mPtMin,AcGePoint3d& mPtMax)
  8. {
  9.  //test for max
  10.  if(mPtSample.x > mPtMax.x) mPtMax.x = mPtSample.x;
  11.  if(mPtSample.y > mPtMax.y) mPtMax.y = mPtSample.y;
  12.  if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
  13.  
  14.  //test for min
  15.  if(mPtSample.x < mPtMin.x) mPtMin.x = mPtSample.x;
  16.  if(mPtSample.y < mPtMin.y) mPtMin.y = mPtSample.y;
  17.  if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
  18. }
  19.  
  20. ///////////////////////////////////////////////////////////////////////////////////////////////
  21. // Описание: fGetBoundingBoxBySampling
  22. // 1) Функция делит AcDbSpline на 1e6 частей и вычисляет точки
  23. ///////////////////////////////////////////////////////////////////////////////////////////////
  24. void fGetBoundingBoxBySampling(AcDbSpline *pSpline,AcGePoint3d& mPtMin, AcGePoint3d& mPtMax)
  25. {
  26.  double mParam;
  27.  double mIncr;
  28.  
  29.  double mStartParam;
  30.  double mEndParam;
  31.  
  32.  AcGePoint3d mPtTemp;
  33.  pSpline->getStartPoint(mPtTemp);
  34.  pSpline->getParamAtPoint(mPtTemp,mStartParam);
  35.  
  36.  pSpline->getEndPoint(mPtTemp);
  37.  pSpline->getParamAtPoint(mPtTemp,mEndParam);
  38.  
  39.  // вычисляем деление
  40.  mIncr = (mEndParam - mStartParam)/1e6; // 1e6 коэффициент деления
  41.  
  42.  // устанавливаем затравочные точки для минимумуа и максимума
  43.  mPtMax = mPtTemp;
  44.  mPtMin = mPtTemp;
  45.  
  46.  for(mParam = mStartParam;mParam <= mEndParam;mParam +=mIncr)
  47.  {
  48.   if(Acad::eOk == pSpline->getPointAtParam(mParam,mPtTemp))
  49.   {
  50.    fKeepExtremes(mPtTemp,mPtMin,mPtMax);
  51.   }
  52.  
  53.  }
  54. }
  55.  
  56. ///////////////////////////////////////////////////////////////////////////////////////////////
  57. // Описание: fDrawRect
  58. // 1) Рисуем прямоугольник с помощью LwPolyline указывая нижнюю левую и верхнюю правую точки
  59. ///////////////////////////////////////////////////////////////////////////////////////////////
  60. void fDrawRect(AcGePoint3d& mPtMin,AcGePoint3d& mPtMax,int mColor)
  61. {
  62.  AcDbPolyline *pPline = new AcDbPolyline(4);
  63.  pPline->addVertexAt(0, AcGePoint2d(mPtMin.x,mPtMin.y));
  64.  pPline->addVertexAt(1,AcGePoint2d(mPtMax.x,mPtMin.y));
  65.  pPline->addVertexAt(2,AcGePoint2d(mPtMax.x,mPtMax.y));
  66.  pPline->addVertexAt(3,AcGePoint2d(mPtMin.x,mPtMax.y));
  67.  pPline->setClosed(Adesk::kTrue);
  68.  
  69.  fAddEntToDwg(acdbHostApplicationServices()->workingDatabase(),pPline);
  70.  pPline->setColorIndex(mColor);
  71.  pPline->close();
  72. }
  73.  
  74. ///////////////////////////////////////////////////////////////////////////////////////////////
  75. // Описание: SplineBB
  76. // 1) команда 'SplineBB'
  77. ///////////////////////////////////////////////////////////////////////////////////////////////
  78. void SplineBB()
  79. {
  80.  AcDbEntity *pEnt = NULL;
  81.  AcDbObjectId mId;
  82.  ads_point mPt;
  83.  ads_name mEname;
  84.  
  85.  //select the entity
  86.  if ( RTNORM == acedEntSel(L"\nВыберите Сплайн: ", mEname, mPt))
  87.  {
  88.   if ( Acad::eOk == acdbGetObjectId(mId, mEname ))
  89.   {
  90.    acdbOpenAcDbEntity(pEnt, mId, AcDb::kForRead);
  91.   }
  92.  }
  93.  else
  94.  {
  95.   return;
  96.  }
  97.  
  98.  // Проверяем сплайн ли это
  99.  AcDbSpline *pSpline = NULL;
  100.  
  101.  if (NULL != pEnt)
  102.  {
  103.   pSpline = AcDbSpline::cast(pEnt);
  104.  
  105.   if(NULL != pSpline)
  106.   {
  107.    AcGePoint3d mPtMin,mPtMax;
  108.  
  109.    // Рисуем габаритный контейнер, возвращаемый методом getGeomExtents
  110.    AcDbExtents mExts;
  111.    pSpline->getGeomExtents(mExts);
  112.  
  113.    // Рисуем расчитанный габаритный контейнер красным цветом
  114.    fDrawRect(mExts.minPoint(),mExts.maxPoint(),1);
  115.   
  116.    // Вычисляем начальное время
  117.    struct _timeb t1,t2;
  118.    _ftime(&t1);
  119.  
  120.    // Вычисляем габаритный контейнер
  121.    fGetBoundingBoxBySampling(pSpline,mPtMin,mPtMax);
  122.   
  123.    _ftime(&t2);
  124.    acutPrintf(L"\nВремя работы метода %6.2f секунд.\n",
  125.       (t2.time + (double)(t2.millitm)/1000) -
  126.       (t1.time + (double)(t1.millitm)/1000) );
  127.   
  128.    //draw calculated bounding box in yellow
  129.    fDrawRect(mPtMin,mPtMax,2);
  130.  
  131.    pSpline->close();
  132.   }
  133.   else
  134.   {
  135.    acutPrintf(L"\nЭто не сплайн");
  136.    pEnt->close();
  137.   }
  138.  }
  139.  return;
  140. }

Источник: http://adndevblog.typepad.com/autocad/2013/01/obtaining-the-bounding-box-of-an-acdbspline-using-objectarx.html

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

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