Тема: Проблемы с вызовом функции align через acedCommand

Под 2005 (и 2002 вторым тоже самое) запускаю:
acedCommand(RTSTR, "_align", 0);
Функция запускается, всё спрашивает, но, в итоге, ничего не делает sad Если запустить align вручную, то всё нормально. Вообще в толк не возьму в чём может быть проблема. Другие функции  через acedCommand у меня в том же месте нормально отрабатывают...

Re: Проблемы с вызовом функции align через acedCommand

> archimag
А можно кусочек кода "побольше"? Ведь если команда запускается именно так и больше нет ни одной acedCommand, то AutoCAD все остальное будет запрашивать уже после завершения команды(функции), в которой ты вызываешь acedCommand(RTSTR, "_align", 0); И тогда по логике никакой разницы нет между вызовом команды вручную и из твоей программы.

Re: Проблемы с вызовом функции align через acedCommand

> Александр Ривилис
void myalign(void) {
   acedCommand(RTSTR, "_align", 0);
}
Всё! У меня проблемы даже вот этим кодом (конечно, я не хочу немного другое) и я несколько озадачен...

Re: Проблемы с вызовом функции align через acedCommand

Разобрался, команда align зарегестрирована arx модулем и, согласно документации, её нельзя вызвать с помощью acedCommand sad
Такой вопрос, можно ли как-нибудь её всё таки вызвать? sendStringToExecute не подходит, ибо там нет нормальной возможности передавать в функцию параметры...

Re: Проблемы с вызовом функции align через acedCommand

archimag пишет:

команда align зарегестрирована arx модулем и, согласно документации, её нельзя вызвать с помощью acedCommand sad

Я такого в докуметации не находил. :) Она зарегистрирована как команда и поэтому может выполняться с использованием acedCommand. А то что она так не работает - это особенность реализации именно команды ALIGN.

Re: Проблемы с вызовом функции align через acedCommand

P.S.: Самый оптимальный вариант - это использовать средства ObjectARX для преобразования примитивов (при помощи transformBy()), а именно:
1) получить матрицу поворота и применить ее.
2) получить матрицу масштабирования и применить ее.
3) получить матрицу переноса и применить ее.

Re: Проблемы с вызовом функции align через acedCommand

> Александр Ривилис
В итоге, пришлось программно формировать соответствующее Лисп-выражения и отправлять его через sendStringToExecute...

Re: Проблемы с вызовом функции align через acedCommand

:( Я бы так делать не стал. Если нужен пример с использованием transformBy() - напиши. Пришлю.

Re: Проблемы с вызовом функции align через acedCommand

> archimag
Нехорошо это, однако. Свой собственный align пишется в течении одного дня (с отладкой и доп. функциональностью).

Re: Проблемы с вызовом функции align через acedCommand

> Александр Ривилис

> Exhumer
Свой собственный align, в итоге, я написал за 30 минут smile Перед этим потратив день на борьбу со стандартной align, которую так и не смог заставить правильно работать: делаю руками - нормально, вызываю тоже самое из Lisp - косяки...

Re: Проблемы с вызовом функции align через acedCommand

> archimag
biggrin Вот это правильно!

Re: Проблемы с вызовом функции align через acedCommand

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

1) получить матрицу поворота и применить ее.
2) получить матрицу масштабирования и применить ее.
3) получить матрицу переноса и применить ее.

с пунктами 2 и 3 все просто как апельсин.
А как повернуть объект в заданную тремя точками плоскость?
В документации говорится что поворачивать нужно три раза: XY, XZ, YZ.
И тут как раз проблема. Точки три, а вектор нужен один

// для XZ
AcGePlane plane = AcGePlane::kZXPlane;
vect = vect.orthoProject(plane.normal());
double angle = vect.angleTo(AcGeVector3d::kZAxis);

ну и так для остольных осей
В общем я запутался :(
Что делать?

Re: Проблемы с вызовом функции align через acedCommand

> Николай
Что-то ты перемудрил (мне так кажется):

static void ALIGN1(void)
{
    ads_name en; ads_point p1; ads_point p2;
    if (acedEntSel(_T("\nВыберите объект: "),en,p1)           != RTNORM ||
        acedGetPoint(NULL,_T("\nПервая исходная точка: "),p1) != RTNORM ||
        acedGetPoint(p1,  _T("\nПервая целевая точка: "),p2)  != RTNORM) return;
    AcGePoint3d pSrcPt1(p1[X],p1[Y],p1[Z]); AcGePoint3d pDestPt1(p2[X],p2[Y],p2[Z]);
    if (acedGetPoint(NULL,_T("\nВторая исходная точка: "),p1) != RTNORM ||
        acedGetPoint(p1,  _T("\nВторая целевая точка: "),p2)  != RTNORM) return;
    AcGePoint3d pSrcPt2(p1[X],p1[Y],p1[Z]); AcGePoint3d pDestPt2(p2[X],p2[Y],p2[Z]);
    AcGeVector3d v1(pSrcPt1 - pSrcPt2); AcGeVector3d v2(pDestPt1 - pDestPt2);
    AcDbObjectId id; acdbGetObjectId(id,en);
    AcDbEntityPointer pEnt(id,AcDb::kForWrite);
    if (pEnt.openStatus() != Acad::eOk) return;
    AcGeMatrix3d mMatScale; AcGeMatrix3d mMatRot; AcGeMatrix3d mMatResul;
    mMatRot = v1.rotateTo(v2);
    mMatScale.setToScaling(v2.length()/v1.length()); mMatResul = mMatRot * mMatScale;
    pSrcPt1.transformBy(mMatResul);
    mMatResul.setTranslation(pDestPt1 - pSrcPt1);
    pEnt->transformBy(mMatResul);
    pEnt->close();
}

Re: Проблемы с вызовом функции align через acedCommand

> Александр Ривилис
Дело в том, что есть полилиния 3d, и ее нужно повернуть с масштабированием в заданную плоскость. А вот плоскость задается тремя точками а не двумя. Да и в команде _align есть возможность работать с тремя точками.

Re: Проблемы с вызовом функции align через acedCommand

> Николай
Почитай справку к команде _align - если заданы три пары точек, то возможен только поворот и перенос - масштабирование невозможно. Если заданы две пары точек, то возможны и перенос, и масштабирование, и поворот.

Re: Проблемы с вызовом функции align через acedCommand

именно в _align это можно делать в два этапа.
сразу по двум точкам отмасштабировать и перенести, а потом по трем точкам повернуть.
Я ж так и написал, что проблема только с формированием матрицы по трем точкам для поворота. А остальное у меня работает. Вот.

Re: Проблемы с вызовом функции align через acedCommand

Вот мой вариант.
ptArrayIn - начальные 3 точки
ptArrayOut - конечные 3 точки

ads_point p1,p2,p11,p22,p3,p33;
double angle,scale;
p1[X] = ptArrayIn.at(0).x;    p1[Y] = ptArrayIn.at(0).y;    p1[Z] = ptArrayIn.at(0).z;
p2[X] = ptArrayIn.at(1).x;    p2[Y] = ptArrayIn.at(1).y;    p2[Z] = ptArrayIn.at(1).z;
p3[X] = ptArrayIn.at(2).x;    p3[Y] = ptArrayIn.at(2).y;    p3[Z] = ptArrayIn.at(2).z;
p11[X] = ptArrayOut.at(0).x;    p11[Y] = ptArrayOut.at(0).y;    p11[Z] = ptArrayOut.at(0).z;
p22[X] = ptArrayOut.at(1).x;    p22[Y] = ptArrayOut.at(1).y;    p22[Z] = ptArrayOut.at(1).z;
p33[X] = ptArrayOut.at(2).x;    p33[Y] = ptArrayOut.at(2).y;    p33[Z] = ptArrayOut.at(2).z;
scale = ads_distance(p11, p22) / ads_distance(p1, p2);
AcGeMatrix3d mat;
AcGeVector3d vec;
vec.set(p11[X]-p1[X],p11[Y]-p1[Y],p11[Z]-p1[Z]);
AcGePoint3dArray ptArr; ptArr.setLogicalLength(0);
AcDbObjectId oId;
//...
//рисуем полилинию точками ptArr, на возврат идет oId
//...
AcDbEntity* entObj;
if(acdbOpenObject(entObj, oId, AcDb::kForWrite) != Acad::eOk) return;
mat.setToIdentity();mat.setTranslation(vec);entObj->transformBy(mat);
mat.setToIdentity();mat.setToScaling(scale,AcGePoint3d(p11[X],p11[Y],p11[Z]));entObj->transformBy(mat);
// а тут еще поворот по трем точкам
entObj->close();

Во как раз поворота мне и не хватает

Re: Проблемы с вызовом функции align через acedCommand

Из help'а:

The selected objects move from the source point (1) to the destination point (2).
The selected object is rotated (1 and 3) so that it aligns with the destination object (2 and 4).
The selected object is then rotated again (3 and 5) so that it aligns with the destination object (4 and 6).

Вывод: нужно сделать один перенос и два поворота. Как получить матрицу поворота - смотри в моем примере.

Re: Проблемы с вызовом функции align через acedCommand

Что-то оно поворачивает, но совсем не так как надо (в матрицах у меня совсем глухо :( )

...
AcGeVector3d v1(pSrcPt1 - pSrcPt2); // вектор между точками 1 и 2 исходными
AcGeVector3d v2(pDestPt1 - pDestPt2); // вектор между точками 1 и 2 новыми
AcGeVector3d v3(pSrcPt2 - pSrcPt3); // вектор между точками 2 и 3 исходными
AcGeVector3d v4(pDestPt2 - pDestPt3); // вектор между точками 2 и 3 новыми
AcDbEntity* entObj;
if(acdbOpenObject(entObj,oId,AcDb::kForWrite)!= Acad::eOk) return;
AcGeMatrix3d mMatScale; AcGeMatrix3d mMatRot; AcGeMatrix3d mMatResul; AcGeMatrix3d mMatRot2;
mMatRot = v1.rotateTo(v2); // поворот по первым двум точкам
mMatRot2 = v3.rotateTo(v4); // поворот по точкам 2 и 3
mMatScale.setToScaling(v2.length()/v1.length()); mMatResul = mMatRot * mMatRot2 * mMatScale;
pSrcPt1.transformBy(mMatResul);
mMatResul.setTranslation(pDestPt1 - pSrcPt1);
entObj->transformBy(mMatResul);
...

Re: Проблемы с вызовом функции align через acedCommand

> Николай
Практически не тестировал, но вроде работает:

static void ALIGN3(void)
{
  ads_name en; ads_point p1; ads_point p2;
  if (acedEntSel(_T("\nВыберите объект: "),en,p1)         != RTNORM ||
    acedGetPoint(NULL,_T("\nПервая исходная точка: "),p1) != RTNORM ||
    acedGetPoint(p1,  _T("\nПервая целевая точка: "), p2) != RTNORM) return;
  acdbUcs2Wcs(p1,p1,false); acdbUcs2Wcs(p2,p2,false);
  AcGePoint3d pSrcPt1(p1[X],p1[Y],p1[Z]); AcGePoint3d pDestPt1(p2[X],p2[Y],p2[Z]);
  if (acedGetPoint(NULL,_T("\nВторая исходная точка: "),p1) != RTNORM ||
      acedGetPoint(p1,  _T("\nВторая целевая точка: "), p2) != RTNORM) return;
  acdbUcs2Wcs(p1,p1,false); acdbUcs2Wcs(p2,p2,false);
  AcGePoint3d pSrcPt2(p1[X],p1[Y],p1[Z]); AcGePoint3d pDestPt2(p2[X],p2[Y],p2[Z]);
  if (acedGetPoint(NULL,_T("\nТретья исходная точка: "),p1) != RTNORM ||
      acedGetPoint(p1,  _T("\nТретья целевая точка: "), p2) != RTNORM) return;
  acdbUcs2Wcs(p1,p1,false); acdbUcs2Wcs(p2,p2,false);
  AcGePoint3d pSrcPt3(p1[X],p1[Y],p1[Z]); AcGePoint3d pDestPt3(p2[X],p2[Y],p2[Z]);
  AcGeVector3d v1(pSrcPt1  - pSrcPt2);
  AcGeVector3d v2(pDestPt1 - pDestPt2);
  AcDbObjectId id; acdbGetObjectId(id,en);
  AcDbEntityPointer pEnt(id,AcDb::kForWrite);
  if (pEnt.openStatus() != Acad::eOk) return;
  AcGeMatrix3d mMatScale, mMatRot, mMatTrans;
  mMatScale.setToScaling(v2.length()/v1.length(),pSrcPt1);
  pEnt->transformBy(mMatScale); // Масштабируем
  AcGePlane pl1(pSrcPt1,pSrcPt1-pSrcPt2,pSrcPt1-pSrcPt3),
            pl2(pDestPt1,pDestPt1-pDestPt2,pDestPt1-pDestPt3);
  AcGePoint3d pOrig1,pOrig2; AcGeVector3d vX1,vX2,vY1,vY2,vZ1,vZ2;
  pl1.getCoordSystem(pOrig1,vX1,vY1); pl2.getCoordSystem(pOrig2,vX2,vY2);
  mMatTrans.setToAlignCoordSys(pSrcPt1,vX1,vY1,pl1.normal(),pDestPt1,vX2,vY2,pl2.normal());
  pEnt->transformBy(mMatTrans); // Остальные преобразования
  pEnt->close();
}

Re: Проблемы с вызовом функции align через acedCommand

Да, все работает.
Спасибо за помощь.
Кстати, на будущее, можно ли почитать про матрицы преобразований и о том как ими пользоваться где-то кроме хелпа arx, или это только опытным путем :) ?

Re: Проблемы с вызовом функции align через acedCommand

> Николай
Help, опытный путь и изучение теории векторных/матричных преобразований, аналитической геометрии и т.д.