A blog for developers programming with Autodesk platforms, particularly AutoCAD and Forge. With a special focus on AR/VR and IoT.

August 26, 2009

Gluing a point to an AutoCAD curve using overrules from .NET – Part 2

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):

1using Autodesk.AutoCAD.ApplicationServices;

2using Autodesk.AutoCAD.DatabaseServices;

3using Autodesk.AutoCAD.EditorInput;

4using Autodesk.AutoCAD.Geometry;

5using Autodesk.AutoCAD.Runtime;

6using System.Collections.Generic;

7

8namespace PointOnCurveTest

9{

10publicclassPtTransOverrule : TransformOverrule

11 {

12// A static pointer to our overrule instance

13

14staticpublicPtTransOverrule theOverrule =

15newPtTransOverrule();

16

17// A list of the curves that have had points

18// attached to

19

20staticinternalList<ObjectId> _curves =

21newList<ObjectId>();

22

23// A flag to indicate whether we're overruling

24

25staticbool overruling = false;

26

27public PtTransOverrule() { }

28

29// Out primary overruled function

30

31publicoverridevoid TransformBy(Entity e, Matrix3d mat)

32 {

33// We only care about points

34

35DBPoint pt = e asDBPoint;

36if (pt != null)

37 {

38Database db = HostApplicationServices.WorkingDatabase;

39

40// Work through the curves to find the closest to our

41// transformed point

42

43double min = 0.0;

44Point3d bestPt = Point3d.Origin;

45bool 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

51OpenCloseTransaction tr =

52 db.TransactionManager.StartOpenCloseTransaction();

53using (tr)

54 {

55foreach (ObjectId curId in _curves)

56 {

57DBObject obj =

58 tr.GetObject(curId, OpenMode.ForRead);

59Curve cur = obj asCurve;

60if (cur != null)

61 {

62Point3d ptLoc =

63 pt.Position.TransformBy(mat);

64Point3d ptOnCurve =

65 cur.GetClosestPointTo(ptLoc, false);

66Vector3d dist = ptOnCurve - ptLoc;

67

68if (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")]

82publicvoid CreatePointOnCurve()

83 {

84Document doc =

85Application.DocumentManager.MdiActiveDocument;

86Database db = doc.Database;

87Editor ed = doc.Editor;

88

89// Ask the user to select a curve

90

91PromptEntityOptions opts =

92newPromptEntityOptions(

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

100PromptEntityResult per = ed.GetEntity(opts);

101

102ObjectId curId = per.ObjectId;

103if (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

110Transaction tr =

111 doc.TransactionManager.StartTransaction();

112using (tr)

113 {

114DBObject obj =

115 tr.GetObject(curId, OpenMode.ForRead);

116Curve cur = obj asCurve;

117if (cur != null)

118 {

119// Our initial point should be the closest point

120// on the curve to the one picked

121

122Point3d pos =

123 cur.GetClosestPointTo(per.PickedPoint, false);

124DBPoint pt = newDBPoint(pos);

125

126// Add it to the same space as the curve

127

128BlockTableRecord btr =

129 (BlockTableRecord)tr.GetObject(

130 cur.BlockId,

131OpenMode.ForWrite

132 );

133ObjectId 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

145if (!overruling)

146 {

147ObjectOverrule.AddOverrule(

148RXClass.GetClass(typeof(DBPoint)),

149PtTransOverrule.theOverrule,

150true

151 );

152 overruling = true;

153TransformOverrule.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: