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.
I see void CalculateEndPoint too long while the video is no longer viewable.
ReplyDeleteCan you simplify it because dividing angle into multiple cases confuses me and other users
Thanks!
It is regrettable that I choose to use TechSmith's screen catching app/services to acquire and host the video clips of my posts more than 10 years ago, because the videos are Flash video, which are no longer supported with almost all web browsers.
ReplyDeleteYes, if you can view the video, you would be able to skip reading some detailed nitty gritty code and still get the idea the post is supposed to convey. But sorry, I currently do not have time to rebuild all the videos, nor revisit/modify the code (since they work as expected: no broken, no fix, right?), though I'd see if I can replace the video gradually in future.
I'd suggest to open a class library project with Visual Studio and copy the code from my posts, then run and see yourself.