بنقرة واحدة
acad-jigs
EntityJig, DrawJig — interactive placement, live preview, Sampler, WorldDraw
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
EntityJig, DrawJig — interactive placement, live preview, Sampler, WorldDraw
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Corridors, baselines, regions, assemblies, subassemblies, corridor surfaces
Custom subassembly .NET design — CorridorState, SubassemblyGenerator, targets, SATemplate
Stock-subassembly pattern catalog — need→file index, worked DrawImplement recipes, point/link/shape code reference, mined from Autodesk's 120 VB stock subassemblies
Superelevation design, attainment, cross slope, pivot points, lane config
Block definitions, references, attributes, dynamic block properties, exploding
Dimensions — aligned, rotated, arc, radial, angular, ordinate, text overrides
| name | acad-jigs |
| description | EntityJig, DrawJig — interactive placement, live preview, Sampler, WorldDraw |
Use this skill when implementing interactive entity placement with live preview, drag-based input acquisition, or custom drawing feedback during user input in AutoCAD plugins.
Jigs provide real-time visual feedback while the user moves the cursor. AutoCAD offers two jig base classes:
Entity that AutoCAD draws automatically each frame.WorldDraw / ViewportDraw, useful when previewing multiple entities or non-entity graphics.Both follow the same loop: AutoCAD repeatedly calls Sampler() to read input, then Update() (EntityJig) or WorldDraw() (DrawJig) to refresh the preview, until the user accepts or cancels.
Subclass Autodesk.AutoCAD.EditorInput.EntityJig and pass the entity to the base constructor. Override two methods:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
public class CircleJig : EntityJig
{
private Point3d _center;
private double _radius;
public CircleJig(Circle circle)
: base(circle)
{
_center = circle.Center;
_radius = circle.Radius;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify radius point: ")
{
BasePoint = _center,
UseBasePoint = true,
CursorType = CursorType.RubberBand
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
double newRadius = _center.DistanceTo(result.Value);
// Return NoChange when value hasn't moved -- prevents flicker
if (Math.Abs(newRadius - _radius) < Tolerance.Global.EqualPoint)
return SamplerStatus.NoChange;
_radius = newRadius;
return SamplerStatus.OK;
}
protected override bool Update()
{
((Circle)Entity).Radius = _radius;
return true; // return false to abort the jig
}
}
Sampler() acquires one input value per call. Available acquisition methods on JigPrompts:
| Method | Returns | Use for |
|---|---|---|
AcquirePoint(JigPromptPointOptions) | PromptPointResult | Pick a point |
AcquireDistance(JigPromptDistanceOptions) | PromptDoubleResult | Drag a distance |
AcquireAngle(JigPromptAngleOptions) | PromptDoubleResult | Drag an angle |
AcquireString(JigPromptStringOptions) | PromptStringResult | Type a string |
Critical: Always compare the new value against the previous value and return SamplerStatus.NoChange when they are equal. Omitting this check causes display flicker because AutoCAD redraws every frame even when nothing changed.
| Value | Meaning |
|---|---|
OK | New value acquired -- call Update() and redraw |
NoChange | Value unchanged -- skip redraw (prevents flicker) |
Cancel | User pressed Escape or right-clicked -- end jig |
Update() applies the sampled values to the entity. Return true to continue, false to abort. AutoCAD draws the entity automatically after Update() returns true.
public void RunCircleJig()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 1.0);
var jig = new CircleJig(circle);
PromptResult result = ed.Drag(jig);
if (result.Status != PromptStatus.OK)
return;
using (var tr = db.TransactionManager.StartTransaction())
{
var btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
btr.AppendEntity(circle);
tr.AddNewlyCreatedDBObject(circle, true);
tr.Commit();
}
}
Subclass Autodesk.AutoCAD.EditorInput.DrawJig when you need to draw custom graphics or preview multiple entities. Override Sampler() and WorldDraw().
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
public class CrosshairJig : DrawJig
{
private Point3d _point;
private readonly double _size;
public CrosshairJig(double size)
{
_size = size;
_point = Point3d.Origin;
}
public Point3d PickedPoint => _point;
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify point: ")
{
CursorType = CursorType.Crosshair
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (result.Value.IsEqualTo(_point))
return SamplerStatus.NoChange;
_point = result.Value;
return SamplerStatus.OK;
}
protected override bool WorldDraw(WorldDraw draw)
{
// Draw a crosshair at the cursor position
var geo = draw.Geometry;
geo.WorldLine(
new Point3d(_point.X - _size, _point.Y, _point.Z),
new Point3d(_point.X + _size, _point.Y, _point.Z));
geo.WorldLine(
new Point3d(_point.X, _point.Y - _size, _point.Z),
new Point3d(_point.X, _point.Y + _size, _point.Z));
return true; // return true = handled; false = let AutoCAD draw defaults
}
}
WorldDraw() draws in world coordinates, visible in all viewports. Return true if drawing is complete, false to also invoke ViewportDraw().ViewportDraw() draws per-viewport. Override it for viewport-specific graphics (rare in jig usage).Common methods available on WorldDraw.Geometry:
| Method | Description |
|---|---|
WorldLine(Point3d from, Point3d to) | Draw a line segment |
Polyline(Point3dCollection, Vector3d, IntPtr) | Draw a polyline |
Circle(Point3d center, double radius, Vector3d normal) | Draw a circle |
Text(...) | Draw text |
Draw(Drawable) | Draw an existing entity |
var jig = new CrosshairJig(5.0);
PromptResult result = ed.Drag(jig);
if (result.Status == PromptStatus.OK)
{
Point3d picked = jig.PickedPoint;
// Use the picked point
}
Editor.Drag(Jig) starts the jig loop and blocks until the user completes or cancels. Returns a PromptResult whose Status property indicates the outcome.
The PromptResult.Status returned by Drag() maps to standard PromptStatus values:
| Value | Meaning |
|---|---|
PromptStatus.OK | User accepted (clicked or pressed Enter) |
PromptStatus.Cancel | User cancelled (Escape or right-click) |
PromptStatus.Keyword | User entered a keyword |
PromptStatus.None | No input / empty response |
var opts = new JigPromptPointOptions("\nSpecify insertion point: ");
opts.UseBasePoint = true;
opts.BasePoint = new Point3d(0, 0, 0);
opts.CursorType = CursorType.RubberBand;
opts.UserInputControls =
UserInputControls.Accept3dCoordinates |
UserInputControls.NullResponseAccepted;
opts.Keywords.Add("Rotate");
opts.Keywords.Add("Scale");
var opts = new JigPromptDistanceOptions("\nSpecify offset distance: ");
opts.BasePoint = _center;
opts.UseBasePoint = true;
opts.DefaultValue = 10.0;
var opts = new JigPromptAngleOptions("\nSpecify rotation angle: ");
opts.BasePoint = _insertionPoint;
opts.UseBasePoint = true;
opts.DefaultValue = 0.0;
Set via JigPromptPointOptions.CursorType:
| CursorType | Appearance |
|---|---|
Crosshair | Standard crosshair (default) |
RubberBand | Line from BasePoint to cursor |
EntitySelect | Pick box for entity selection |
Invisible | Hidden cursor |
RubberBand requires UseBasePoint = true and a valid BasePoint.
For entities that need multiple inputs (e.g., pick insertion point, then set rotation), track the current step and branch in Sampler() / Update().
public class BlockInsertJig : EntityJig
{
private Point3d _position;
private double _rotation;
private int _step; // 0 = position, 1 = rotation
public BlockInsertJig(BlockReference blockRef)
: base(blockRef)
{
_position = blockRef.Position;
_rotation = blockRef.Rotation;
_step = 0;
}
public int Step
{
get => _step;
set => _step = value;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
switch (_step)
{
case 0:
return SamplePosition(prompts);
case 1:
return SampleRotation(prompts);
default:
return SamplerStatus.Cancel;
}
}
private SamplerStatus SamplePosition(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify insertion point: ")
{
CursorType = CursorType.Crosshair
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (result.Value.IsEqualTo(_position))
return SamplerStatus.NoChange;
_position = result.Value;
return SamplerStatus.OK;
}
private SamplerStatus SampleRotation(JigPrompts prompts)
{
var opts = new JigPromptAngleOptions("\nSpecify rotation angle: ")
{
BasePoint = _position,
UseBasePoint = true,
DefaultValue = 0.0
};
PromptDoubleResult result = prompts.AcquireAngle(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (Math.Abs(result.Value - _rotation) < Tolerance.Global.EqualPoint)
return SamplerStatus.NoChange;
_rotation = result.Value;
return SamplerStatus.OK;
}
protected override bool Update()
{
var blockRef = (BlockReference)Entity;
switch (_step)
{
case 0:
blockRef.Position = _position;
break;
case 1:
blockRef.Rotation = _rotation;
break;
}
return true;
}
}
Call Editor.Drag() once per step, advancing the step counter between calls:
public static void InsertBlockWithJig(
Database db, Editor ed, ObjectId blockDefId)
{
using (var tr = db.TransactionManager.StartTransaction())
{
var btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
var blockRef = new BlockReference(Point3d.Origin, blockDefId);
var jig = new BlockInsertJig(blockRef);
// Step 0: pick position
jig.Step = 0;
PromptResult res = ed.Drag(jig);
if (res.Status != PromptStatus.OK)
return;
// Step 1: pick rotation
jig.Step = 1;
res = ed.Drag(jig);
if (res.Status != PromptStatus.OK)
return;
// Commit the entity
btr.AppendEntity(blockRef);
tr.AddNewlyCreatedDBObject(blockRef, true);
tr.Commit();
}
}
public class LineJig : EntityJig
{
private Point3d _startPoint;
private Point3d _endPoint;
public LineJig(Line line, Point3d startPoint)
: base(line)
{
_startPoint = startPoint;
_endPoint = startPoint;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify end point: ")
{
BasePoint = _startPoint,
UseBasePoint = true,
CursorType = CursorType.RubberBand
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (result.Value.IsEqualTo(_endPoint))
return SamplerStatus.NoChange;
_endPoint = result.Value;
return SamplerStatus.OK;
}
protected override bool Update()
{
var line = (Line)Entity;
line.StartPoint = _startPoint;
line.EndPoint = _endPoint;
return true;
}
}
public class MoveJig : EntityJig
{
private Point3d _basePoint;
private Point3d _currentPoint;
private Matrix3d _lastTransform;
public MoveJig(Entity entity, Point3d basePoint)
: base(entity)
{
_basePoint = basePoint;
_currentPoint = basePoint;
_lastTransform = Matrix3d.Identity;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify destination point: ")
{
BasePoint = _basePoint,
UseBasePoint = true,
CursorType = CursorType.RubberBand
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (result.Value.IsEqualTo(_currentPoint))
return SamplerStatus.NoChange;
_currentPoint = result.Value;
return SamplerStatus.OK;
}
protected override bool Update()
{
// Undo previous transform, apply new one
Entity.TransformBy(_lastTransform.Inverse());
Vector3d displacement = _currentPoint - _basePoint;
_lastTransform = Matrix3d.Displacement(displacement);
Entity.TransformBy(_lastTransform);
return true;
}
}
public class RectangleJig : DrawJig
{
private Point3d _corner1;
private Point3d _corner2;
public RectangleJig(Point3d firstCorner)
{
_corner1 = firstCorner;
_corner2 = firstCorner;
}
public Point3d Corner1 => _corner1;
public Point3d Corner2 => _corner2;
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var opts = new JigPromptPointOptions("\nSpecify opposite corner: ")
{
BasePoint = _corner1,
UseBasePoint = true,
CursorType = CursorType.RubberBand
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
if (result.Value.IsEqualTo(_corner2))
return SamplerStatus.NoChange;
_corner2 = result.Value;
return SamplerStatus.OK;
}
protected override bool WorldDraw(WorldDraw draw)
{
var pts = new Point3dCollection
{
_corner1,
new Point3d(_corner2.X, _corner1.Y, 0),
_corner2,
new Point3d(_corner1.X, _corner2.Y, 0),
_corner1 // close the rectangle
};
draw.Geometry.Polyline(pts, Vector3d.ZAxis, IntPtr.Zero);
return true;
}
}
SamplerStatus.OK every frame causes display flicker because AutoCAD redraws even when the entity has not moved. Compare new values against previous values and return NoChange when equal.EntityJig must be a transient (non-added) entity. Add it to the database only after Drag() returns PromptStatus.OK.Update() throws an exception, the jig terminates and the entity is left in an inconsistent state. Validate values before applying.Point3d is a struct; use IsEqualTo() or DistanceTo() < tolerance for reliable equality checks in Sampler().AcquireAngle is in radians, not degrees. Use it directly with Rotation properties (which also expect radians).PromptResult.Status == PromptStatus.Keyword and read PromptResult.StringResult to get the keyword. Return SamplerStatus.OK to keep the jig alive after processing a keyword.WorldDraw().Sampler(), Update(), or WorldDraw(). These run in a tight loop and transactions will severely degrade performance or cause errors.Drag() and AppendEntity().acad-editor-input -- prompt options, keyword handling, and input acquisition outside of jigsacad-geometry -- Point3d, Vector3d, Matrix3d, and transformation math used in jig calculationsacad-blocks -- BlockReference creation and attribute handling for block insertion jigsacad-polylines -- polyline construction techniques used with DrawJig preview rendering