fivegg 发表于 2010-12-23 14:47:41

想过使用.net开发自定义实体没有(一)-源程序

本帖最后由 fivegg 于 2010-12-23 19:48 编辑

是否一直期盼着autocad能支持.net开发自定义实体呢。我等了很久一直没有等到。后来我想既然.net可以包裹arx类,那可能编写一个arx代理实体,将所有自定义实体的函数调用转到.net类实现呢。下面我用2007开发了一个代理类,欢迎大家拍砖。

二。使用方法

TomCustomEntityDBX.DBXarx对象
TomCustomEntityMgd.dllarx对象的manage class
RealEntityLib.dll       .net对象的接口,里面包含了我实现的简单例子
mgPolyTestVB.dll      生成SimpleEntity的例子
TomCustomEntityMgd.dll显示属性的面板

复制RealEntityLib.dll到autocad2007的目录下,运行_appload加载TomCustomEntityDBX.DBX 。
运行netload加载mgPolyTestVB.dll,TomCustomEntityMgd.dll。
使用命令ttt绘制对象,使用dtpalette显示属性面板,选择生成的对象,就可以修改显示属性了。


三。目前问题
修改属性后对象不会立即绘制,需要在cad中移动一下鼠标才会刷新

QQ104794806,fivegg@163.com

后续文章:
2.C++代码分析http://bbs.mjtd.com/thread-84747-1-1.html
3。.net代码分析 http://bbs.mjtd.com/thread-84748-1-1.html

fivegg 发表于 2010-12-23 14:52:45

想过使用.net开发自定义实体没有(三) -.net代码分析

.net实现的项目:
3.RealDotNetLib:实际的.net实体

我实现的一个简单的实体,这个对象目前必须拷贝到autocad2007目录下,否则它提示找不到。
    //
    public class SimpleEntity : IRealEntity
    {
      private Entity _proxy;
      private ObjectId _myId;

      public Point3d _PtA, _PtAB, _PtB, _PtBA;
      [Description("PtBA"),
      CategoryAttribute("位置"),
      TypeConverterAttribute(typeof(Point3dConverter))]
      public Point3d PtBA
      {
            get { return _PtBA; }
            set {
                _PtBA = value;
            }
      }
      [Description("PtB"),
      CategoryAttribute("位置"),
      TypeConverterAttribute(typeof(Point3dConverter))]
      public Point3d PtB
      {
            get { return _PtB; }
            set {
                _PtB = value;
            }
      }
      [Description("PtAB"),
      CategoryAttribute("位置"),
      TypeConverterAttribute(typeof(Point3dConverter))]
      public Point3d PtAB
      {
            get { return _PtAB; }
            set {
                _PtAB = value;
            }
      }
      [Description("PtA"),
      CategoryAttribute("位置"),
      TypeConverterAttribute(typeof(Point3dConverter))]
      public Point3d PtA
      {
            get { return _PtA; }
            set {
                _PtA = value;
            }
      }
      public String Text;
      public SimpleEntity()
      {
            PtA = new Point3d();
            PtAB = new Point3d();
            PtB = new Point3d();
            PtBA = new Point3d();
            Text = "";
      }

      #region IRealEntity 成员
      
      public Entity Proxy
      {
            get
            {
                return _proxy;
            }
            set
            {
                _proxy = value;
            }
      }

      public void DwgInFields(DwgFiler filer)
      {
            PtA = filer.ReadPoint3d();
            PtAB = filer.ReadPoint3d();
            PtB = filer.ReadPoint3d();
            PtBA = filer.ReadPoint3d();
      }

      public void DwgOutFields(DwgFiler filer)
      {
            filer.WritePoint3d(PtA);
            filer.WritePoint3d(PtAB);
            filer.WritePoint3d(PtB);
            filer.WritePoint3d(PtBA);
      }

      public string List()
      {
            return this.ToString();
      }

      public bool WorldDraw(WorldDraw wd)
      {
            Point3dCollection pts = new Point3dCollection();
            pts.Add(PtA);
            pts.Add(PtAB);
            pts.Add(PtB);
            pts.Add(PtBA);

            wd.SubEntityTraits.SetSelectionMarker(1);

            //Database db = HostApplicationServices.WorkingDatabase;
            //Transaction trans = db.TransactionManager.StartTransaction();

            //Entity Proxy=(Entity)trans.GetObject(myId, OpenMode.ForRead);
            wd.SubEntityTraits.Color = (short)Proxy.ColorIndex;

            //trans.Commit();
            wd.Geometry.Polygon(pts);

            /*
            AcGiTextStyle style;
    style.setFileName("txt.shx");
    style.setBigFontFileName("");
    style.setTextSize(25);
    style.loadStyleRec();
    AcGePoint3d txtPt((m_PtB.x+m_PtA.x)/2.0,(m_PtB.y+m_PtA.y)/2.0,   m_PtA.z);

    mode->geometry().text(txtPt, AcGeVector3d::kZAxis,
    (m_PtAB-m_PtA),m_Text,m_Text.GetLength(),Adesk::kFalse, style);
            */
            TextStyle style = new TextStyle();
            style.FileName = "txt.shx";
            style.BigFontFileName = "";
            style.TextSize = 25;
            //style.LoadStyleRec;
            Point3d txtPt = new Point3d((PtB.X + PtA.X) / 2, (PtB.Y + PtA.Y) / 2, PtA.Z);
            wd.Geometry.Text(txtPt, new Vector3d(0, 0, 1), PtAB - PtA, Text, false, style);
            return true;
      }

      public void Dispose()
      {

      }
      public void TransformBy(Matrix3d transform)
      {
            PtA = PtA.TransformBy(transform);
            PtAB = PtAB.TransformBy(transform);
            PtB = PtB.TransformBy(transform);
            PtBA = PtBA.TransformBy(transform);
      }
      #endregion

      private string name, email;
      
      public string Name
      {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
      }

      
      public string Email
      {
            get
            {
                return email;
            }
            set
            {
                email = value;
            }
      }
    }
4.mgPolyTestVB:使用.net代码在cad中绘制实体

<Autodesk.AutoCAD.Runtime.CommandMethod("ttt")> _
Public Sub TestFunction()

    ' get the working databasre
    Dim db As Database = HostApplicationServices.WorkingDatabase
    ' get the transaction manager for the working database
    Dim tm As DBTransMan = db.TransactionManager
    ' create a new transaction
    Dim myT As Transaction = tm.StartTransaction()
    ' start our try/catch block
    Try
            'Assembly.LoadFrom("RealEntityLib.dll")
      ' create a poly samp object via the .net wrapper
      Dim poly As New Tomcad.CustomObject.DotNetEntity() //用manager class生成CustomEntityDBX
      ' set the properties for the poly
      Dim simpEntity As New SimpleEntity()
      simpEntity.PtA = New Point3d(0, 0, 0)
      simpEntity.PtAB = New Point3d(100, 0, 0)
      simpEntity.PtB = New Point3d(100, 200, 0)
      simpEntity.PtBA = New Point3d(0, 200, 0)

      poly.SetManagedObject(simpEntity)//这步很关键,将CustomEntityDBX的.net句柄赋值,指向我们生成的SimpleEntity。


      ' get the blocktable as before, but lets open it for read within the transaction manager
      Dim bt As BlockTable = CType(tm.GetObject(db.BlockTableId, OpenMode.ForRead, False), BlockTable)
      ' do the same again but for the model space itself, we will need to open model space for write as
      ' we will be adding to it
      Dim btr As BlockTableRecord = CType(tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite, False), BlockTableRecord)
      ' add the new line to the model space as before
      btr.AppendEntity(poly)
      ' and then make sure that the transaction knows about this new object
      tm.AddNewlyCreatedDBObject(poly, True)
      ' finally commit the changes
      myT.Commit()

    Catch ex As Exception

      ' an error occurred
      ' ...


    Finally

      ' for the transactions we need to call the dispose to finish off
      myT.Dispose()

    End Try
5.TomPropertyMgr:根据kean代码实现的对象属性面板,可选。因为使用autocad的com对象接口实现自定义实体的动态属性太复杂了,我搞不定,就借用kean的代码,另外显示一个属性面板。

evergreenxq 发表于 2018-9-28 17:34:42

共享就是伟大,感谢,学习中

fivegg 发表于 2010-12-23 14:51:31

想过使用.net开发自定义实体没有(二) -代码分析

一。代码组成
项目组成:
C++实现的两个项目:
1.CustomEntityDBX:arx实现自定义实体,实际调用转到.net实体。只要自己编程实现IRealEntity接口,就可以被该对象调用
class DLLIMPEXP TomDotNetEntityProxy : public AcDbEntity {
...
private:
    gcroot<IRealEntity*> iRealEntity;//.net实体句柄
public:
    TomDotNetEntityProxy () ;
    virtual ~TomDotNetEntityProxy () ;
    void set_ManagedObject(gcroot<IRealEntity*> iObject);
    gcroot<IRealEntity*>get_ManagedObject();
   
...
}
关键的几个函数

输出dwg时,首先输出.net对象的名字。然后调用.net对象的DwgOutFields输出自定义属性
Acad::ErrorStatus TomDotNetEntityProxy::dwgOutFields (AcDbDwgFiler *pFiler) const {
    assertReadEnabled () ;
    //----- Save parent class information first.
    Acad::ErrorStatus es =AcDbEntity::dwgOutFields (pFiler) ;
    if ( es != Acad::eOk )
      return (es) ;
    //----- Object version number needs to be saved first
    if ( (es =pFiler->writeUInt32 (TomDotNetEntityProxy::kCurrentVersionNumber)) != Acad::eOk )
      return (es) ;
    //----- Output params
    //.....
    if (iRealEntity==NULL)
      return Acad::eNullObjectPointer;
   
    //write assembly and type info
    DwgFiler* f=dynamic_cast<DwgFiler*>(RXObject::Create(pFiler,false));
    Type* t=iRealEntity->GetType();
    //f->WriteString(t->AssemblyQualifiedName);
    StringToWchar stw(t->AssemblyQualifiedName);
    pFiler->writeString( (const wchar_t*)stw);   //首先输出.net对象的名字
    //pFiler->writeString(L"test.asfasdfa.asdfasf");

    iRealEntity->DwgOutFields(f);//调用.net对象的DwgOutFields输出自定义属性

    return (pFiler->filerStatus ()) ;
}

读入dwg时,首先读出.net对象的名字。然后调用相应.net对象的DwgInFields输出自定义属性
Acad::ErrorStatus TomDotNetEntityProxy::dwgInFields (AcDbDwgFiler *pFiler) {
    assertWriteEnabled () ;
    //----- Read parent class information first.
    Acad::ErrorStatus es =AcDbEntity::dwgInFields (pFiler) ;
    if ( es != Acad::eOk )
      return (es) ;
    //----- Object version number needs to be read first
    Adesk::UInt32 version =0 ;
    if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk )
      return (es) ;
    if ( version > TomDotNetEntityProxy::kCurrentVersionNumber )
      return (Acad::eMakeMeProxy) ;
    //- Uncomment the 2 following lines if your current object implementation cannot
    //- support previous version of that object.
    //if ( version < TomDotNetEntityProxy::kCurrentVersionNumber )
    //    return (Acad::eMakeMeProxy) ;
    //----- Read params
    //.....
   
    //if (iRealEntity==NULL)
    //    return Acad::eNullObjectPointer;


    //first read assembly and type info and load,create it 读出.net对象的名字
    DwgFiler* f=dynamic_cast<DwgFiler*>(RXObject::Create(pFiler,false));
    //String* typeName=f->ReadString();
    TCHAR* pStr;
    pFiler->readString(&pStr);
    String* typeName=WcharToString(pStr);
    delString(pStr);

    Type* t=Type::GetType(typeName,false);
    if (t==NULL)
      return Acad::eNullObjectPointer;
    iRealEntity=dynamic_cast<IRealEntity*>(Activator::CreateInstance(t));//创建.net对象
    Entity* ent=dynamic_cast<Entity*>(RXObject::Create(this,false));
    //AcDbObjectId id=this->id();
    //iRealEntity->myId=ToObjectId(id) ;
    iRealEntity->Proxy=ent;
    iRealEntity->DwgInFields(f);   //调用其DwgInFields输入函数

    return (pFiler->filerStatus ()) ;
}

//-----------------------------------------------------------------------------
//----- AcDbEntity protocols
Adesk::Boolean TomDotNetEntityProxy::worldDraw (AcGiWorldDraw *mode) {
    assertReadEnabled () ;
    //return (AcDbEntity::worldDraw (mode)) ;
    //AcGePoint3d pts;
    //pts = *(new AcGePoint3d(0,0,0));
    //pts = *(new AcGePoint3d(100,0,0));
    //pts = *(new AcGePoint3d(100,200,0));
    //pts = *(new AcGePoint3d(0,200,0));

    //mode->subEntityTraits().setSelectionMarker(1); // Mark 1
    //mode->subEntityTraits().setColor(1); // Red
    //mode->geometry().polygon(4,pts);
    if (iRealEntity==NULL)
      return Acad::eNullObjectPointer;

    WorldDraw* wd=dynamic_cast<WorldDraw*>(RXObject::Create(mode,false));//dynamic_cast<WorldDraw*>(RXObject.Create(mode,true));
    iRealEntity->WorldDraw(wd);   //调用.net对象的绘制函数
   
    //(*pRealEntity)->WorldDraw(wd);
    return Adesk::kTrue;
}

// -----------------------------------------------------------------------------
void TomDotNetEntityProxy::list(void) const
{
    AcDbEntity::list () ;

    if (iRealEntity==NULL)
      return ;

    String* str=iRealEntity->List(); //调用.net对象的list函数
    StringToWchar w(str);
    acutPrintf((const wchar_t *)w);
}
//变化函数
Acad::ErrorStatus TomDotNetEntityProxy::transformBy(const AcGeMatrix3d &xform)
{
    assertWriteEnabled();
    if (iRealEntity==NULL)
      return Acad::eNullObjectPointer;

    Matrix3d m=ToMatrix3d(xform);
    iRealEntity->TransformBy(m);
    return Acad::eOk;
}
其他的getOsnapPoints等函数可以自己看情况实现
2.CustDotNetLib:CustomEntityDBX的.net类,类似cad中arx实体的.net类,例如Polyline2d ,Solid3d 都是对应的arx对象的managed class
其他函数都可以不用实现,因为这个对象只是一个arx代理对象的.net代理,我们实际操作的是另外的.net对象
namespace CustomObject
    {
      
      public __gc class DotNetEntity: public Autodesk::AutoCAD::DatabaseServices::Entity
      {

      public:
            DotNetEntity();

      public private:
            DotNetEntity(System::IntPtr unmanagedPointer, bool autoDelete);
            inline TomDotNetEntityProxy*GetImpObj()
            {
                return static_cast<TomDotNetEntityProxy*>(UnmanagedObject.ToPointer());
            }

      public:

      //static __property bool get_UseDragData();
      //static __property void set_UseDragData(bool value);

      //__property virtual bool get_Closed();
      //__property virtual bool get_IsPeriodic();
      //__property virtual bool get_IsPlanar(); this is missing from Curve!

      //__property virtual double get_StartParam();
      //__property virtual double get_EndParam();

      //AcGeVector3d GetSideVector(int whichSide);
            void SetManagedObject(IRealEntity* iObject);
            IRealEntity* GetManagedObject();
      };
    }

雪山飞狐_lzh 发表于 2010-12-23 19:07:33

第三个问题能解决最好
这应该是Arx和NetApi结合的标准方式
但还有很多问题需要解决:)
1、需要C++功底,业余的开发者很难解决
2、自定义开发现在还只是ObjectArx的禁区
3、是否有更好的解决方案?

fivegg 发表于 2010-12-23 19:45:05

本帖最后由 fivegg 于 2010-12-23 19:50 编辑

lzh741206 发表于 2010-12-23 19:07 http://bbs.mjtd.com/static/image/common/back.gif
第三个问题能解决最好
这应该是Arx和NetApi结合的标准方式
但还有很多问题需要解决:)


我的目的就是以后都使用这个代理对象,用户实现不同的.net类。使用了我的C++模块TomCustomEntityDBX.DBX,用户只需要自己用.net实现IRealEntity接口就可以了。我给出C++代码只是用于高级用户的研究。过两天给出一个例子。

fivegg 发表于 2010-12-24 11:25:46

想过使用.net开发自定义实体没有(四)--纯.net例子

四。使用例子
目录:SampleCase
1.自定义实体:新建.net类库,引用acdbmgd,acmgd,RealEntityLib
实现Tomcad.IRealEntity接口
2.在cad中使用实体的命令:新建.net类库,引用acdbmgd,acmgd,RealEntityLib,TomCustomEntityMgd
用类似代码创建:
            Dim poly As New Tomcad.CustomObject.DotNetEntity()
            ' set the properties for the poly
            Dim ent As New MyCircleEntity.MyCircleEntity()
            ent.PtCenter = New Point3d(0, 0, 0)
            ent.R = 50
            ent.Text = "Hello Circle"

            poly.SetManagedObject(ent)
3.使用步骤:
    复制MyCircleEntity.dll,RealEntityLib.dll到C:\program files\autocad2007
    将TomCustomEntityDBX.DBX,TomCustomEntityMgd.dll复制在同一个目录下
    启动autocad2007,appload加载TomCustomEntityDBX.DBX,netload加载TomCustomEntityMgd.dll,MyCircleEntity.dll。
    如果要显示属性框,netload加载Tom.PropertyMgr.dll
    运行mycicle(我拼写错误,不是mycircle)即可,可以移动复制实体。如果要改属性,使用命令dtpalette显示属性框,选择一个实体。

其他版本的auotcad请使用我的源程序编译

yxr_MJTD 发表于 2010-12-24 11:45:41

下来学习一下!谢谢。

雪山飞狐_lzh 发表于 2010-12-24 11:59:48

要点时间慢慢研究了
为了查找方便,我直接把这几个相关的帖子合并了
望见谅

fivegg 发表于 2010-12-24 16:07:16

本帖最后由 fivegg 于 2010-12-24 16:08 编辑

lzh741206 发表于 2010-12-24 11:59 static/image/common/back.gif
要点时间慢慢研究了
为了查找方便,我直接把这几个相关的帖子合并了
望见谅
谢谢版主,我赶出一个2011的源程序。其中C++代码中的list,worlddraw等几个函数变成了subList,subWorldDraw。.net代码不影响
由于使用civil 3d2011开发,路径请大家自己修改。


SimpleCase目录是(四)部分例子的2011代码,由于使用.net开发,没有任何改动,只是引用改了一下

cdinten 发表于 2010-12-27 22:26:42

要是能有原理的解释就更好了
页: [1] 2
查看完整版本: 想过使用.net开发自定义实体没有(一)-源程序