枫叶棋语 发表于 2024-11-9 17:28:04

ObjectArx 实现类似C# 的DrawJig,支持多实体拖动

首先实现接口,因为AcEdJig 仅仅支持单实体进行更新显示,如果用多实体那么就需要一个AcDbEntity 去包装,本次我们换个方式,直接在类中加入AcDbEntity接口,实现subWorldDraw显示多个图元



class DrawJig : public AcDbEntity, public AcEdJig {
public:
        virtual DragStatus sampler() = 0;
        virtual boolupdate() = 0;
        virtual bool subWorldDraw(AcGiWorldDraw* mode) = 0;
protected:
        AcDbEntity* entity() const final
        {
                return (AcDbEntity*)this;
        }
};下面用一个简单的例子继承测试下

class TestDrrawJig :public DrawJig {
public:
        TestDrrawJig() {}
        bool startDrag(AcGePoint3d ptCenter);
        DragStatus sampler() override;
        bool update() override;
        bool subWorldDraw(AcGiWorldDraw* mode)override;
        AcGePoint2d Point3dTo2d(AcGePoint3d pnt);
        AcDbVoidPtrArray CreateEntitys();
        AcArray<AcDbEntity*> GetEntities();
private:
        AcGePoint3d m_centerPnt;
        AcGePoint3d m_curPnt;
        AcDbVoidPtrArray m_aryPtr;
};

inline AcEdJig::DragStatus TestDrrawJig::sampler()
{
        setUserInputControls((UserInputControls)(AcEdJig::kAccept3dCoordinates
                | AcEdJig::kNoNegativeResponseAccepted
                | AcEdJig::kNullResponseAccepted));
        AcGePoint3d pointTemp;
        DragStatus stat = acquirePoint(m_curPnt);
        if (pointTemp != m_curPnt)
        {
                pointTemp = m_curPnt;
        }
        else if (stat == AcEdJig::kNormal)
        {
                return AcEdJig::kNoChange;
        }
        return stat;
}

inline bool TestDrrawJig::update()
{
        for (int i = 0; i < m_aryPtr.length(); i++)
        {
                AcDbEntity* pEnt = (AcDbEntity*)m_aryPtr.at(i);
                delete pEnt;
                pEnt = NULL;
        }
        //创建新实体
        m_aryPtr = CreateEntitys();

        return Adesk::kTrue;
}
inline bool TestDrrawJig::subWorldDraw(AcGiWorldDraw* mode)
{
        for (int i = 0; i < m_aryPtr.length(); i++)
        {
                AcDbEntity* pEnt = (AcDbEntity*)m_aryPtr;
                mode->geometry().draw(pEnt);
        }

        return Adesk::kTrue;
}


inline AcGePoint2d TestDrrawJig::Point3dTo2d(AcGePoint3d pnt)
{
        return AcGePoint2d(pnt.x, pnt.y);
}

inline AcDbVoidPtrArray TestDrrawJig::CreateEntitys()
{
        AcDbVoidPtrArray aryEnts;
        //创建实体
        double dist = Point3dTo2d(m_curPnt).distanceTo(Point3dTo2d(m_centerPnt));
        AcGeVector2d vec = Point3dTo2d(m_curPnt) - Point3dTo2d(m_centerPnt);
        AcGePoint2d pt1, pt2, pt3, pt4;
        pt1 = Point3dTo2d(m_curPnt);
        pt3 = pt1 - 2 * vec;
        vec.rotateBy(PI * 0.5);
        pt2 = Point3dTo2d(m_centerPnt) + vec;
        pt4 = pt2 - 2 * vec;
        AcDbPolyline* poly = new AcDbPolyline;
        poly->addVertexAt(0, pt1);
        poly->addVertexAt(1, pt2);
        poly->addVertexAt(2, pt3);
        poly->addVertexAt(3, pt4);
        poly->setClosed(Adesk::kTrue);
        poly->setColorIndex(1);
        aryEnts.append(static_cast<void*>(poly));
        AcDbCircle* circle = new AcDbCircle(m_centerPnt, AcGeVector3d::kZAxis, pt1.distanceTo(pt2) * 0.5);
        circle->setColorIndex(3);
        aryEnts.append(static_cast<void*>(circle));
        return aryEnts;
}

inline AcArray<AcDbEntity*> TestDrrawJig::GetEntities()
{
        AcArray <AcDbEntity*> ents;
        for (int i = 0; i < m_aryPtr.length(); i++) {
                ents.append((AcDbEntity*)(m_aryPtr));
        }
        return ents;
}

inline bool TestDrrawJig::startDrag(AcGePoint3d ptCenter)
{
        m_centerPnt = ptCenter;
        m_curPnt = ptCenter;
        AcString prompt = _T("\n指定角点");
        setDispPrompt(prompt);
        AcEdJig::DragStatus stat = drag();
        if (stat == AcEdJig::kNormal)
        {
                return true;
        }
        else
        {
                return false;
        }
}void tsJig()
{
        DbTrans tr;
        auto btr = tr.CurrentSpace();
        auto res = MapleGetPoint();
        if (!res.Ok) return;
        TestDrrawJig jig;
        if (jig.startDrag(res.Value)) {
                auto ents = jig.GetEntities();
                tr.AddEntities(btr, ents);
        }

}这样就可以使用多实体Jig了,与C#的DrawJig 差不多

gzxl 发表于 2024-12-27 22:16:42

arx本来就有,类似c#不知道几个意思

cable2004 发表于 2025-5-17 18:27:52

本帖最后由 cable2004 于 2025-5-17 19:12 编辑

class CMoveJig : public AcEdJig {
public:
    CMoveJig() : mBasePoint(), mCurrentPoint(), mOffset() {}

    AcEdJig::DragStatus Start(const AcDbObjectIdArray& objIds, const AcGePoint3d& basePoint) {
      mObjIds = objIds;
      mBasePoint = basePoint;
      mCurrentPoint = basePoint;
      mOffset.set(0.0, 0.0, 0.0);
      if (!PrepareDisplayEntities()) {
      return kCancel;
      }

      setDispPrompt(_T("\n指定目标点: "));
      setSpecialCursorType(AcEdJig::kCrosshair);

      DragStatus stat = drag();

      if (stat == kNormal) {
      MoveOriginalEntities();
      }

      CleanupDisplayEntities();
      return stat;
    }

protected:
    virtual DragStatus sampler() {
      AcGePoint3d newPt;
      DragStatus stat = acquirePoint(newPt, mBasePoint);
      if (stat == kNormal && !newPt.isEqualTo(mCurrentPoint)) {
      mCurrentPoint = newPt;
      mOffset = mCurrentPoint - mBasePoint;
      return kNormal;
      }
      return stat;
    }

    virtual Adesk::Boolean update() {
      AcGeMatrix3d xform;
      xform.setToTranslation(mOffset); // 创建平移矩阵
      for (int i = 0; i < mDisplayEntities.length(); ++i) {
      if (mDisplayEntities) {
          mDisplayEntities->transformBy(xform);
      }
      }
      acedRedraw(NULL, 1);
      return Adesk::kTrue;
    }

    // 返回第一个实体作为主实体
    virtual AcDbEntity* entity() const override {
      return mDisplayEntities.isEmpty() ? NULL : mDisplayEntities;
    }

    // 添加额外方法获取所有实体
    const AcArray<AcDbEntity*>& entities() const {
      return mDisplayEntities;
    }

    virtual Adesk::Boolean worldDraw(AcGiWorldDraw* pWorldDraw) {
      for (int i = 0; i < mDisplayEntities.length(); ++i) {
      if (mDisplayEntities) {
          mDisplayEntities->worldDraw(pWorldDraw);
          if (mDisplayEntities != NULL)
          {
            pWorldDraw->geometry().draw(mDisplayEntities);
          }
      }
      }
      return Adesk::kTrue;
    }

private:
    AcDbObjectIdArray mObjIds;
    AcGePoint3d mBasePoint;
    AcGePoint3d mCurrentPoint;
    AcGeVector3d mOffset;
    AcArray<AcDbEntity*> mDisplayEntities;

    bool PrepareDisplayEntities() {
      for (int i = 0; i < mObjIds.length(); ++i) {
      AcDbEntity* pEnt = NULL;
      if (acdbOpenObject(pEnt, mObjIds, AcDb::kForRead) == Acad::eOk) {
          AcDbEntity* pClone = static_cast<AcDbEntity*>(pEnt->clone());
          if (pClone) {
            mDisplayEntities.append(pClone);
          }
          pEnt->close();
      }
      }
      return mDisplayEntities.length() > 0;
    }

    void CleanupDisplayEntities() {
      for (int i = 0; i < mDisplayEntities.length(); ++i) {
      if (mDisplayEntities) {
          delete mDisplayEntities;
      }
      }
      mDisplayEntities.removeAll();
    }

    void MoveOriginalEntities() {
      AcGeMatrix3d xform;
      xform.setToTranslation(mOffset); // 创建平移矩阵
      for (int i = 0; i < mObjIds.length(); ++i) {
      AcDbEntity* pEnt = NULL;
      if (acdbOpenObject(pEnt, mObjIds, AcDb::kForWrite) == Acad::eOk) {
          pEnt->transformBy(xform);
          pEnt->close();
      }
      }
    }


   
};

// 移动选中对象命令入口函数
static void Cmd_MoveSelected() {
    ads_name ss;
    if (RTNORM != acedSSGet(NULL, NULL, NULL, NULL, ss)) {
      acutPrintf(_T("\n未选择对象"));
      return;
    }

    AcDbObjectIdArray objIds;
    Adesk::Int32 length = 0;
    acedSSLength(ss, &length);

    for (long i = 0; i < length; ++i) {
      ads_name ent;
      acedSSName(ss, i, ent);
      AcDbObjectId id;
      acdbGetObjectId(id, ent);
      objIds.append(id);
    }
    acedSSFree(ss);

    ads_point pt;
    if (RTNORM != acedGetPoint(NULL, _T("\n指定基点: "), pt)) {
      return;
    }

    acdbUcs2Wcs(pt, pt, false);
    AcGePoint3d basePt = asPnt3d(pt);

    CMoveJig jig;
    jig.Start(objIds, basePt);
}


模仿一个move移动的功能,为什么不能时时看到移动的过程,最终结果是对的。
页: [1]
查看完整版本: ObjectArx 实现类似C# 的DrawJig,支持多实体拖动