.NET

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

Clone a 3d Polyline?

378 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,125
Registered: ‎04-29-2006
Message 2 of 10 (339 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 (303 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,450
Registered: ‎04-09-2008
Message 4 of 10 (294 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 (274 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 (266 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,125
Registered: ‎04-29-2006
Message 7 of 10 (261 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 (246 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,125
Registered: ‎04-29-2006
Message 9 of 10 (241 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,125
Registered: ‎04-29-2006
Message 10 of 10 (231 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
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.