Regardless it possible use/benefit an AutoCAD user may find, here is the code to do this. Yes, as you may have guessed, I used TransientGraphics again.
Here is the class that do the dynamic dragging. At the end of AngledDrag() call, the class provides two points (Point3d) - StartPoint and EndPoint as public read-only properties for the calling procedure to use.
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
namespace AngleLockedDrag
{
public class AngledDrag
{
private Document _dwg;
private Database _db;
private Editor _editor;
private Point3d _startPoint = new Point3d(0.0, 0.0, 0.0);
private Point3d _endPoint = new Point3d(0.0, 0.0, 0.0);
private double _dragAngle = 45.0;
private Line _dragLine = null;
private int _colorIndex = 1;
public AngledDrag(Document dwg)
{
_dwg = dwg;
_db = dwg.Database;
_editor = dwg.Editor;
}
public Point3d StartPoint
{
get { return _startPoint; }
}
public Point3d EndPoint
{
get { return _endPoint; }
}
#region public methods
public bool DragAtAngle()
{
_endPoint = _startPoint;
_editor.PointMonitor +=
new PointMonitorEventHandler(Editor_PointMonitor);
try
{
//Get end point
if (GetEndPoint())
{
return true;
}
else
{
return false;
}
}
finally
{
ClearTransientGraphics();
_editor.PointMonitor -= Editor_PointMonitor;
}
}
#endregion
#region private methods
private void Editor_PointMonitor(
object sender, PointMonitorEventArgs e)
{
DrawDragLine(e.Context.RawPoint);
if (_dragLine != null)
{
e.AppendToolTipText("Angle: " +
_dragAngle.ToString() + "\nLength: " +
_dragLine.Length.ToString());
}
else
{
e.AppendToolTipText("");
}
}
private void DrawDragLine(Point3d mousePoint)
{
ClearTransientGraphics();
Point3d pt = CalculateEndPoint(mousePoint);
_dragLine = new Line(_startPoint, pt);
_dragLine.SetDatabaseDefaults(_db);
_dragLine.ColorIndex = _colorIndex;
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.AddTransient(
_dragLine, TransientDrawingMode.Highlight, 128, col);
//whenever the dragged line updated, reset _endPoint
_endPoint = pt;
}
private void ClearTransientGraphics()
{
if (_dragLine != null)
{
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.
EraseTransient(_dragLine, col);
_dragLine.Dispose();
_dragLine = null;
}
}
private Point3d CalculateEndPoint(Point3d mousePoint)
{
Point3d pt = mousePoint;
if (_dragAngle <= 90.0 || _dragAngle >= 270.0)
{
if (mousePoint.X <= _startPoint.X)
{
pt = _startPoint;
}
else
{
if (_dragAngle <= 45.0 || _dragAngle >= 315.0)
{
double y = (mousePoint.X - _startPoint.X) *
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
mousePoint.X, _startPoint.Y + y, 0.0);
}
else
{
if (_dragAngle > 45.0 && _dragAngle <= 90.0)
{
if (mousePoint.Y < _startPoint.Y)
{
pt = _startPoint;
}
else
{
double x = (mousePoint.Y - _startPoint.Y) /
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
_startPoint.X + x, mousePoint.Y, 0.0);
}
}
else
{
if (mousePoint.Y > _startPoint.Y)
{
pt = _startPoint;
}
else
{
double x = (mousePoint.Y - _startPoint.Y) /
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
_startPoint.X + x, mousePoint.Y, 0.0);
}
}
}
return pt;
}
}
if (_dragAngle >= 90.0 && _dragAngle <= 270.0)
{
if (mousePoint.X >= _startPoint.X)
{
pt = _startPoint;
}
else
{
if (_dragAngle >= 135.0 && _dragAngle <= 225.0)
{
double y = (mousePoint.X - _startPoint.X) *
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
mousePoint.X, _startPoint.Y + y, 0.0);
}
else
{
if (_dragAngle >=90.0 && _dragAngle < 135.0)
{
if (mousePoint.Y <= _startPoint.Y)
{
pt = _startPoint;
}
else
{
double x = (mousePoint.Y - _startPoint.Y) /
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
_startPoint.X + x, mousePoint.Y, 0.0);
}
}
else
{
if (mousePoint.Y >= _startPoint.Y)
{
pt = _startPoint;
}
else
{
double x = (mousePoint.Y - _startPoint.Y) /
Math.Tan(_dragAngle * Math.PI / 180);
pt = new Point3d(
_startPoint.X + x, mousePoint.Y, 0.0);
}
}
}
return pt;
}
}
return pt;
}
private bool GetEndPoint()
{
//endPoint = new Point3d();
bool go = true;
bool picked = false;
while (go)
{
PromptPointOptions opt = new PromptPointOptions("\nPick point:");
//opt.BasePoint = _startPoint;
//opt.UseBasePoint = true;
opt.Keywords.Add("Start point");
opt.Keywords.Add("Angle");
opt.Keywords.Add("End point");
opt.Keywords.Add("eXit");
opt.Keywords.Default = "End point";
opt.AppendKeywordsToMessage = true;
opt.AllowArbitraryInput = false;
opt.AllowNone = false;
PromptPointResult res = _editor.GetPoint(opt);
if (res.Status == PromptStatus.Cancel)
{
go = false; ;
}
else
{
switch (res.Status)
{
case PromptStatus.Keyword:
//_editor.WriteMessage("\n" + res.StringResult);
if (res.StringResult.StartsWith("Start"))
{
SetStartPoint();
go = true;
}
if (res.StringResult.StartsWith("Angle"))
{
SetAngle();
go = true;
}
if (res.StringResult.StartsWith("eXit"))
{
go = false;
}
break;
case PromptStatus.OK:
//endPoint = res.Value;
picked = true;
go = false;
break;
default:
go = true;
break;
}
}
}
return picked;
}
private void SetStartPoint()
{
ClearTransientGraphics();
_editor.PointMonitor -= Editor_PointMonitor;
PromptPointOptions opt =
new PromptPointOptions("\nStart point:");
PromptPointResult res = _editor.GetPoint(opt);
if (res.Status == PromptStatus.OK)
{
_startPoint = res.Value;
}
_editor.PointMonitor +=
new PointMonitorEventHandler(Editor_PointMonitor);
}
private void SetAngle()
{
ClearTransientGraphics();
_editor.PointMonitor -= Editor_PointMonitor;
PromptDoubleOptions opt =
new PromptDoubleOptions("\nEnter drag-angle in degree [" +
_dragAngle.ToString() + "]: ");
opt.AllowNegative = false;
opt.AllowZero = true;
opt.AllowNone = true;
PromptDoubleResult res = _editor.GetDouble(opt);
if (res.Status == PromptStatus.OK)
{
_dragAngle = res.Value;
if (_dragAngle > 360.0) _dragAngle -= 360.0;
}
_editor.PointMonitor +=
new PointMonitorEventHandler(Editor_PointMonitor);
}
#endregion
}
}
Here is the command class that uses the AngleLockedDrag class to draw a Line in AutoCAD.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
[assembly: CommandClass(typeof(AngleLockedDrag.DragCommand))]
namespace AngleLockedDrag
{
public class DragCommand
{
[CommandMethod("AngledDrag")]
public void RunThisMethod()
{
Document dwg = Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
AngledDrag drag = new AngledDrag(dwg);
try
{
if (drag.DragAtAngle())
{
GenerateLine(dwg, drag.StartPoint, drag.EndPoint);
dwg.Editor.WriteMessage("\nMyCommand executed.");
}
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
dwg.Editor.WriteMessage("\nError: {0}\n", ex.Message);
}
}
private static void GenerateLine(
Document dwg, Point3d startPt, Point3d endPt)
{
using (Transaction tran =
dwg.Database.TransactionManager.StartTransaction())
{
BlockTableRecord br = (BlockTableRecord)tran.GetObject(
dwg.Database.CurrentSpaceId, OpenMode.ForWrite);
Line line = new Line(startPt, endPt);
line.SetDatabaseDefaults(dwg.Database);
br.AppendEntity(line);
tran.AddNewlyCreatedDBObject(line, true);
tran.Commit();
}
}
}
}
Here is the video clip that shows the "angled dragging" effect.