Тема: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

Здравствуйте все!
Пишу код, работающий с 2d-полилинией и столкнулся с несколькими проблемами:
1) AcDb2dPolyline создаётся в памяти самостоятельно, а редактировать геометрию можно только через AcDb2dVertex.
2) AcDb2dVertex::position() возращает AcGePoint3d() (3d у них получилось исторически), но якобы в OSC (то есть ECS), а не WCS. Для получения AcGePoint3d() в WCS рекомендуют использовать AcDb2dPolyline::vertexPosition(const AcDb2dVertex& vert). Те, кто видели пример итерирования полилинии могут оценить прелести этой рекомендации Autodesk. Собрал небольшой тест который даёт распечатку координат возращаемых точек и узрел, что разницы почему-то не наблюдается ... Может опытные коллеги подскажут в чём фишка ...
3) Замечательный метод transformBy() работает с оригиналом, из-за этого каждый раз накапливается незначительная ошибка. Попытки  свести общую ошибку к минимуму натолкнули на мысль применять transformBy() к начальному состоянию полилинии, но как выяснилось скопировать в память её нельзя, потому как объект составной и поэтому нужно применять deep cloning (без горячительного не разобраться) после чего можно получить клон, но кажется опять в базе, а мне бы хотелось поместить его в память, чтобы не открывать и закрывать его каждый раз, когда понадобиться начальное состояние...
Прошу прощения за некраткость. Буду раз любым комментариям.

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> Сергей
1) Да. AcDb2Polyline - это составной объект и это обуславливает специфику работы с ним.
2) Большой сложности в итерировании по вершинам полилинии - не вижу.
Твой тест не полный. Если ECS полилинии != WCS, то координаты могут получится разными, так что документация не врет. Для примера:

a) Команда: _UCS _w
b) Команда: _UCS _o 0,0,100
c) затем нарисуй 2d-полилинию командой _PLINE (не забудь, что plinetype должна быть равна 0).
d) Потестируй ее... Результаты тебя удивят.
Это уже не говоря о возмоожностях поворота системы координат.

3) По поводу накопления ошибки - не очень понял что ты такое делаешь с ней, что накапливается ошибка.
А почему бы тебе не воспользоваться классом AcDbPolyline (т.е. облегченной полилинией)? Это простой примитив. И копировать можно и вершины легче находить...

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

Пока что результаты не удивили ...
Тестировал этим:
ads_name en;
AcGePoint3d startPt;
acedEntSel("\nSelect an entity: ", en, asDblArray(startPt));
AcDbObjectId eId;
        acdbGetObjectId(eId, en);
        AcDbEntity* pEnt;
        if(Acad::eOk != acdbOpenObject(pEnt, eId, AcDb::kForRead))
            return;
        if (pEnt->isA() == AcDb2dPolyline::desc())
        {
            acutPrintf("\nОна самая ...");
            AcDbObjectIterator *pVertIter = ((AcDb2dPolyline*)pEnt)->vertexIterator();
            AcDb2dVertex *pVertex;
            AcDbObjectId vertexObjId;
            for (int vertexNumber = 0; !pVertIter->done();
                vertexNumber++, pVertIter->step())
            {
                vertexObjId = pVertIter->objectId();
                acdbOpenObject(pVertex, vertexObjId,
                    AcDb::kForRead);
                AcGePoint3d pt1 = (((AcDb2dPolyline*)pEnt)->vertexPosition((*pVertex)));
                AcGePoint3d pt2 = pVertex->position();
                acutPrintf("\nwX = %f, wY = %f, wZ = %f, eX = %f, eY = %f, eZ = %f",
                    pt1.x, pt1.y, pt1.z, pt2.x, pt2.y, pt2.z);
                pVertex->close();
            }
            delete pVertIter;
            pEnt->close();
        }
        else
        {
            acutPrintf("\nЭто не AcDb2dPolyline!!!");
            pEnt->close();
        }

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> Сергей
А я тестировал такой функцией:

Acad::ErrorStatus get_points_from_2dpoly(AcDb2dPolyline* pline,AcGePoint3dArray& pts1,AcGePoint3dArray& pts2)
{
  Acad::ErrorStatus es = Acad::eOk;
  AcDb2dVertex*  vert   = NULL;
  AcDbObjectId   vId;
  AcDbObjectIterator *vIter;
  vIter = pline->vertexIterator();
  for (; !vIter->done(); vIter->step()) {
    vId = vIter->objectId();
    pline->openVertex(vert, vId, AcDb::kForRead);
    pts1.append(pline->vertexPosition(*vert)); // 1
    pts2.append(vert->position());             // 2
    vert->close();
  }
  delete vIter;
  return es;
}
void TestPoly(void)
{
  ads_name en; ads_point p;
  Acad::ErrorStatus es;
  if (acedEntSel("\nУкажите 2D-полилинию: ",en,p) == RTNORM) {
    AcDbObjectId eid; acdbGetObjectId(eid,en);
    AcDbObjectPointer<AcDb2dPolyline> pPline(eid,AcDb::kForRead);
    if ((es = pPline.openStatus()) == Acad::eOk) {
      AcGePoint3dArray pts1,pts2;
      get_points_from_2dpoly(pPline.object(),pts1,pts2);
      for (int i=0; i < min(pts1.length(),pts2.length()); i++) {
        acutPrintf("\npts[%d]=(%g %g %g) (%g %g %g)",i,
          pts1[i].x,pts1[i].y,pts1[i].z,
          pts2[i].x,pts2[i].y,pts2[i].z);
      }
    } else {
      acutPrintf("\nError pPline.openStatus: %s",acadErrorStatusText(es));
    }
  }
}

Обрати внимание как я строил и на результаты (координата Z для точек pts[1],pts[2],pts[3]):

Command: ucs
Current ucs name:  *WORLD*
Enter an option [New/Move/orthoGraphic/Prev/Restore/Save/Del/Apply/?/World] <World>: _o
Specify new origin point <0,0,0>: 0,0,100
Command: _pline
Specify start point:  0,0
Current line-width is 0.0000
Specify next point or [Arc/Halfwidth/Length/Undo/Width]: 0,100
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: 100,100
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: 100,0
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: _c
Command: testpoly
Укажите 2D-полилинию:
pts[0]=(0.000000 0.000000 [b]100.000000[/b]) (0.000000 0.000000 [b]100.000000[/b])
pts[1]=(0.000000 100.000000 [b]100.000000[/b]) (0.000000 100.000000 [b]0.000000[/b])
pts[2]=(100.000000 100.000000 [b]100.000000[/b]) (100.000000 100.000000 [b]0.000000[/b])
pts[3]=(100.000000 0.000000 [b]100.000000[/b]) (100.000000 0.000000 [b]0.000000[/b])

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

А вот еще более разительный пример:

Command: _vpoint
Current view direction:  VIEWDIR=0.0000,0.0000,1.0000
Specify a view point or [Rotate] <display compass and tripod>: 1,1,1
Regenerating model.
Command: _ucs
Current ucs name:  *WORLD*
Enter an option [New/Move/orthoGraphic/Prev/Restore/Save/Del/Apply/?/World]
<World>: _v
Command: _ucs
Current ucs name:  *NO NAME*
Enter an option [New/Move/orthoGraphic/Prev/Restore/Save/Del/Apply/?/World]
<World>: _o
Specify new origin point <0,0,0>: 0,0,100
Command: _pline
Specify start point: 0,0
Current line-width is 0.0000
Specify next point or [Arc/Halfwidth/Length/Undo/Width]: 0,100
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: 100,100
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: 100,0
Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: _c
Command: testpoly
Укажите 2D-полилинию:
pts[0]=(57.735027 57.735027 57.735027) (0.000000 0.000000 100.000000)
pts[1]=(16.910198 16.910198 139.384685) (0.000000 100.000000 0.000000)
pts[2]=(-53.800480 87.620876 139.384685) (100.000000 100.000000 0.000000)
pts[3]=(-12.975651 128.445705 57.735027) (100.000000 0.000000 0.000000)

Тоже не удивляет? :)

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

А можно встречный вопрос.
почему не пользоваться AcDbPolyline?
Она ничем не хуже, но очень проста в использовании.
Мне пришлось столкнуться с AcDb3dPolyline, это был кошмар! Самое безобидное действие, типа "getEndPoint" могло завершиться страшным сообщением eWasErased, потому что вершина была удалена. И таких фокусов было столько что...
Очень советую, отказывайся от этого класса пока не поздно

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> ROMA
Я уже этот вопрос задавал Сергею, но он его проигнорировал: https://www.caduser.ru/forum/topic24246.html
Но вообще-то AcDbPolyline не всегда способна заменить AcDb2dPolyline. Обрати внимание на типы полилиний, которые поддерживает AcDb2dPolyline:

k2dSimplePoly  - A standard polyline with no curve/spline fitting. Только этот вариант поддерживается AcDbPolyline.
k2dFitCurvePoly - A polyline that has been curve fit. This reflects that the second bit of DXF group code 70 is set.
k2dQuadSplinePoly - A spline-fit polyline that has a Quadratic B-spline path. This reflects that the third bit of DXF group code 70 is set and that DXF group code 75 is set to 5.
k2dCubicSplinePoly  A spline-fit polyline that has a Cubic B-spline path. This reflects that the third bit of DXF group code 70 is set and that DXF group code 75 is set to 6.
..............................
Functionality and command options not available in a lightweight polyline include:
- Arc Fit curve data
- Spline Fit data
- Curve fit tangent direction data

Так что если используются только простые полилинии, то можно смело менять на AcDbPolyline, а если нет - то увы...

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> Александр
Ривилис
Простите Александр, что не ответил на вопрос.
Я работаю сейчас с Land Development Desktop, который Autodesk "унаследовал" вместе с кодом продукта у компании с одноимённым названием Softdesk. И как всегда, "исторически" сложилось, что спираль (в частности клотоида) базируется на AcDb2dPolyline, со всеми вытекающими для меня последствиями ... Не хочу нарушать совместимость, поэтому следую принципу "исторически...
Почти закончил возню с этим замечательным объектом, но немогу реализовать откат последствий transformBy(). Похоже без deep cloning не обойтись. Подскажите кто-нибудь как запихать клон в память для манипуляций, оставив в покое оригинал AcDb2dPolyline, находящийся в базе *.dwg.
Спасибо всем!

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> Сергей
Сделай ее клон в виде AcDbPolyline в память:

AcDb2dPolyline *p2dPoly; // Считаем, что указатель уже ссылается на твою полилинию
AcDbPolyline *pPoly = new AcDbPolyline(); // Будующий клон
pPoly->convertFrom(p2dPoly,Adesk::kFalse); // Выполнили клонирование в память.

Дальше "играешься" с pPoly, как только тебе нравится. По окончанию "игры" получишь матрицу преобразования, выполнишь p2dPoly->transformBy(...) и delete pPoly.
Годится?

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

Здравствуйте все!
> Александр Ривилис
Клон в памяти получился, только пришлось повозиться с convertFrom()
В SDK написанотак:
Acad::ErrorStatus convertFrom(AcDbEntity*& pPline, ...);
pPline Input pointer to the AcDb2dPolyline to copy from
В декларации принимается AcDbEntity*, в пояснении AcDb2dPolyline*... Как хочешь - так и понимай. Выячнил, что если передавать AcDb2dPolyline*, компилятор выдаёт ошибку: cannot convert from AcDb2dPolyline* to AcDb2dPolyline*&.
Если предварительно сделать преобразование(AcDbEntity*)p2dPline и присвоить результат AcDbEntity* pEnt, то convertFrom() успешно проглатывает pEnt.
Клон таскается, но клонируется всё кроме толщины полилинии. Сделаю принудительно.
Спасибо за подсказку!

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> Сергей
:)

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

кто-нибудь знает, по какому алгоритму делается curve fit в AcDb2dPolyline?

Re: Как пользоваться AcDb2dPolyline и AcDb2dVertex?

> danone
1) Это секрет Autodesk.
2) А зачем нужен этот алгоритм?