zoukankan      html  css  js  c++  java
  • Working with specific AutoCAD object types in .NET

    转载:http://through-the-interface.typepad.com/

    Most of the functions to access objects in the AutoCAD drawing return generic objects/entities. The base type for objects stored in the AutoCAD database is “DBObject” – which can be used to access common persistence information such as the handle, etc. – but there is no such thing as a pure DBObject: all DBObjects actually belong to a type that is derived from this base (whether that’s a “Line”, “Circle”, “BlockReference”, etc.).

    The next level up in the hierarchy is “Entity”, from where you can access graphical properties such as color, layer, linetype, material, etc. The sample code in this previous entry shows how to treat a DBObject as an Entity – in this entry we’re going to look at how to access information from an even more specific type, such as the center point and radius of a Circle.

    In order to find out what kind of object you’re dealing with, you need to use some kind of runtime type system. A compile-time type system is not going to be enough, as in many cases you simply don’t know what type of object it is you’re going to find in a particular location in the drawing database – especially when asking the user to select entities or when reading them from one of the block table records such as the model-space.

    C++ introduced a system for RTTI (RunTime Type Identification) after ObjectARX was first implemented, so AutoCAD maintains its own class hierarchy in memory. In order to use a more specific class in ObjectARX than the generic AcDbObject, you typically use isKindOf() or cast(), which ultimately use the AcDb class hierarchy behind the scenes to determine whether the pointer conversion operation is safe. The C++ standard now includes dynamic_cast<> to perform the equivalent task, but this is not enabled for standard ObjectARX types. As far as I recall, it is enabled for some of our other APIs (such as the Object Modeling Framework, the C++ API in Architectural Desktop that sits on top of ObjectARX), but for ObjectARX the existing type system has proven adequate until now.

    Here’s some ObjectARX code showing this:

    // objId is the object ID of the entity we want to access

    Acad::ErrorStatus es;

    AcDbEntity *pEnt = NULL;

    es = acdbOpenAcDbEntity( pEnt, objId, AcDb::kForRead );

    if ( es == Acad::eOk )

    {

      AcDbCircle *pCircle = NULL;

      pCircle = AcDbCircle::cast( pEnt );

    if ( pCircle )

      {

    // Access circle-specific properties/methods here

        AcGePoint3d cen = pCircle->center();

    // ...

      }

      pEnt->close();   

    }

    In a managed environment you get access to the .NET type system. Here’s an example of what you might do in VB.NET:

    [Note: the following two fragments have been pointed out in comments as being sub-optimal - please see further down for a better technique...]

    ' tr is the running transaction

    ' objId is the object ID of the entity we want to access

    Dim obj As DBObject = tr.GetObject(objId, OpenMode.ForRead)

    Try

    Dim circ As Circle = CType(obj, Circle)

    ' Access circle-specific properties/methods here

    ' ...

    Catch ex As InvalidCastException

    ' That's fine - it's just not a circle...

    End Try

    obj.Dispose()

    And in C#:

    // tr is the running transaction

    // objId is the object ID of the entity we want to access

    DBObject obj = tr.GetObject(objId, OpenMode.ForRead);

    try

    {

    Circle circ = (circle)obj;

    // Access circle-specific properties/methods here

    // ...

    }

    catch (InvalidCastException ex)

    {

    // That's fine - it's just not a circle...

    }

    obj.Dispose();

    [Here is the more elegant way to code this...]

    VB.NET:

    ' tr is the running transaction

    ' objId is the object ID of the entity we want to access

    Dim obj As DBObject = tr.GetObject(objId, OpenMode.ForRead)

    If TypeOf (obj) Is Circle Then

    Dim circ As Circle = CType(obj, Circle)

    ' Access circle-specific properties/methods here

    ' ...

    End If

    obj.Dispose()

    C#:

    // tr is the running transaction

    // objId is the object ID of the entity we want to access

    DBObject obj = tr.GetObject(objId, OpenMode.ForRead);

    Circle circ = obj as Circle;

    if (circ != null)

    {

    // Access circle-specific properties/methods here

    // ...

    }

    obj.Dispose();

    So now let's plug that technique into the previous sample. All we're going to do is check whether each entity that was selected is a Circle, and if so, print out its radius and center point in addition to the common entity-level properties we listed in last time.

    Here's the VB.NET version:

    Imports Autodesk.AutoCAD

    Imports Autodesk.AutoCAD.Runtime

    Imports Autodesk.AutoCAD.ApplicationServices

    Imports Autodesk.AutoCAD.DatabaseServices

    Imports Autodesk.AutoCAD.EditorInput

    Namespace SelectionTest

    Public Class PickfirstTestCmds

    ' Must have UsePickSet specified

        <CommandMethod("PFT", _

          (CommandFlags.UsePickSet _

    Or CommandFlags.Redraw _

    Or CommandFlags.Modal))> _

    Public Shared Sub PickFirstTest()

    Dim doc As Document = _

            Application.DocumentManager.MdiActiveDocument

    Dim ed As Editor = doc.Editor

    Try

    Dim selectionRes As PromptSelectionResult

            selectionRes = ed.SelectImplied

    ' If there's no pickfirst set available...

    If (selectionRes.Status = PromptStatus.Error) Then

    ' ... ask the user to select entities

    Dim selectionOpts As PromptSelectionOptions

              selectionOpts = New PromptSelectionOptions

              selectionOpts.MessageForAdding = _

                vbLf & "Select objects to list: "

              selectionRes = ed.GetSelection(selectionOpts)

    Else

    ' If there was a pickfirst set, clear it

              ed.SetImpliedSelection(Nothing)

    End If

    ' If the user has not cancelled...

    If (selectionRes.Status = PromptStatus.OK) Then

    ' ... take the selected objects one by one

    Dim tr As Transaction = _

                doc.TransactionManager.StartTransaction

    Try

    Dim objIds() As ObjectId = _

                  selectionRes.Value.GetObjectIds

    For Each objId As ObjectId In objIds

    Dim obj As Object = _

                    tr.GetObject(objId, OpenMode.ForRead)

    Dim ent As Entity = _

    CType(obj, Entity)

    ' This time access the properties directly

                  ed.WriteMessage(vbLf + "Type:        " + _

                    ent.GetType().ToString)

                  ed.WriteMessage(vbLf + "  Handle:    " + _

                    ent.Handle().ToString)

                  ed.WriteMessage(vbLf + "  Layer:      " + _

                    ent.Layer().ToString)

                  ed.WriteMessage(vbLf + "  Linetype:  " + _

                    ent.Linetype().ToString)

                  ed.WriteMessage(vbLf + "  Lineweight: " + _

                    ent.LineWeight().ToString)

                  ed.WriteMessage(vbLf + "  ColorIndex: " + _

                    ent.ColorIndex().ToString)

                  ed.WriteMessage(vbLf + "  Color:      " + _

                    ent.Color().ToString)

    ' Let's do a bit more for circles...

    If TypeOf (obj) Is Circle Then

    ' Let's do a bit more for circles...

    Dim circ As Circle = CType(obj, Circle)

                    ed.WriteMessage(vbLf + "  Center:  " + _

                      circ.Center.ToString)

                    ed.WriteMessage(vbLf + "  Radius:  " + _

                      circ.Radius.ToString)

    End If

                  obj.Dispose()

    Next

    ' Although no changes were made, use Commit()

    ' as this is much quicker than rolling back

                tr.Commit()

    Catch ex As Autodesk.AutoCAD.Runtime.Exception

                ed.WriteMessage(ex.Message)

                tr.Abort()

    End Try

    End If

    Catch ex As Autodesk.AutoCAD.Runtime.Exception

            ed.WriteMessage(ex.Message)

    End Try

    End Sub

    End Class

    End Namespace

    And here it is in C#:

    using Autodesk.AutoCAD;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.DatabaseServices;

    using Autodesk.AutoCAD.EditorInput;

    namespace SelectionTest

    {

    public class PickfirstTestCmds

      {

    // Must have UsePickSet specified

        [CommandMethod("PFT", CommandFlags.UsePickSet |

    CommandFlags.Redraw |

    CommandFlags.Modal)

        ]

    static public void PickFirstTest()

        {

    Document doc =

    Application.DocumentManager.MdiActiveDocument;

    Editor ed = doc.Editor;

    try

          {

    PromptSelectionResult selectionRes =

              ed.SelectImplied();

    // If there's no pickfirst set available...

    if (selectionRes.Status == PromptStatus.Error)

            {

    // ... ask the user to select entities

    PromptSelectionOptions selectionOpts =

    new PromptSelectionOptions();

              selectionOpts.MessageForAdding =

    "\nSelect objects to list: ";

              selectionRes =

                ed.GetSelection(selectionOpts);

            }

    else

            {

    // If there was a pickfirst set, clear it

              ed.SetImpliedSelection(new ObjectId[0]);

            }

    // If the user has not cancelled...

    if (selectionRes.Status == PromptStatus.OK)

            {

    // ... take the selected objects one by one

    Transaction tr =

                doc.TransactionManager.StartTransaction();

    try

              {

    ObjectId[] objIds =

                  selectionRes.Value.GetObjectIds();

    foreach (ObjectId objId in objIds)

                {

    DBObject obj =

                    tr.GetObject(objId, OpenMode.ForRead);

    Entity ent = (Entity)obj;

    // This time access the properties directly

                  ed.WriteMessage("\nType:        " +

                    ent.GetType().ToString());

                  ed.WriteMessage("\n  Handle:    " +

                    ent.Handle.ToString());

                  ed.WriteMessage("\n  Layer:      " +

                    ent.Layer.ToString());

                  ed.WriteMessage("\n  Linetype:  " +

                    ent.Linetype.ToString());

                  ed.WriteMessage("\n  Lineweight: " +

                    ent.LineWeight.ToString());

                  ed.WriteMessage("\n  ColorIndex: " +

                    ent.ColorIndex.ToString());

                  ed.WriteMessage("\n  Color:      " +

                    ent.Color.ToString());

    // Let's do a bit more for circles...

    Circle circ = obj as Circle;

    if (circ != null)

                  {

                    ed.WriteMessage("\n  Center:  " +

                      circ.Center.ToString());

                    ed.WriteMessage("\n  Radius:  " +

                      circ.Radius.ToString());

                  }

                  obj.Dispose();

                }

    // Although no changes were made, use Commit()

    // as this is much quicker than rolling back

                tr.Commit();

              }

    catch (Autodesk.AutoCAD.Runtime.Exception ex)

              {

                ed.WriteMessage(ex.Message);

                tr.Abort();

              }

            }

          }

    catch(Autodesk.AutoCAD.Runtime.Exception ex)

          {

            ed.WriteMessage(ex.Message);

          }

        }

      }

    }

    You'll notice the copious use of ToString - this just saves us having to get (and print out) the individual values making up the center point co-ordinate, for instance.

    Let's see this running with entities selected from one of AutoCAD's sample drawings. Notice the additional data displayed for the circle object:

    Command: PFT

    Select objects to list: 1 found

    Select objects to list: 1 found, 2 total

    Select objects to list: 1 found, 3 total

    Select objects to list: 1 found, 4 total

    Select objects to list:

    Type:        Autodesk.AutoCAD.DatabaseServices.Circle

      Handle:    1AB

      Layer:      Visible Edges

      Linetype:  Continuous

      Lineweight: LineWeight035

      ColorIndex: 179

      Color:      38,38,89

      Center:    (82.1742895599028,226.146274397998,0)

      Radius:    26

    Type:        Autodesk.AutoCAD.DatabaseServices.Line

      Handle:    205

      Layer:      Visible Edges

      Linetype:  Continuous

      Lineweight: LineWeight035

      ColorIndex: 179

      Color:      38,38,89

    Type:        Autodesk.AutoCAD.DatabaseServices.BlockReference

      Handle:    531

      Layer:      Dimensions

      Linetype:  ByLayer

      Lineweight: ByLayer

      ColorIndex: 256

      Color:      BYLAYER

    Type:        Autodesk.AutoCAD.DatabaseServices.Hatch

      Handle:    26B

      Layer:      Hatch

      Linetype:  Continuous

      Lineweight: LineWeight009

      ColorIndex: 179

      Color:      30,30,71

    Command:

  • 相关阅读:
    第一章 Java Collections Framework总览
    MySQL常用sql语句
    static关键字
    Mysql常用索引及优化
    JDK安装及环境变量配置
    破解IntelliJ IDEA 2017
    Spring自我总结
    Java中根据字节截取字符串
    外键的主要作用:保持数据的一致性、完整性
    使用SSI框架写的简单Demo(查询模块)
  • 原文地址:https://www.cnblogs.com/ddlzq/p/1989296.html
Copyright © 2011-2022 走看看