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?
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(); } } } }
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?
Regular clone (i.e. Entity.Clone()) can not clone complex entity such as Polyline3d
Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"
Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
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.
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?
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(); }
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?
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.
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
Can't find what you're looking for? Ask the community or share your knowledge.