I am trying to copy various object type entities. Some entities are lines, circles, block references and polylines. After some time of searching and manipulating code that I found, I was able to find a copy jig for a single entity. My issue is I need it for an array of entities ...
Take a look at the CopyJig class that works for 1 entity (source😞
Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Geometry Imports Autodesk.AutoCAD.DatabaseServices Imports MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application Imports MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document Imports AcWindowsNS = Autodesk.AutoCAD.Windows Public Class CopyJig Inherits EntityJig #Region "Fields" Public mCurJigFactorIndex As Integer = 1 Private mBasePoint As New Point3d() Private mNewPoint As Point3d ' Factor #1 #End Region #Region "Constructors" Public Sub New(ent As Entity, basePoint As Point3d) MyBase.New(ent) mNewPoint = InlineAssignHelper(mBasePoint, basePoint.TransformBy(UCS)) End Sub #End Region #Region "Properties" Private ReadOnly Property Editor() As Editor Get Return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor End Get End Property Private ReadOnly Property UCS() As Matrix3d Get Return Editor.CurrentUserCoordinateSystem End Get End Property #End Region #Region "Overrides" Protected Overrides Function Update() As Boolean Dim mat As Matrix3d = Matrix3d.Displacement(mBasePoint.GetVectorTo(mNewPoint)) Entity.TransformBy(mat) mBasePoint = mNewPoint Return True End Function Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus Select Case mCurJigFactorIndex Case 1 Dim prOptions1 As New JigPromptPointOptions(vbLf & "Location:") prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates Or UserInputControls.GovernedByOrthoMode Or UserInputControls.GovernedByUCSDetect prOptions1.BasePoint = mBasePoint prOptions1.UseBasePoint = True Dim prResult1 As PromptPointResult = prompts.AcquirePoint(prOptions1) If prResult1.Status = PromptStatus.Cancel Then Return SamplerStatus.Cancel End If If prResult1.Value.Equals(mNewPoint) Then 'Use better comparision method if wanted. Return SamplerStatus.NoChange Else mNewPoint = prResult1.Value Return SamplerStatus.OK End If Case Else Exit Select End Select Return SamplerStatus.OK End Function #End Region #Region "Methods to Call" Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T target = value Return value End Function Public Shared Function Jig(ent As Entity, basePt As Point3d) As Boolean Dim jigger As CopyJig = Nothing Try jigger = New CopyJig(ent, basePt) Dim pr As PromptResult Do pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger) ' Add keyword handling code below If pr.Status = PromptStatus.Keyword Then Else jigger.mCurJigFactorIndex += 1 End If Loop While pr.Status <> PromptStatus.Cancel AndAlso pr.Status <> PromptStatus.[Error] AndAlso jigger.mCurJigFactorIndex <= 1 If pr.Status = PromptStatus.Cancel OrElse pr.Status = PromptStatus.[Error] Then If jigger IsNot Nothing AndAlso jigger.Entity IsNot Nothing Then jigger.Entity.Dispose() End If Return False Else Return True End If Catch If jigger IsNot Nothing AndAlso jigger.Entity IsNot Nothing Then jigger.Entity.Dispose() End If Return False End Try End Function #End Region End Class
The following class is called using this code:
<CommandMethod("CopyEntities")> _ Public Sub CopyEntities() Dim ed As Editor = AcApp.DocumentManager.MdiActiveDocument.Editor Dim db As Database = HostApplicationServices.WorkingDatabase Dim rb As ResultBuffer Dim FoundCorrectXData As Boolean Dim Lst_ObjId As New List(Of ObjectId) Dim acBlkTbl As BlockTable Dim acBlkTblRec As BlockTableRecord Dim SelSet As SelectionSet = Nothing Dim entities As Entity() Try Dim selRes As PromptEntityResult = ed.GetEntity(vbLf & "Pick an entity:") Dim ptRes As PromptPointResult = ed.GetPoint(vbLf & "Base Point: ") If selRes.Status = PromptStatus.OK AndAlso ptRes.Status = PromptStatus.OK Then Using tr As Transaction = db.TransactionManager.StartTransaction() '------------------------- START BUILDING THE ARRAY OF ENTITIES--------------------- rb = New ResultBuffer rb = selRes.ObjectId.GetObject(OpenMode.ForRead).XData() If IsHunter(rb) Then MyObject.SetByDataTable(GetPKFromResultBuffer(rb), Project.PK_Project) acBlkTbl = tr.GetObject(db.BlockTableId, OpenMode.ForRead) 'Open the Block table for read acBlkTblRec = tr.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite) 'Open the Block table record Model space for write 'Go through the Block Table Record and build the collection ID For Each acObjId As ObjectId In acBlkTblRec rb = New ResultBuffer rb = acObjId.GetObject(OpenMode.ForRead).XData() FoundCorrectXData = False If Not rb Is Nothing Then For Each tv As TypedValue In rb If tv.TypeCode = DxfCode.ExtendedDataRegAppName Then If tv.Value = "OBJECT_TO_BE_FOUND" Then FoundCorrectXData = True End If If FoundCorrectXData And tv.TypeCode = DxfCode.ExtendedDataInteger32 Then If tv.Value = MyObject.PK_MyObject Then Lst_ObjId.Add(acObjId) Exit For End If End If Next rb.Dispose() End If Next 'Create a selection set from the object IDs added to the list SelSet = SelectionSet.FromObjectIds(Lst_ObjId.ToArray) entities = New Entity(SelSet.Count - 1) {} 'Create an array of entities For i As Integer = 0 To SelSet.Count - 1 entities(i) = DirectCast(tr.GetObject(SelSet(i).ObjectId, OpenMode.ForWrite), Entity) Next '-----------------------------END OF ENTITY ARRAY BUILD---------------------------------- 'Code used to clone a single entity Dim ent As Entity = TryCast(tr.GetObject(selRes.ObjectId, OpenMode.ForRead), Entity) If ent IsNot Nothing Then Dim clone As Entity = TryCast(ent.Clone(), Entity) If CopyJig.Jig(clone, ptRes.Value) Then Dim ms As BlockTableRecord = TryCast(tr.GetObject(ent.OwnerId, OpenMode.ForWrite), BlockTableRecord) If ms IsNot Nothing Then ms.AppendEntity(clone) tr.AddNewlyCreatedDBObject(clone, True) tr.Commit() End If Else tr.Abort() End If End If End If End Using End If Catch ex As System.Exception ed.WriteMessage(ex.ToString()) End Try End Sub
The goal is to be able to see where I'm copying my entities and be able to select that point. I cleaned up the code above from my CopyEntities method. It includes an array of entities that contain the perfect selection that I wanted. I've been trying to pass this into the CopyJig class but I keep hitting snags.
My main snag is in the constructor of the CopyJig, I cannot pass an array of entities in there...
I thank you for the help in advance,
Alex
Solved! Go to Solution.
Solved by _gile. Go to Solution.
In most cases of jigging multiple entities, your custom Jig would be better off to derive from DrawJig, rather than EntityJig. However, there is very minor difference between the two in terms the purpose of jigging: providing visual feedback to user's mouse move.
If you insist to use EntityJig, you can simply make your custom jig's constructor like this:
Private myEntities() As Entity
Private myBasePoint As Point3d
Public Sub New MyCopyJig(ents As Entitys(), basePoint As Point3d)
MyBase(Nothing)
''stored the passed entity array in a private member field here
myEntities=ents
myBasePoint=basePoint
End Sub
Of course, this EntityJig derived Jib object will have its Entity property equals null, but it will not matter, because you do not need it anyway.
Then in the overriden Update() method, you will transform the array of entities instead of a single entity. Do not forget to dispose the array of cloned entities, if the jiging is cancelled.
Norman Yuan
Thank you for the feedback norman. After messing around with both DrawJig and EntityJig I decided to go for the DrawJig as you mentioned. I'm almost there! I'll be posting the solution once I get it figured out - or ask for some pointers if I can't get this last bit solved.
Very appreciated.
Here's the new version I started coding that inherits DrawJig. Now, for some reason, it copies the entities correctly but the mLocation (or destination point3d) is not correct. It is set correctly during the sampler but then becomes (0,0,0) once I click on the desired destination. It seems to be copying it over the existing entities that I selected to copy from.
Here's my CopyJig_2.vb class:
Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Geometry Imports Autodesk.AutoCAD.DatabaseServices Imports AcApp = Autodesk.AutoCAD.ApplicationServices.Application Public Class CopyJig_2 Inherits DrawJig #Region "Fields" Private entities As Entity() Private mBase As Point3d Private mLocation As Point3d Public mCurJigFactorIndex As Integer = 1 #End Region #Region "Constructors" Public Sub New(ents As Entity(), basePt As Point3d) entities = ents mBase = basePt.TransformBy(UCS) End Sub #End Region #Region "Properties" Public Property Location() As Point3d Get Return mLocation End Get Set(value As Point3d) mLocation = value End Set End Property Public ReadOnly Property UCS() As Matrix3d Get Return AcApp.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem End Get End Property #End Region #Region "Methods" Public Sub TransformEntities() Dim mat As Matrix3d = Matrix3d.Displacement(mBase.GetVectorTo(mLocation)) Dim line As Line Dim pLine As Polyline Dim startPoint As Point3d Dim endPoint As Point3d For Each ent As Entity In entities ent.TransformBy(mat) 'Store main line / polyline for database information If ent.Handle.ToString = MyObject.Handle.ToString Then If TypeOf ent Is Line Then line = DirectCast(ent, Line) startPoint = line.StartPoint endPoint = line.EndPoint ElseIf TypeOf ent Is Polyline Then pLine = DirectCast(ent, Polyline) startPoint = pLine.StartPoint endPoint = pLine.EndPoint End If
'Set the primary key to -1 so that it creates another instance of the copied item MyObject.PK_MyObject = -1 MyObject.StartX = startPoint.X MyObject.StartY = startPoint.Y MyObject.EndX = endPoint.X MyObject.EndY = endPoint.Y MyObject.Update() End If Next End Sub Public Function Jig(ents As Entity(), basePt As Point3d) As Boolean Dim jigger As CopyJig_2 = Nothing Try jigger = New CopyJig_2(ents, basePt) Dim pr As PromptResult Do pr = AcApp.DocumentManager.MdiActiveDocument.Editor.Drag(jigger) ' Add keyword handling code below If pr.Status = PromptStatus.Keyword Then Else jigger.mCurJigFactorIndex += 1 End If Loop While pr.Status <> PromptStatus.Cancel AndAlso pr.Status <> PromptStatus.[Error] AndAlso jigger.mCurJigFactorIndex <= 1 If pr.Status = PromptStatus.Cancel OrElse pr.Status = PromptStatus.[Error] Then For Each e As Entity In ents If jigger IsNot Nothing AndAlso e IsNot Nothing Then e.Dispose() End If Next Return False Else Return True End If Catch For Each e As Entity In ents If jigger IsNot Nothing AndAlso e IsNot Nothing Then e.Dispose() End If Next Return False End Try End Function #End Region #Region "Overrides" Protected Overrides Function WorldDraw(draw As Autodesk.AutoCAD.GraphicsInterface.WorldDraw) As Boolean Dim mat As Matrix3d = Matrix3d.Displacement(mBase.GetVectorTo(mLocation)) Dim geo As Autodesk.AutoCAD.GraphicsInterface.WorldGeometry = draw.Geometry If geo IsNot Nothing Then geo.PushModelTransform(mat) For Each ent As Entity In entities geo.Draw(ent) Next geo.PopModelTransform() End If Return True End Function Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus Select Case mCurJigFactorIndex Case 1 Dim prOptions1 As New JigPromptPointOptions(vbLf & "Location:") prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates Or UserInputControls.GovernedByOrthoMode Or UserInputControls.GovernedByUCSDetect prOptions1.BasePoint = mBase prOptions1.UseBasePoint = True Dim prResult1 As PromptPointResult = prompts.AcquirePoint(prOptions1) If prResult1.Status = PromptStatus.Cancel Then Return SamplerStatus.Cancel End If If prResult1.Value.Equals(mLocation) Then 'Use better comparision method if wanted. Return SamplerStatus.NoChange Else mLocation = prResult1.Value Return SamplerStatus.OK End If Case Else Exit Select End Select Return SamplerStatus.OK End Function #End Region End Class
Here is my command code, I'll shorten it because the majority of it is me filling up the entities array:
Dim cJig As New CopyJig_2(entities, pointResult.Value) If cJig.Jig(entities, pointResult.Value) Then For Each e As Entity In entities clone = TryCast(e.Clone, Entity) acBlkTblRec.AppendEntity(clone) acTrans.AddNewlyCreatedDBObject(clone, True) Next acTrans.Commit() Else acTrans.Abort() End If
Any idea why I can't keep the value in mLocation?
Hi
There's a simpler solution to drag several entities with the overload Editor.Drag(PromptDragOptions) or Editor.Drag(SelectionSet, string, DragCallback) methods. The two methods are similar as the PromptDragOptions constructor requires the same arguments as the second method.
If you're not starting with a selection set, you can build one from an ObjectId array with the static (Shared) SelectionSet.FromObjectIds(ObjectId[]) method.
Here a little example which mimics the MOVE command.
C#
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; namespace CsMoveSelectionSet { public class Commands { Point3d _basePoint; [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptSelectionResult psr = ed.GetSelection(); if (psr.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { List<Entity> ents = new List<Entity>(); foreach (ObjectId id in psr.Value.GetObjectIds()) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Highlight(); ents.Add(ent); } PromptPointOptions ppo = new PromptPointOptions("\nBase point: "); ppo.AllowNone = true; PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) return; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = ppr.Value.TransformBy(ucs); PromptDragOptions pdo = new PromptDragOptions( psr.Value, "\nSecond point: ", delegate(Point3d pt, ref Matrix3d xform) { if (pt.IsEqualTo(basePoint)) { return SamplerStatus.NoChange; } else { xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))); return SamplerStatus.OK; } }); pdo.AllowNone = true; ppr = ed.Drag(pdo); if (ppr.Status == PromptStatus.OK) { Matrix3d mat = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))); foreach (Entity ent in ents) { ent.TransformBy(mat); } } else { foreach (Entity ent in ents) { ent.Unhighlight(); } } tr.Commit(); } } } }
F#
module FsMoveSelectionSet open Autodesk.AutoCAD.ApplicationServices open Autodesk.AutoCAD.DatabaseServices open Autodesk.AutoCAD.EditorInput open Autodesk.AutoCAD.Geometry open Autodesk.AutoCAD.Runtime [<CommandMethod("Test")>] let test () = let doc = Application.DocumentManager.MdiActiveDocument let db = doc.Database let ed = doc.Editor let psr = ed.GetSelection() if psr.Status = PromptStatus.OK then use tr = db.TransactionManager.StartTransaction() let ents = psr.Value.GetObjectIds() |> Array.map(fun id -> tr.GetObject(id, OpenMode.ForWrite) :?> Entity) ents |> Array.iter(fun ent -> ent.Highlight()) let ppo = new PromptPointOptions("\nBase point: ") ppo.AllowNone <- true let ppr = ed.GetPoint(ppo) if ppr.Status = PromptStatus.OK then let ucs = ed.CurrentUserCoordinateSystem let basePoint = ppr.Value.TransformBy(ucs) let pdo = new PromptDragOptions( psr.Value, "\nSecond point: ", fun pt (xform: Matrix3d byref) -> if pt.IsEqualTo(basePoint) then SamplerStatus.NoChange else xform <- Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))) SamplerStatus.OK) pdo.AllowNone <- true let ppr = ed.Drag(pdo) if ppr.Status = PromptStatus.OK then let xform = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))) ents |> Array.iter(fun ent -> ent.TransformBy(xform)) else ents |> Array.iter(fun ent -> ent.Unhighlight()) tr.Commit()
VB
Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Geometry Imports Autodesk.AutoCAD.Runtime Namespace VbMoveSelectionSet Public Class Commands Private basePoint As Point3d <CommandMethod("Test")> _ Public Sub Test() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim psr As PromptSelectionResult = ed.GetSelection() If psr.Status <> PromptStatus.OK Then Return End If Using tr As Transaction = db.TransactionManager.StartTransaction() Dim ents As New List(Of Entity)() For Each id As ObjectId In psr.Value.GetObjectIds() Dim ent As Entity = DirectCast(tr.GetObject(id, OpenMode.ForWrite), Entity) ent.Highlight() ents.Add(ent) Next Dim ppo As New PromptPointOptions(vbLf & "Base point: ") ppo.AllowNone = True Dim ppr As PromptPointResult = ed.GetPoint(ppo) If ppr.Status <> PromptStatus.OK Then Return End If Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem basePoint = ppr.Value.TransformBy(ucs) Dim pdo As New PromptDragOptions(psr.Value, vbLf & "Second point: ", AddressOf Callback) pdo.AllowNone = True ppr = ed.Drag(pdo) If ppr.Status = PromptStatus.OK Then Dim mat As Matrix3d = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))) For Each ent As Entity In ents ent.TransformBy(mat) ent.Unhighlight() Next Else For Each ent As Entity In ents ent.Unhighlight() Next End If tr.Commit() End Using End Sub Private Function Callback(ByVal pt As Point3d, ByRef xform As Matrix3d) As SamplerStatus If pt.IsEqualTo(basePoint) Then Return SamplerStatus.NoChange Else Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))) Return SamplerStatus.OK End If End Function End Class End Namespace
A Copy method using the same way
C#
private ObjectIdCollection Copy(Database db, Editor ed, ObjectIdCollection source) { ObjectIdCollection copied = new ObjectIdCollection(); PromptPointResult result = ed.GetPoint("\nBase point: "); if (result.Status != PromptStatus.OK) return copied; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = result.Value.TransformBy(ucs); using (IdMapping idMap = new IdMapping()) { db.DeepCloneObjects(source, db.CurrentSpaceId, idMap, false); foreach (IdPair pair in idMap) { if (pair.IsPrimary && pair.IsCloned) copied.Add(pair.Value); } } ObjectId[] ids = new ObjectId[copied.Count]; copied.CopyTo(ids, 0); SelectionSet selSet = SelectionSet.FromObjectIds(ids); Matrix3d disp = new Matrix3d(); DragCallback callback = (Point3d current, ref Matrix3d xform) => { Point3d pt = current.TransformBy(ucs); if (pt.IsEqualTo(basePoint)) return SamplerStatus.NoChange; disp = xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt)); return SamplerStatus.OK; }; result = ed.Drag(selSet, "\nSecond point: ", callback); using (Transaction tr = db.TransactionManager.StartTransaction()) { var ents = ids.Select(id => (Entity)tr.GetObject(id, OpenMode.ForWrite)); if (result.Status == PromptStatus.OK) { foreach (Entity ent in ents) { ent.TransformBy(disp); } } else { foreach (Entity ent in ents) { ent.Erase(); } copied.Clear(); } tr.Commit(); } return copied; }
VB
Private Function Copy(db As Database, ed As Editor, source As ObjectIdCollection) As ObjectIdCollection Dim copied As ObjectIdCollection = New ObjectIdCollection() Dim result As PromptPointResult = ed.GetPoint(vbLf & "Base point: ") If result.Status <> PromptStatus.OK Then Return copied End If Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem Dim basePoint As Point3d = result.Value Using idMap As IdMapping = New IdMapping() db.DeepCloneObjects(source, db.CurrentSpaceId, idMap, False) For Each pair As IdPair In idMap If pair.IsPrimary AndAlso pair.IsCloned Then copied.Add(pair.Value) End If Next End Using Dim ids(copied.Count - 1) As ObjectId copied.CopyTo(ids, 0) Dim selSet As SelectionSet = SelectionSet.FromObjectIds(ids) Dim disp As Matrix3d = New Matrix3d() Dim callback As DragCallback = _ Function(current As Point3d, ByRef xform As Matrix3d) Dim pt As Point3d = current.TransformBy(ucs) If current.IsEqualTo(basePoint) Then Return SamplerStatus.NoChange Else xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt)) disp = xform Return SamplerStatus.OK End If End Function result = ed.Drag(selSet, vbLf & "Second point: ", callback) Using tr As Transaction = db.TransactionManager.StartTransaction() Dim ents As IEnumerable(Of Entity) = _ From id In ids Select DirectCast(tr.GetObject(id, OpenMode.ForWrite), Entity) If result.Status = PromptStatus.OK Then For Each ent As Entity In ents ent.TransformBy(disp) Next Else For Each ent As Entity In ents ent.Erase() Next copied.Clear() End If tr.Commit() End Using Return copied End Function
Here's a better implementation of the previous method.
C#
private ObjectIdCollection Copy(Database db, Editor ed, ObjectId[] source) { ObjectIdCollection copied = new ObjectIdCollection(); PromptPointResult result = ed.GetPoint("\nBase point: "); if (result.Status != PromptStatus.OK) return copied; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = result.Value.TransformBy(ucs); SelectionSet selSet = SelectionSet.FromObjectIds(source); Matrix3d disp = new Matrix3d(); DragCallback callback = (Point3d current, ref Matrix3d xform) => { Point3d pt = current.TransformBy(ucs); if (pt.IsEqualTo(basePoint)) return SamplerStatus.NoChange; disp = xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt)); return SamplerStatus.OK; }; result = ed.Drag(selSet, "\nSecond point: ", callback); if (result.Status == PromptStatus.OK) { using (Transaction tr = db.TransactionManager.StartTransaction()) using (IdMapping idMap = new IdMapping()) { db.DeepCloneObjects(new ObjectIdCollection(source), db.CurrentSpaceId, idMap, false); foreach (IdPair pair in idMap) { if (pair.IsPrimary && pair.IsCloned) { copied.Add(pair.Value); Entity ent = (Entity)tr.GetObject(pair.Value, OpenMode.ForWrite); ent.TransformBy(disp); } } tr.Commit(); } } return copied; }
VB
Private Function Copy(db As Database, ed As Editor, source As ObjectId()) As ObjectIdCollection Dim copied As ObjectIdCollection = New ObjectIdCollection() Dim result As PromptPointResult = ed.GetPoint(vbLf & "Base point: ") If result.Status = PromptStatus.OK Then Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem Dim basePoint As Point3d = result.Value Dim selSet As SelectionSet = SelectionSet.FromObjectIds(source) Dim disp As Matrix3d = New Matrix3d() Dim callback As DragCallback = _ Function(current As Point3d, ByRef xform As Matrix3d) Dim pt As Point3d = current.TransformBy(ucs) If current.IsEqualTo(basePoint) Then Return SamplerStatus.NoChange Else xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt)) disp = xform Return SamplerStatus.OK End If End Function result = ed.Drag(selSet, vbLf & "Second point: ", callback) If result.Status = PromptStatus.OK Then Using tr As Transaction = db.TransactionManager.StartTransaction() Using idMap As IdMapping = New IdMapping() db.DeepCloneObjects(New ObjectIdCollection(source), db.CurrentSpaceId, idMap, False) For Each pair As IdPair In idMap If pair.IsPrimary AndAlso pair.IsCloned Then copied.Add(pair.Value) Dim ent As Entity = DirectCast(tr.GetObject(pair.Value, OpenMode.ForWrite), Entity) ent.TransformBy(disp) End If Next End Using tr.Commit() End Using End If End If
If you rather use a DrawJig derived class, you have to transform the entities (the DrawJig only draws transformed geometries).
C#
the CopyJig class
class CopyJig : DrawJig { Point3d basePoint, dragPoint; Matrix3d xform; Entity[] entities; public CopyJig(IEnumerable<Entity> ents, Point3d basePoint) { this.basePoint = basePoint; this.entities = ents.ToArray(); } public Matrix3d Transform { get { return xform; } } protected override bool WorldDraw(WorldDraw draw) { WorldGeometry wg = draw.Geometry; xform = Matrix3d.Displacement(basePoint.GetVectorTo(dragPoint)); wg.PushModelTransform(xform); foreach (Entity ent in entities) { wg.Draw(ent); } wg.PopModelTransform(); return true; } protected override SamplerStatus Sampler(JigPrompts prompts) { JigPromptPointOptions options = new JigPromptPointOptions("\nSecond point: "); options.BasePoint = basePoint; options.UseBasePoint = true; options.Cursor = CursorType.RubberBand; options.UserInputControls = UserInputControls.Accept3dCoordinates; PromptPointResult result = prompts.AcquirePoint(options); if (result.Value.IsEqualTo(dragPoint)) return SamplerStatus.NoChange; dragPoint = result.Value; return SamplerStatus.OK; } }
the JigCopy method
private ObjectIdCollection JigCopy(Database db, Editor ed, ObjectIdCollection source) { ObjectIdCollection copied = new ObjectIdCollection(); Entity[] entities = new Entity[source.Count]; PromptPointResult result = ed.GetPoint("\nBase point: "); if (result.Status != PromptStatus.OK) return copied; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = result.Value.TransformBy(ucs); using (Transaction tr = db.TransactionManager.StartTransaction()) { for (int i = 0; i < source.Count; i++) { entities[i] = (Entity)tr.GetObject(source[i], OpenMode.ForRead); } CopyJig jig = new CopyJig(entities, basePoint); PromptResult pr = ed.Drag(jig); if (pr.Status == PromptStatus.OK) { Matrix3d xform = jig.Transform; using (IdMapping idMap = new IdMapping()) { db.DeepCloneObjects(source, db.CurrentSpaceId, idMap, false); foreach (IdPair pair in idMap) { if (pair.IsPrimary && pair.IsCloned) { copied.Add(pair.Value); Entity ent = (Entity)tr.GetObject(pair.Value, OpenMode.ForWrite); ent.TransformBy(xform); } } } } tr.Commit(); } return copied; }
VB
the CopyJig class
Private Class EntitiesJig Inherits DrawJig Private basePoint As Point3d Private dragPoint As Point3d Private xform As Matrix3d Private entities() As Entity Public Sub New(ents As IEnumerable(Of Entity), basePt As Point3d) basePoint = basePt entities = ents.ToArray() End Sub Public ReadOnly Property Transform() As Matrix3d Get Return xform End Get End Property Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus Dim options As JigPromptPointOptions = New JigPromptPointOptions(vbLf & "Second point: ") options.BasePoint = basePoint options.UseBasePoint = True options.Cursor = CursorType.RubberBand options.UserInputControls = UserInputControls.Accept3dCoordinates Dim result As PromptPointResult = prompts.AcquirePoint(options) If result.Value.IsEqualTo(dragPoint) Then Return SamplerStatus.NoChange End If dragPoint = result.Value Return SamplerStatus.OK End Function Protected Overrides Function WorldDraw(draw As WorldDraw) As Boolean Dim wg As WorldGeometry = draw.Geometry xform = Matrix3d.Displacement(basePoint.GetVectorTo(dragPoint)) wg.PushModelTransform(xform) For Each entity As Entity In entities wg.Draw(entity) Next wg.PopModelTransform() Return True End Function End Class
the JigCopy method
Private Function JigCopy(db As Database, ed As Editor, source As ObjectIdCollection) As ObjectIdCollection Dim copied As ObjectIdCollection = New ObjectIdCollection() Dim entities(source.Count - 1) As Entity Dim result As PromptPointResult = ed.GetPoint(vbLf & "Base point: ") If result.Status <> PromptStatus.OK Then Return copied End If Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem Dim basePoint As Point3d = result.Value.TransformBy(ucs) Using tr As Transaction = db.TransactionManager.StartTransaction() For i = 0 To source.Count - 1 entities(i) = DirectCast(tr.GetObject(source(i), OpenMode.ForRead), Entity) Next Dim jig As EntitiesJig = New EntitiesJig(entities, basePoint) Dim pr As PromptResult = ed.Drag(jig) If pr.Status = PromptStatus.OK Then Dim xform As Matrix3d = jig.Transform Using idMap As IdMapping = New IdMapping() db.DeepCloneObjects(source, db.CurrentSpaceId, idMap, False) For Each pair As IdPair In idMap If pair.IsPrimary AndAlso pair.IsCloned Then copied.Add(pair.Value) Dim ent As Entity = _ DirectCast(tr.GetObject(pair.Value, OpenMode.ForWrite), Entity) ent.TransformBy(xform) End If Next End Using End If tr.Commit() End Using Return copied End Function