Тема: Как программно сделать offset?

Есть такой метод у AcDbCurve
virtual Acad::ErrorStatus
getOffsetCurves(
double offsetDist,
AcDbVoidPtrArray& offsetCurves) const;
Но что то я не могу понять как указать напрвление сдвига. Т.е. кривую можно сдвинуть вправо или влево "от своего направления" на заданную дистанцию...
В команде offset для кривых - запрашивается offsetDist, кривая которую надо сдвинуть и точка для определения в какую сторону сдвигать - а в програмном методе этого нет...
Как можно программно задать направление сдвига кривой - вправо/влево?

Re: Как программно сделать offset?

> KonstantinM
Если я ничего не перепутал, то если offsetDist > 0 то сдвиг вправо по ходу кривой (т.е. все зависит от ее ориентации), если offsetDist < 0 - то влево.

Re: Как программно сделать offset?

Алекснадр - ты это проверял или интуитивно?
В хелпе к этому методу я не нашел слов относительно "хода кривой" и привяки сдвига оной к знаку.
If the offsetDist value is negative, it is usually interpreted as being an offset to make a smaller curve (that is, for an arc it would offset to a radius that is offsetDist less than the starting curve’s radius). If the negative value has no meaning in terms of making the curve smaller, a negative offsetDist may be interpreted as an offset in the direction of smaller X,Y,Z WCS coordinates. This is not enforced, so custom entities can interpret the sign of the offsetDist value however they want.

Re: Как программно сделать offset?

> KonstantinM
Так реализованно в лиспе...

Re: Как программно сделать offset?

> KonstantinM
Я это проверял и во всех случаях, с которыми я имел дело - это было правильно. Попробуй этот код:

static bool IsRightDirection(AcDbCurve *pCurv, AcGePoint3d p, AcGeVector3d vDir)
{
  AcGeVector3d vNormal = AcGeVector3d::kZAxis;
  if (pCurv->isPlanar()) {
    AcDb::Planarity plan_type;
    AcGePlane plane;
    pCurv->getPlane(plane,plan_type);
    vNormal = plane.normal();
    p.project(plane,vDir);
  }
  AcGePoint3d  pNear;  pCurv->getClosestPointTo(p,pNear);
  AcGeVector3d vSide   = p - pNear,
               vDeriv;
  pCurv->getFirstDeriv(pNear,vDeriv);
  if (vDeriv.crossProduct(vSide).dotProduct(vNormal) <= 0.0)
    return true;
  else
    return false;
}
// - OffsetCurve.OffsetCurve command (do not rename)
static void OffsetCurveOffsetCurve(void)
{
  // Add your code for command OffsetCurve.OffsetCurve here
  double offset = 0;
  AcGePoint3d p;
  if (acedGetDist(NULL,"\nУкажите величину смещения: ",&offset) == RTNORM &&
      acedGetPoint(NULL,"\nУкажите сторону смещения: ",asDblArray(p)) == RTNORM) {
    acdbUcs2Wcs(asDblArray(p),asDblArray(p),false);
    ads_name en;
    ads_point p_ent;
    if (acedEntSel("\nВыберите кривую: ",en,p_ent) == RTNORM) {
      AcDbObjectId objId;
      if (acdbGetObjectId(objId,en) == Acad::eOk) {
        AcDbObjectPointer<AcDbCurve> pCurv(objId,AcDb::kForRead);
        if (pCurv.openStatus() == Acad::eOk) {
          AcGeVector3d vDir = AcGeVector3d::kZAxis;
          resbuf rb; acedGetVar("viewdir",&rb);
          if (rb.restype == RT3DPOINT) vDir = asVec3d(rb.resval.rpoint);
          if (!IsRightDirection(pCurv.object(),p,vDir)) offset = -offset;
          AcDbVoidPtrArray aCurvs;
          if (pCurv->getOffsetCurves(offset,aCurvs) == Acad::eOk) {
            for (int i=0; i < aCurvs.length(); i++) {
              postToDwgAndClose(static_cast<AcDbEntity*>(aCurvs[i]));
            }
          }
        }
      }
    }
  }
}

Код postToDwgAndClose не привожу - он очевиден.

Re: Как программно сделать offset?

Я слегка нахалтурил в функции IsRightDirection. wink Исправляюсь.

//////////////////////////////////////////////////////////////////////////
//                     IsRightDirection
//                   --------------------
//    Функция для определения положения точки относительно направления
//    кривой (слева или справа).
//
//    Вход:
//         AcDbCurve     *pCurv  - кривая
//         AcGepoint      p      - точка (в WCS)
//         AcGeVector3d   vDir   - направление взгляда
//
//    Выход:
//         true   - точка справа от кривой
//         false  - точка слева от кривой
//////////////////////////////////////////////////////////////////////////
static bool IsRightDirection(AcDbCurve *pCurv, AcGePoint3d p, AcGeVector3d vDir)
{
  AcGeVector3d vNormal = AcGeVector3d::kZAxis;
  if (pCurv->isPlanar()) { // Если кривая плоская
    AcDb::Planarity plan_type;
    AcGePlane plane;
    pCurv->getPlane(plane,plan_type); // Плоскость кривой
    vNormal = plane.normal(); // Нормаль к плоскости кривой
    // Проецируем указанную точку в плоскость
    // кривой по направлению взгляда
    p = p.project(plane,vDir);
  }
  // Ближайшая точка на кривой к проекции заданной точки
  AcGePoint3d  pNear;  pCurv->getClosestPointTo(p,pNear);
  // Вектор из точки на прямой к проекции указанной точки
  AcGeVector3d vSide   = p - pNear,
               vDeriv;
  // Вектор касательной к кривой
  pCurv->getFirstDeriv(pNear,vDeriv);
  if (vNormal.crossProduct(vDeriv).dotProduct(vSide) < 0.0)
    return true;
  else
    return false;
}

Надеюсь, что так будет правильно.