Получение габаритного контейнера сплайна с помощью ObjectARX
Вопрос:
Я хочу получить габаритный контейнер сплайна, но метод getGeomExtents() дает неточные результаты. Как можно получить точный габаритный контейнер для сплайна?
Ответ:
Для AcDbSpline метод getGeomExtents() возвращает неточный габаритный контейнер, т.к. вычисление точного контейнера сопряжено с временными тратами.
Чтобы получить точный габаритный контейнер вам придется вычислить его самостоятельно. Вы можете воспользоваться методом getPointAtParam() для прохода по сплайну и вычисления максимальных/минимальных координат X и Y. Точность вычисления габаритного контейнера зависит от того насколько частей кривая поделена. Коэффициент 1e6 даёт приемлемую точность и допустимое время для подсчета. Функции показанные ниже показывают как это можно сделать. Запустите команду SplineBB и выберите сплайн. Команда нарисует два габаритных контейнера. Красный возвращает метод getGeomExtents(), а желтый – это тот, который мы вычислили.
Как-то так:
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Описание: fKeepExtremes
- // 1) Функция проверяет минимум и максимум X и Y.
- // 2) mPtMin и mPtMax получат минимум/максимум X и Y
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void fKeepExtremes(AcGePoint3d& mPtSample,AcGePoint3d& mPtMin,AcGePoint3d& mPtMax)
- {
- //test for max
- if(mPtSample.x > mPtMax.x) mPtMax.x = mPtSample.x;
- if(mPtSample.y > mPtMax.y) mPtMax.y = mPtSample.y;
- if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
- //test for min
- if(mPtSample.x < mPtMin.x) mPtMin.x = mPtSample.x;
- if(mPtSample.y < mPtMin.y) mPtMin.y = mPtSample.y;
- if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Описание: fGetBoundingBoxBySampling
- // 1) Функция делит AcDbSpline на 1e6 частей и вычисляет точки
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void fGetBoundingBoxBySampling(AcDbSpline *pSpline,AcGePoint3d& mPtMin, AcGePoint3d& mPtMax)
- {
- double mParam;
- double mIncr;
- double mStartParam;
- double mEndParam;
- AcGePoint3d mPtTemp;
- pSpline->getStartPoint(mPtTemp);
- pSpline->getParamAtPoint(mPtTemp,mStartParam);
- pSpline->getEndPoint(mPtTemp);
- pSpline->getParamAtPoint(mPtTemp,mEndParam);
- // вычисляем деление
- mIncr = (mEndParam - mStartParam)/1e6; // 1e6 коэффициент деления
- // устанавливаем затравочные точки для минимумуа и максимума
- mPtMax = mPtTemp;
- mPtMin = mPtTemp;
- for(mParam = mStartParam;mParam <= mEndParam;mParam +=mIncr)
- {
- if(Acad::eOk == pSpline->getPointAtParam(mParam,mPtTemp))
- {
- fKeepExtremes(mPtTemp,mPtMin,mPtMax);
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Описание: fDrawRect
- // 1) Рисуем прямоугольник с помощью LwPolyline указывая нижнюю левую и верхнюю правую точки
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void fDrawRect(AcGePoint3d& mPtMin,AcGePoint3d& mPtMax,int mColor)
- {
- AcDbPolyline *pPline = new AcDbPolyline(4);
- pPline->addVertexAt(0, AcGePoint2d(mPtMin.x,mPtMin.y));
- pPline->addVertexAt(1,AcGePoint2d(mPtMax.x,mPtMin.y));
- pPline->addVertexAt(2,AcGePoint2d(mPtMax.x,mPtMax.y));
- pPline->addVertexAt(3,AcGePoint2d(mPtMin.x,mPtMax.y));
- pPline->setClosed(Adesk::kTrue);
- fAddEntToDwg(acdbHostApplicationServices()->workingDatabase(),pPline);
- pPline->setColorIndex(mColor);
- pPline->close();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////
- // Описание: SplineBB
- // 1) команда 'SplineBB'
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void SplineBB()
- {
- AcDbEntity *pEnt = NULL;
- AcDbObjectId mId;
- ads_point mPt;
- ads_name mEname;
- //select the entity
- if ( RTNORM == acedEntSel(L"\nВыберите Сплайн: ", mEname, mPt))
- {
- if ( Acad::eOk == acdbGetObjectId(mId, mEname ))
- {
- acdbOpenAcDbEntity(pEnt, mId, AcDb::kForRead);
- }
- }
- else
- {
- return;
- }
- // Проверяем сплайн ли это
- AcDbSpline *pSpline = NULL;
- if (NULL != pEnt)
- {
- pSpline = AcDbSpline::cast(pEnt);
- if(NULL != pSpline)
- {
- AcGePoint3d mPtMin,mPtMax;
- // Рисуем габаритный контейнер, возвращаемый методом getGeomExtents
- AcDbExtents mExts;
- pSpline->getGeomExtents(mExts);
- // Рисуем расчитанный габаритный контейнер красным цветом
- fDrawRect(mExts.minPoint(),mExts.maxPoint(),1);
- // Вычисляем начальное время
- struct _timeb t1,t2;
- _ftime(&t1);
- // Вычисляем габаритный контейнер
- fGetBoundingBoxBySampling(pSpline,mPtMin,mPtMax);
- _ftime(&t2);
- acutPrintf(L"\nВремя работы метода %6.2f секунд.\n",
- (t2.time + (double)(t2.millitm)/1000) -
- (t1.time + (double)(t1.millitm)/1000) );
- //draw calculated bounding box in yellow
- fDrawRect(mPtMin,mPtMax,2);
- pSpline->close();
- }
- else
- {
- acutPrintf(L"\nЭто не сплайн");
- pEnt->close();
- }
- }
- return;
- }
Обсуждение: http://adn-cis.org/forum/index.php?topic=1009
Опубликовано 09.10.2014