In the last post we looked at some code to create a point on a curve, and make sure it stays on that curve when edited.
In this post we’re extending that code (albeit slightly) to work with a network of curves: the idea is that any curve which has a point created on it becomes a candidate for any point to snap onto as it moves around. This could clearly be extended to provided a better way of specifying the curves forming the network, of course.
Here’s the updated C# code, with the modified/new lines in red (the full source file is available here):
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.EditorInput;
4 using Autodesk.AutoCAD.Geometry;
5 using Autodesk.AutoCAD.Runtime;
6 using System.Collections.Generic;
7
8 namespace PointOnCurveTest
9 {
10 public class PtTransOverrule : TransformOverrule
11 {
12 // A static pointer to our overrule instance
13
14 static public PtTransOverrule theOverrule =
15 new PtTransOverrule();
16
17 // A list of the curves that have had points
18 // attached to
19
20 static internal List<ObjectId> _curves =
21 new List<ObjectId>();
22
23 // A flag to indicate whether we're overruling
24
25 static bool overruling = false;
26
27 public PtTransOverrule() { }
28
29 // Out primary overruled function
30
31 public override void TransformBy(Entity e, Matrix3d mat)
32 {
33 // We only care about points
34
35 DBPoint pt = e as DBPoint;
36 if (pt != null)
37 {
38 Database db = HostApplicationServices.WorkingDatabase;
39
40 // Work through the curves to find the closest to our
41 // transformed point
42
43 double min = 0.0;
44 Point3d bestPt = Point3d.Origin;
45 bool first = true;
46
47 // We're using an Open/Close transaction, to avoid
48 // problems with us using transactions in an event
49 // handler
50
51 OpenCloseTransaction tr =
52 db.TransactionManager.StartOpenCloseTransaction();
53 using (tr)
54 {
55 foreach (ObjectId curId in _curves)
56 {
57 DBObject obj =
58 tr.GetObject(curId, OpenMode.ForRead);
59 Curve cur = obj as Curve;
60 if (cur != null)
61 {
62 Point3d ptLoc =
63 pt.Position.TransformBy(mat);
64 Point3d ptOnCurve =
65 cur.GetClosestPointTo(ptLoc, false);
66 Vector3d dist = ptOnCurve - ptLoc;
67
68 if (first || dist.Length < min)
69 {
70 first = false;
71 min = dist.Length;
72 bestPt = ptOnCurve;
73 }
74 }
75 }
76 pt.Position = bestPt;
77 }
78 }
79 }
80
81 [CommandMethod("POC")]
82 public void CreatePointOnCurve()
83 {
84 Document doc =
85 Application.DocumentManager.MdiActiveDocument;
86 Database db = doc.Database;
87 Editor ed = doc.Editor;
88
89 // Ask the user to select a curve
90
91 PromptEntityOptions opts =
92 new PromptEntityOptions(
93 "\nSelect curve at the point to create: "
94 );
95 opts.SetRejectMessage(
96 "\nEntity must be a curve."
97 );
98 opts.AddAllowedClass(typeof(Curve), false);
99
100 PromptEntityResult per = ed.GetEntity(opts);
101
102 ObjectId curId = per.ObjectId;
103 if (curId != ObjectId.Null)
104 {
105 // Let's make sure we'll be able to see our point
106
107 db.Pdmode = 97; // square with a circle
108 db.Pdsize = -10; // relative to the viewport size
109
110 Transaction tr =
111 doc.TransactionManager.StartTransaction();
112 using (tr)
113 {
114 DBObject obj =
115 tr.GetObject(curId, OpenMode.ForRead);
116 Curve cur = obj as Curve;
117 if (cur != null)
118 {
119 // Our initial point should be the closest point
120 // on the curve to the one picked
121
122 Point3d pos =
123 cur.GetClosestPointTo(per.PickedPoint, false);
124 DBPoint pt = new DBPoint(pos);
125
126 // Add it to the same space as the curve
127
128 BlockTableRecord btr =
129 (BlockTableRecord)tr.GetObject(
130 cur.BlockId,
131 OpenMode.ForWrite
132 );
133 ObjectId ptId = btr.AppendEntity(pt);
134 tr.AddNewlyCreatedDBObject(pt, true);
135 }
136 tr.Commit();
137
138 // And add the curve to our central list
139
140 _curves.Add(curId);
141 }
142
143 // Turn on the transform overrule if it isn't already
144
145 if (!overruling)
146 {
147 ObjectOverrule.AddOverrule(
148 RXClass.GetClass(typeof(DBPoint)),
149 PtTransOverrule.theOverrule,
150 true
151 );
152 overruling = true;
153 TransformOverrule.Overruling = true;
154 }
155 }
156 }
157 }
158 }
Now after having run our POC command to add points to a number of curves – effectively adding them to the “network” – we can grip-move a point, and should another curve in the network be closer, the point being edited will snap across to that one: