DeEng Posted April 10 Posted April 10 (edited) Hi everyone, I'm drawing slot holes (oval shapes) in AutoCAD using the .NET API. The arcs at the ends of the slot are drawn using center, start, and end points. My issue is: one arc is drawn correctly counter-clockwise, but the other one is drawn in the opposite (clockwise) direction, even though the same function is used. Here’s the code I’m using: public void DrawArcInAutoCAD(double cx, double cy, double sx, double sy, double ex, double ey, double radius, string layerName) { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (doc.LockDocument()) { using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); Point3d center = new Point3d(cx, cy, 0); Point3d startPt = new Point3d(sx, sy, 0); Point3d endPt = new Point3d(ex, ey, 0); double startAngle = Math.Atan2(sy - cy, sx - cx); double endAngle = Math.Atan2(ey - cy, ex - cx); if (startAngle < 0) startAngle += 2 * Math.PI; if (endAngle < 0) endAngle += 2 * Math.PI; if (endAngle <= startAngle) endAngle += 2 * Math.PI; Arc arc = new Arc(center, radius, startAngle, endAngle); arc.LayerId = GetOrCreateLayer(layerName); btr.AppendEntity(arc); tr.AddNewlyCreatedDBObject(arc, true); tr.Commit(); } } } Even though both arcs use the same logic and angle correction, one of them ends up being flipped. I'm assuming it's related to how start and end points are ordered, or perhaps how AutoCAD interprets angle direction? Any suggestions on how to make sure all arcs always follow the counter-clockwise direction, or how to detect and fix this? Thanks in advance! Edited April 10 by DeEng I forget the upload image Quote
CyberAngel Posted April 10 Posted April 10 I can't follow the code exactly, but could the issue be the point selection? The start point for one arc needs to be on the line opposite from the start point for the other. So you're traversing the oval and drawing the arc from the edge you're following. In other words, you have to flip the start and end points when you go to the other side. Quote
DeEng Posted April 10 Author Posted April 10 I implemented the suggestions: I'm using Math.Atan2 to calculate angles and normalizing them if negative. If endAngle < startAngle, I add 2π to ensure correct CCW drawing. I also tried checking Math.Abs(endAngle - startAngle) > Math.PI to swap the angles if needed. I even used cross product logic to detect if the arc should be drawn clockwise and swap the angles accordingly, but still… some arcs appear in the wrong direction. Here's an updated screenshot with coordinates labeled and a sample row of data used to draw the arc: [img]https://i.imgur.com/your_image_link_here.png[/img] As you can see, the arc on the left is correct, while the arc on the right is reversed (it should be clockwise). This is the row used to create that middle arc: 64 -38 31.8 -38 31.8 Do you have any suggestions on how to consistently control the arc direction when using AutoCAD .NET API's Arc class? Should I manually swap start/end points depending on geometry, or is there a more reliable method? else if (type == "O" && line.Length >= 5) { double x1 = double.Parse(line[1]); double y1 = double.Parse(line[2]); double x2 = double.Parse(line[3]); double y2 = double.Parse(line[4]); double rd = double.Parse(line[5]); double z1 = y1 + (rd / 2); double z2 = y2 + (rd / 2); double z3 = y1 - (rd / 2); double z4 = y2 - (rd / 2); DrawLineInAutoCAD(x1, y1, x2, y2, "SLOT"); DrawLineInAutoCAD(x1, z1, x2, z2, "PERI"); DrawLineInAutoCAD(x1, z3, x2, z4, "PERI"); // Slot merkezini hesapla double cx1 = x1; double cy1 = (z1 + z3) / 2; double cx2 = x2; double cy2 = (z2 + z4) / 2; DrawArcInAutoCAD(cx1, cy1, x1, z1, x1, z3, rd / 2, "HOLE"); DrawArcInAutoCAD(cx2, cy2, x2, z2, x2, z4, rd / 2, "HOLE"); AddTextWithAlignment($"{rd:F1}", x1, y1 - 10, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x1:F1},{y1:F1})", x1, y1, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x2:F1},{y2:F1})", x2, y2, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x1:F1},{z1:F1})", x1, z1, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x2:F1},{z2:F1})", x2, z2, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x1:F1},{z3:F1})", x1, z3, 3, "DIM", "LEFT"); AddTextWithAlignment($"({x2:F1},{z4:F1})", x2, z4, 3, "DIM", "LEFT"); } public void DrawArcInAutoCAD(double cx, double cy, double sx, double sy, double ex, double ey, double radius, string layerName) { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (doc.LockDocument()) { using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); Point3d center = new Point3d(cx, cy, 0); Point3d startPt = new Point3d(sx, sy, 0); Point3d endPt = new Point3d(ex, ey, 0); double startAngle = Math.Atan2(sy - cy, sx - cx); double endAngle = Math.Atan2(ey - cy, ex - cx); if (startAngle < 0) startAngle += 2 * Math.PI; if (endAngle < 0) endAngle += 2 * Math.PI; Vector3d vStart = startPt - center; Vector3d vEnd = endPt - center; double cross = vStart.X * vEnd.Y - vStart.Y * vEnd.X; if (Math.Abs(endAngle - startAngle) > Math.PI) { double temp = startAngle; startAngle = endAngle; endAngle = temp; } if (endAngle < startAngle) endAngle += 2 * Math.PI; Arc arc = new Arc(center, radius, startAngle, endAngle); arc.LayerId = GetOrCreateLayer(layerName); btr.AppendEntity(arc); tr.AddNewlyCreatedDBObject(arc, true); tr.Commit(); } } } I appreciate any help or ideas. Quote
BIGAL Posted April 10 Posted April 10 Must be it be a .NET solution ? ; draw a slot by AlanH (defun c:slot ( / ) (setq oldsnap (getvar 'osmode)) (setvar 'osmode 0) (setq pt1 (getpoint "\nPick centre point 1 ") pt2 (getpoint pt1 "\nPick second centre point ") ) (setq rad (getreal "\nEnter radius ")) (setq ang (angle pt1 pt2)) (setq dist (distance pt1 pt2)) (command "LIne" pt1 pt2 "") (setq obj (vlax-ename->vla-object (entlast))) (vla-offset obj rad) (setq off (entlast)) (setq pt1 (vlax-curve-getstartPoint off)) (setq pt6 (vlax-curve-getEndPoint off)) (entdel off) (vla-offset obj (- rad)) (setq off (entlast)) (setq pt3 (vlax-curve-getstartPoint off)) (setq pt4 (vlax-curve-getEndPoint off)) (entdel off) (setq mp (mapcar '* (mapcar '+ pt1 pt3) '(0.5 0.5))) (setq pt2 (polar mp (+ ang pi) rad)) (setq mp (mapcar '* (mapcar '+ pt4 pt6) '(0.5 0.5))) (setq pt5 (polar mp ang rad)) (command "pLINE" pt1 "w" 0.0 0.0 "arc" "s" pt2 pt3 "L" pt4 "arc" "s" pt5 pt6 "L" "c") (princ) ) (c:slot) Quote
Danielm103 Posted April 12 Posted April 12 Imho use vectors. Note angleTo is overloaded to take a normal @Ap.Command() def doit(): try: db = Db.curDb() p1 = Ge.Point3d(0, 0, 0) p2 = Ge.Point3d(0, 100, 0) vx = Ge.Vector3d.kXAxis vz = Ge.Vector3d.kZAxis d = p2 - p1 dn = p1 - p2 arc1 = Db.Arc(Ge.Point3d(0, 50, 0), 50, d.angleTo(vx, vz), dn.angleTo(vx, vz)) arc1.setColorIndex(5) arc2 = Db.Arc(Ge.Point3d(0, 50, 0), 50, dn.angleTo(vx, vz), d.angleTo(vx, vz)) arc2.setColorIndex(1) db.addToModelspace(arc1) db.addToModelspace(arc2) except Exception as err: traceback.print_exception(err) Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.