.NET

Reply
Mentor
conormccartney3897
Posts: 187
Registered: ‎08-18-2010
Message 1 of 10 (376 Views)

Clone a 3d Polyline?

376 Views, 9 Replies
04-12-2013 01:09 PM

The 3d poly would be in an xref, and for my purposes i don't need it to be a 3d poly. Can this type of object be cloned? Or would it be better to collect the vertex points and create a 2d poly on top of it?

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 2 of 10 (337 Views)

Re : Clone a 3d Polyline?

04-13-2013 07:51 AM in reply to: conormccartney3897

Hi,

 

Here's a little example to clone a 3d polyline from a xref.

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

[assembly: CommandClass(typeof(CloneFromXrefSample.CommandMethods))]

namespace CloneFromXrefSample
{
    public class CommandMethods
    {
        [CommandMethod("Copy3dPolyFromXref", CommandFlags.Modal)]
        public void Copy3dPolylineFromXref()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptNestedEntityResult pner;
            ObjectId id;
            while (true)
            {
                pner = ed.GetNestedEntity("\nSelect a 3d polyline in a xref: ");
                id = pner.ObjectId;
                if (pner.Status != PromptStatus.OK) return;
                if (id.ObjectClass != RXClass.GetClass(typeof(PolylineVertex3d)))
                {
                    ed.WriteMessage("\nThe selected object is not 3d polyline.");
                    continue;
                }
                if (pner.ObjectId.Database == db)
                {
                    ed.WriteMessage("\nThe 3d polyline is not inside a xref.");
                    continue;
                }
                break;
            }

            Database xrefDb = id.Database;
            using (Transaction tr = xrefDb.TransactionManager.StartTransaction())
            {
                Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
                id = ent.OwnerId;
                tr.Commit();
            }

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection ids = new ObjectIdCollection();
                IdMapping mapping = new IdMapping();
                ids.Add(id);
                xrefDb.WblockCloneObjects(ids, db.CurrentSpaceId, mapping, DuplicateRecordCloning.Ignore, false);

                Entity ent = (Entity)tr.GetObject(mapping[id].Value, OpenMode.ForWrite);
                ent.TransformBy(pner.Transform);
                tr.Commit();
            }
        }
    }
}

 

Gilles Chanteau
Mentor
conormccartney3897
Posts: 187
Registered: ‎08-18-2010
Message 3 of 10 (301 Views)

Re : Clone a 3d Polyline?

04-15-2013 05:47 PM in reply to: _gile

Thanks Gilles, ill take a closer look later this week. From a brief look through, it looks mostly like a regular clone, the major difference being the 'WblockCloneObjects", anything else special?

Moderator
Alexander.Rivilis
Posts: 1,449
Registered: ‎04-09-2008
Message 4 of 10 (292 Views)

Re : Clone a 3d Polyline?

04-15-2013 10:38 PM in reply to: conormccartney3897

Regular clone (i.e. Entity.Clone()) can not clone complex entity such as Polyline3d


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Mentor
conormccartney3897
Posts: 187
Registered: ‎08-18-2010
Message 5 of 10 (272 Views)

Re: Clone a 3d Polyline?

04-16-2013 04:30 PM in reply to: conormccartney3897

Okay so played with it a bit, tryed incorporated into some other code, mostly worked. So question, must it be cloned as a PolylineVertex3d? the rest of the code is uses Curve Class objects, which would work if its Polyline3d.

Mentor
conormccartney3897
Posts: 187
Registered: ‎08-18-2010
Message 6 of 10 (264 Views)

Re: Clone a 3d Polyline?

04-16-2013 05:24 PM in reply to: conormccartney3897

bah okay so read up a bit, so i get that the PolylineVertex3d is part of the Polyline3d, so i guess the real question, how to access the Polyline3d after its cloned?

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 7 of 10 (259 Views)

Re: Clone a 3d Polyline?

04-16-2013 11:18 PM in reply to: conormccartney3897

Hi,

 

Did you read / try the snippet  posted ?

It gets the Polyline3d ObjectId from the selected PolylineVertex3d using a transaction from the xref database:

Database xrefDb = id.Database;
using (Transaction tr = xrefDb.TransactionManager.StartTransaction())
{
    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
    id = ent.OwnerId;
    tr.Commit();
}

 Then it clones the Polyline3d within a Transaction from the current database:

   

using (Transaction tr = db.TransactionManager.StartTransaction())
{
    ObjectIdCollection ids = new ObjectIdCollection();
    IdMapping mapping = new IdMapping();
    ids.Add(id);
    xrefDb.WblockCloneObjects(ids, db.CurrentSpaceId, mapping, DuplicateRecordCloning.Ignore, false);
    Entity ent = (Entity)tr.GetObject(mapping[id].Value, OpenMode.ForWrite);
    ent.TransformBy(pner.Transform);
    tr.Commit();
}

 

Gilles Chanteau
Mentor
conormccartney3897
Posts: 187
Registered: ‎08-18-2010
Message 8 of 10 (244 Views)

Re: Clone a 3d Polyline?

04-18-2013 08:11 AM in reply to: _gile

Yes i read through that, i suppose the problem is my implementation, so here's the code im using it with:

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
<Assembly: CommandClass(GetType(Line_Labler.snibbity))> 
Namespace Line_Labler
    Public Class snibbity
        <CommandMethod("linelabel")>
        Public Sub snabble()
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor
            Dim vwtw = Application.GetSystemVariable("viewtwist")
            Dim cid As New ObjectIdCollection
            Dim meas As Integer = Application.GetSystemVariable("measurement")
            Application.SetSystemVariable("textstyle", "MKA Standard")
            Dim ansc = Application.GetSystemVariable("cannoscalevalue")
            Dim txht As Double
            If meas = 0 Then
                Application.SetSystemVariable("textsize", 0.125)
            Else
                Application.SetSystemVariable("textsize", 3.175)
            End If
            Dim lt As LayerTable
            Dim peo As New PromptEntityOptions(vbCrLf & "Select Object AT the Point to be labeled:")
            Dim per As PromptEntityResult = ed.GetEntity(peo)
            If per.Status = PromptStatus.OK Then
                Dim objId As ObjectId = per.ObjectId
                Dim dbo As Database = objId.Database
                Using tr As Transaction = dbo.TransactionManager.StartTransaction()
                    lt = DirectCast(tr.GetObject(db.LayerTableId, OpenMode.ForRead), LayerTable)
                    ' First get the currently selected object
                    ' and check whether it's a block reference
                    Dim br As BlockReference = TryCast(tr.GetObject(objId, OpenMode.ForRead), BlockReference)
                    If br IsNot Nothing Then
                        ' If so, we check whether the block table record
                        ' to which it refers is actually from an XRef
                        Dim btrId As ObjectId = br.BlockTableRecord
                        Dim btr As BlockTableRecord = TryCast(tr.GetObject(btrId, OpenMode.ForRead), BlockTableRecord)
                        ' If so, then we programmatically select the object
                        ' underneath the pick-point already used
                        Dim pneo As New PromptNestedEntityOptions("")
                        pneo.NonInteractivePickPoint = per.PickedPoint
                        pneo.UseNonInteractivePickPoint = True
                        Dim pner As PromptNestedEntityResult = ed.GetNestedEntity(pneo)
                        Dim nid As ObjectId = pner.ObjectId
                            Dim selId As ObjectId = pner.ObjectId
                            Dim obj As DBObject = tr.GetObject(selId, OpenMode.ForRead)
                        If pner.Status = PromptStatus.OK Then
                            If TypeOf obj Is PolylineVertex3d Then 'If nid.ObjectClass = RXClass.GetClass(GetType(PolylineVertex3d)) Then '<---why vertex3d and not straight p3d? need for curve class...
                                Using tr2 As Transaction = dbo.TransactionManager.StartTransaction()
                                    Dim ent2 As Entity = DirectCast(tr2.GetObject(nid, OpenMode.ForRead), Entity)
                                    nid = ent2.OwnerId
                                    tr2.Commit()
                                End Using
                                Using tr2 As Transaction = db.TransactionManager.StartTransaction()
                                    Dim ids As New ObjectIdCollection()
                                    Dim map As New IdMapping
                                    ids.Add(nid)
                                    dbo.WblockCloneObjects(ids, db.CurrentSpaceId, map, DuplicateRecordCloning.Ignore, False)
                                    Dim ent2 As Entity = DirectCast(tr2.GetObject(map(nid).Value, OpenMode.ForWrite), Entity)
                                    ent2.TransformBy(pner.Transform)
                                    ent2.SetPropertiesFrom(br)
                                    If lt.Has("C-VPRT") Then
                                        ent2.LayerId = lt("C-VPRT")
                                    End If
                                    cid.Add(nid)
                                    tr2.Commit()
                                End Using
                                GoTo p3d
                            End If
                            Dim ent As Entity = DirectCast(obj, Entity)
                            ' Clone the selected object
                            Dim clob As Object = ent.Clone()
                            Dim clone As Entity = TryCast(clob, Entity)
                            If clone IsNot Nothing Then
                                clone.SetPropertiesFrom(br)
                                If lt.Has("C-VPRT") Then
                                    clone.LayerId = lt("C-VPRT")
                                End If
                                Dim conts As ObjectId() = pner.GetContainers()
                                For Each contId As ObjectId In conts
                                    Dim cont As BlockReference = TryCast(tr.GetObject(contId, OpenMode.ForRead), BlockReference)
                                    If cont IsNot Nothing Then
                                        clone.TransformBy(cont.BlockTransform)
                                    End If
                                Next
                                Dim btr2 As BlockTableRecord = TryCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
                                Dim cloneId As ObjectId = btr2.AppendEntity(clone)
                                tr.AddNewlyCreatedDBObject(clone, True)
                                tr.TransactionManager.QueueForGraphicsFlush()
                                cid.Add(cloneId)
                            End If
p3d:
                            per = pner
                        End If
                    End If
                    tr.Commit()
                End Using
            End If
            Using tr As Transaction = db.TransactionManager.StartTransaction
                Dim pso As New PromptStringOptions(vbCrLf & "Enter Text:")
                pso.AllowSpaces = True
                Dim psr As PromptResult = ed.GetString(pso)
                Dim inspt As Point3d
                Dim rotang As Double
                Dim radians As Double
                Dim degrees As Double
                Dim ent As Entity = tr.GetObject(per.ObjectId, OpenMode.ForRead)
                Dim obj As DBObject = tr.GetObject(per.ObjectId, OpenMode.ForRead)
                If TypeOf obj Is Curve Then
                    Dim bah As Curve = TryCast(ent, Curve)
                    'Calc rotation at point
                    inspt = bah.GetClosestPointTo(per.PickedPoint, True)
                    Dim fder As Vector3d = bah.GetFirstDerivative(inspt)
                    radians = Math.Truncate((Math.Atan2(CDbl(fder.Y), CDbl(fder.X)) + vwtw) * 100000000000) / 100000000000
                    degrees = Math.Round(radians * (180 / Math.PI), 5)
                    'check rotation
                    If degrees = (0 Or 180 Or -180) Then
                        rotang = 0
                    Else
                        rotang = radians
                    End If
                    If degrees > 360 Then
                        rotang = radians - (Math.PI * 2)
                        degrees = Math.Round(rotang * (180 / Math.PI), 5)
                    End If
                    If (degrees > 90 And degrees <= 270) Or (degrees <= -90 And degrees >= -270) Then
                        rotang = radians + Math.PI
                    End If
                End If
                'create mtext, apply rotation at point
                Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
                Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
                Dim mt As MText = New MText
                mt.Annotative = AnnotativeStates.True
                mt.Location = inspt
                mt.Attachment = AttachmentPoint.MiddleCenter
                mt.Rotation = rotang - vwtw
                mt.Contents = String.Concat(psr.StringResult, "\P ")
                mt.Height = txht
                btr.AppendEntity(mt)
                tr.AddNewlyCreatedDBObject(mt, True)
                For Each id As ObjectId In cid
                    Dim ob As DBObject = tr.GetObject(id, OpenMode.ForWrite, True)
                    ob.Erase()
                Next
                tr.Commit()
            End Using
            cid.Clear()
        End Sub
    End Class
End Namespace

It fails here, as it still thinks the object is polylinevertex3d, so the insertion point is 0,0:

  inspt = bah.GetClosestPointTo(per.PickedPoint, True)

 thoughts?

 

 

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 9 of 10 (239 Views)

Re: Clone a 3d Polyline?

04-18-2013 09:03 AM in reply to: conormccartney3897

Hi,

 

It looks like you're confusing databases to get the Transaction manager.

 

Dim dbo As Database = objId.Database

As objId is the ObjectId of a BlockReference inserted in the current drawing, dbo is the same db (i.e. the current Database).

You have to get the xref Database from the nested selected object:

Dim dbo As Database = nid.Database

 and use this database to open a transaction to get the Polylinevertex3d.OwnerId, and the current database transaction to make the deep cloning.

 

PS: Your check for pnr.Status before getting pnr.ObjectId.

 

Gilles Chanteau
*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 10 of 10 (229 Views)

Re: Clone a 3d Polyline?

04-18-2013 02:49 PM in reply to: conormccartney3897

Hi,

 

I tried to go a little deeper in your code, but it's too difficult for me. I'm not so comfortable with VB and it seems to me there're many unusefull and/or duplicated assignments and the using of a GoTo which ends confusing my undersanding.

 

So I tried to write a simple reusable function to get nested curves. This function have to be called from a transaction. It returns True if the selection succeeded False if it failed (Cancel). It uses two ByRef arguments which the function binds to the cloned curve and the picked point.

 

        ' Prompts the user to select a nested curve.
        ' Returns True if the selection succeeded, False if it failed.
        ' If the selection succeeded, sets the ByRef arguments with the clones curve and the picked point.
        Private Function TryGetNestedCurve(message As String, ed As Editor, _
ByRef curve As Curve, ByRef pickedPoint As Point3d) As Boolean Dim vertexClass As RXClass = RXClass.GetClass(GetType(Vertex)) Dim curveClass As RXClass = RXClass.GetClass(GetType(Curve)) Dim pner As PromptNestedEntityResult While True pner = ed.GetNestedEntity(message) If pner.Status <> PromptStatus.OK Then Return False End If If pner.GetContainers().Length = 0 Then ed.WriteMessage(vbLf & "The selected object is not nested.") Continue While End If If pner.ObjectId.ObjectClass.IsDerivedFrom(vertexClass) OrElse _ pner.ObjectId.ObjectClass.IsDerivedFrom(curveClass) Then Exit While End If ed.WriteMessage(vbLf & "The selected object is not a curve.") End While Dim db As Database = ed.Document.Database ' get the current Top transaction or throw an exception Dim tr As Transaction = ed.Document.Database.TransactionManager.TopTransaction If tr Is Nothing Then Throw New Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions) End If pickedPoint = pner.PickedPoint Dim id As ObjectId = pner.ObjectId ' if the selected object is a vertex, set id to its owner If id.ObjectClass.IsDerivedFrom(vertexClass) Then Using trx As Transaction = id.Database.TransactionManager.StartTransaction() Dim vertex As Vertex = DirectCast(trx.GetObject(id, OpenMode.ForRead), Vertex) id = vertex.OwnerId trx.Commit() End Using End If ' Clone the curve Dim ids As New ObjectIdCollection() Dim mapping As New IdMapping() ids.Add(id) If id.Database = db Then ' the object is in a block reference in the current Database db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, False) Else ' the object is from an Xref id.Database.WblockCloneObjects(ids, db.CurrentSpaceId, mapping, DuplicateRecordCloning.Ignore, False) End If ' set curve to the cloned curve curve = DirectCast(tr.GetObject(mapping(id).Value, OpenMode.ForWrite), Curve) ' transform the cloned curve curve.TransformBy(pner.Transform) Return True End Function

 A using example;

 

        <CommandMethod("Test", CommandFlags.Modal)> _
        Public Sub Test()
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim pickedPt As Point3d = Point3d.Origin
                Dim curve As Curve = Nothing
                If TryGetNestedCurve(vbLf & "Select a nested curve: ", ed, curve, pickedPt) Then
                    ' do some stuff here with the cloned curve
                    Dim pt As Point3d = curve.GetClosestPointTo(pickedPt, False)
                    Dim btr As BlockTableRecord = _
                        DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
                    Dim dbPt As New DBPoint(pt)
                    btr.AppendEntity(dbPt)
                    tr.AddNewlyCreatedDBObject(dbPt, True)
                    curve.[Erase]()
                End If
                tr.Commit()
            End Using
        End Sub

 

Gilles Chanteau
Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!