TheSwamp
Code Red => .NET => Topic started by: gabep on June 06, 2008, 12:11:21 PM
-
Please excuse my cluelesness, but how do I draw an arc when I have the two endpoints and the center point of the arc.
I have been combing thru the .NET portion of objectARX help file, it is just getting me more confused... Is there a help file specifically for .NET?
Thanks!
-
Try this code sample
Public Shared Sub AddArc()
Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
Dim ed As Editor = AcadApp.DocumentManager.MdiActiveDocument.Editor
Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem
Dim nor As Vector3d = ucs.CoordinateSystem3d.Zaxis
Using ta As Transaction = db.TransactionManager.StartTransaction()
Try
Dim bt As BlockTable = CType(ta.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
Dim btr As BlockTableRecord = CType(ta.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite), BlockTableRecord)
Dim sp As New Point3d(5, 0, 0)
Dim ep As New Point3d(0, 5, 0)
Dim cr As New Point3d(0, 0, 0)
Dim sa As Double = AngleFromX(cr, sp, ed)
Dim ea As Double = AngleFromX(cr, ep, ed)
Dim rad As Double = 5.0
Dim arc As New Arc(cr, nor, rad, sa, ea)
btr.AppendEntity(arc)
ta.AddNewlyCreatedDBObject(arc, True)
ta.Commit()
Catch ex As Exception
ed.WriteMessage(ex.Message, _
"Exception", _
MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End Try
End Using
End Sub
Public Shared Function AngleFromX(ByVal pt1 As Point3d, ByVal pt2 As Point3d, ByVal ed As Editor) As Double
Dim ucsmtx As Matrix3d = ed.CurrentUserCoordinateSystem
Dim ucs As CoordinateSystem3d = ucsmtx.CoordinateSystem3d
Dim ucsplane As Plane = New Plane(ucs.Origin, ucs.Xaxis, ucs.Yaxis)
Dim vec As Vector3d = pt2 - pt1
Dim ang As Double = vec.AngleOnPlane(ucsplane)
Return ang
End Function
In .NET you can create arc with using of following constructors
(from ObjectARX):
Arc Class
Constructor
Arc()
--------------------------------------------------------------------------------
Arc(
Autodesk.AutoCAD.Geometry.Point3d center,
System.Double radius,
System.Double startAngle,
System.Double endAngle)
Parameters
center Input Autodesk.AutoCAD.Geometry.Point3d object.
radius Input System.Double object.
startAngle Input System.Double object.
endAngle Input System.Double object.
--------------------------------------------------------------------------------
Arc(
Autodesk.AutoCAD.Geometry.Point3d center,
Autodesk.AutoCAD.Geometry.Vector3d normal,
System.Double radius,
System.Double startAngle,
System.Double endAngle)
Parameters
center Input Autodesk.AutoCAD.Geometry.Point3d object.
normal Input Autodesk.AutoCAD.Geometry.Vector3d object.
radius Input System.Double object.
startAngle Input System.Double object.
endAngle Input System.Double object.
~'J'~
-
<................>
I have been combing thru the .NET portion of objectARX help file, it is just getting me more confused... Is there a help file specifically for .NET?
Thanks!
From the ObjectARX SDK ..
"... \docs\arxmgd.chm"
"... \docs\acad_mgd.chm"
-
You guys are just awesome!
Thanks! :-)
-
Try this code sample...
~'J'~
Hi Fixo,
I’m getting strange results from your routine, I wonder if you might check mine to see if I’m on the right track
Here is the class..
public class Arc3p : Arc
{
// Fields
private const double halfapi = 1.570796325;
private const double pi = 3.14159265;
// Methods
public Arc3p()
{
}
public Arc3p(Point3d startPoint, Point3d centerPoint, Point3d endPoint)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
Point3d p1 = myMath(startPoint, centerPoint);
Point3d p2 = myMath(centerPoint, endPoint);
Point3d cp = inters(p1, polarPoint(p1, halfapi + angle(startPoint, centerPoint, ed), 1.0),
p2, polarPoint(p2, halfapi + angle(centerPoint, endPoint, ed), 1.0));
base.Center = cp;
base.Radius = distance(cp, startPoint);
base.StartAngle = angle(cp, startPoint, ed);
base.EndAngle = angle(cp, endPoint, ed);
}
public Arc3p(IntPtr umanagedObjPtr, bool autoDelete)
: base(umanagedObjPtr, autoDelete)
{
}
public Arc3p(Point3d Center, double radius, double startAngle, double endAngle)
: base(Center, radius, startAngle, endAngle)
{
}
public Arc3p(Point3d Center, Vector3d normal, double radius, double startAngle, double endAngle)
: base(Center, normal, radius, startAngle, endAngle)
{
}
private static double angle(Point3d pt1, Point3d pt2, Editor ed)
{
CoordinateSystem3d ucs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
Plane ucsplane = new Plane(ucs.Origin, ucs.Xaxis, ucs.Yaxis);
Vector3d vec = (Vector3d)(pt2 - pt1);
return vec.AngleOnPlane(ucsplane);
}
private static double distance(Point3d from, Point3d to)
{
return from.DistanceTo(to);
}
private static Point3d inters(Point3d pt1, Point3d pt2, Point3d pt3, Point3d pt4)
{
using (Line3d l1 = new Line3d(pt1, pt2),
l2 = new Line3d(pt3, pt4))
{
return l1.IntersectWith(l2)[0];
}
}
private static Point3d myMath(Point3d pt1, Point3d pt2)
{
return new Point3d(pt1.X + pt2.X, pt1.Y + pt2.Y, pt1.Z + pt2.Z).DivideBy(2.0);
}
private static Point3d polarPoint(Point3d point, double angle, double distance)
{
return new Point3d(point.X + (distance * Math.Cos(angle)), point.Y + (distance * Math.Sin(angle)), point.Z);
}
}
call it like..
[CommandMethod("doit")]
public void doit()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
try
{
Database db = HostApplicationServices.WorkingDatabase;
AcDb.TransactionManager tm = db.TransactionManager;
using (Transaction tr = tm.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite));
//new arc class
Arc3p arcp3p1 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0));
btr.AppendEntity(arcp3p1);
tr.AddNewlyCreatedDBObject(arcp3p1,true);
Arc3p arcp3p2 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0));
btr.AppendEntity(arcp3p2);
tr.AddNewlyCreatedDBObject(arcp3p2, true);
tr.Commit();
}
}
catch (SystemException ex)
{
ed.WriteMessage("\n" + ex.Message);
ed.WriteMessage("\n" + ex.StackTrace);
}
}
Thanks
Dan
-
Hi Dan
Your routine just worked nice for me
(same as mine here, though)
:)
~'J'~
-
Hi Dan
Your routine just worked nice for me
(same as mine here, though)
:)
~'J'~
Thanks for trying it out for me. This is the result I’m getting ( your arc is in red) . I must be doing something wrong. Time for a shot of alcohol :lol:
-
Ah ya see, a couple of quick shots did the trick, it’s just a CW CCW thing. :lol:
-
Ah, I forgot to test my code in the arbitary UCS
Now I understand what are you talking about
Just I have not have a time to rewrite it now
Better yet to grab your class :)
Regards, :kewl:
~'J'~
-
Ah, I forgot to test my code in the arbitary UCS
Now I understand what are you talking about
Just I have not have a time to rewrite it now
Better yet to grab your class :)
Regards, :kewl:
~'J'~
Oh no need to rewrite anything, I just want to verify why my routine was acting
different than yours. I appreciate the help. :-)
-
Daniel I ran yours and the center isn't (50,25,0), maybe I didn't do it right.
I have messed with arcs a bit and they are pretty tricky.
Below is an attempt to add an arc using either ucs points or world points.
I had the hardest time with it as I was using
double startAng = Vector3d.XAxis.GetAngleTo(StartP - Cen);
and GetAngle does'nt work over 180 degrees (rotten thing to do, acad).
This works in 3d as far as I have tested, however the function NormalFromPoints
will give a different normal (reversed) if you change the order of the points you supply it.
This is a lot like fixo's code. (Fatty)
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
static public Arc ArcFromCenterWcs(Point3d Cen, Point3d StartP, Point3d EndP)
//3 point arc from 3 Wcs points
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Matrix3d ucs = doc.Editor.CurrentUserCoordinateSystem;
Vector3d norm;
if (Cen.Z == 0 && StartP.Z == 0 && EndP.Z==0)
norm = Vector3d.ZAxis;
else
norm = NormalFromPoints(Cen,StartP, EndP);
double Rad = Cen.DistanceTo(StartP);
Plane pn =new Plane(Cen, norm);
double startAng = (StartP - Cen).AngleOnPlane(pn);
double endAng = (EndP - Cen).AngleOnPlane(pn);
Arc oArc = new Arc(Cen, Vector3d.ZAxis, Rad, startAng, endAng);
oArc.Normal = norm;
oArc.ColorIndex = 1;
oArc = AddArc(oArc);
return oArc;
}
static public Arc ArcFromCenter(Point3d Cen, Point3d StartP, Point3d EndP)
//3 point arc from 3 ucs points
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Matrix3d ucs = doc.Editor.CurrentUserCoordinateSystem;
double Rad = Cen.DistanceTo(StartP);
CoordinateSystem3d cs = ucs.CoordinateSystem3d;
Plane pn = new Plane(); //world plane
double startAng = (StartP - Cen).AngleOnPlane(pn);
double endAng = (EndP - Cen).AngleOnPlane(pn);
Arc oArc = new Arc(Cen,Vector3d.ZAxis, Rad, startAng, endAng);
oArc.TransformBy(ucs);
oArc = AddArc(oArc);
return oArc;
}
static public Arc AddArc(Arc oArc)
{
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject
(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject
(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
btr.AppendEntity(oArc);
tr.AddNewlyCreatedDBObject(oArc, true);
tr.Commit();
}
return oArc;
}
static public Vector3d NormalFromPoints(Point3d p0, Point3d p1, Point3d p2)
//n = u×v = (V1-V0)×(V2-V0)
{
double Unit;
//Get distance from zero
Point3d x = new Point3d(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Point3d y = new Point3d(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
//get CrossProduct
Vector3d n = new Vector3d(x.Y * y.Z - x.Z * y.Y, x.Z * y.X - x.X * y.Z, x.X * y.Y - x.Y * y.X);
//Convert to unit normal
Unit = Math.Sqrt(n.X * n.X + n.Y * n.Y + n.Z * n.Z);
n = new Vector3d(n.X / Unit, n.Y / Unit, n.Z / Unit);
if (n.X == 0 && n.Y == 0 && n.Z == -1) n = new Vector3d(0, 0, 1);
return n;
}
-
Interesting, I haven’t tested your code yet, but is it possible we are talking about different centers? I am thinking more along the lines of “midpoint” of the arc.
-
Ok that does seem to be where I was goofing up. Fixos routine is correct then :oops:
-
Maybe both methods would be handy, I left everything in WCS, I guess one could do a TransformBy() on the instance? :mrgreen:
public class Arc3p : Arc
{
// Fields
private const double halfapi = 1.570796325;
private const double pi = 3.14159265;
// Methods
public Arc3p()
{
}
public Arc3p(Point3d startPoint, Point3d centerPoint, Point3d endPoint, bool centerIsMidPoint)
{
if (centerIsMidPoint)
{
Point3d p1 = myMath(startPoint, centerPoint);
Point3d p2 = myMath(centerPoint, endPoint);
Point3d cp = inters(p1, polarPoint(p1, halfapi + angle(startPoint, centerPoint), 1.0),
p2, polarPoint(p2, halfapi + angle(centerPoint, endPoint), 1.0));
base.Center = cp;
base.Radius = distance(cp, startPoint);
base.StartAngle = angle(cp, startPoint);
base.EndAngle = angle(cp, endPoint);
}
else
{
base.Center = centerPoint;
base.Radius = distance(centerPoint, startPoint);
base.StartAngle = angle(centerPoint, startPoint);
base.EndAngle = angle(centerPoint, endPoint);
}
}
public Arc3p(IntPtr umanagedObjPtr, bool autoDelete)
: base(umanagedObjPtr, autoDelete)
{
}
public Arc3p(Point3d Center, double radius, double startAngle, double endAngle)
: base(Center, radius, startAngle, endAngle)
{
}
public Arc3p(Point3d Center, Vector3d normal, double radius, double startAngle, double endAngle)
: base(Center, normal, radius, startAngle, endAngle)
{
}
private static double angle(Point3d pt1, Point3d pt2)
{
CoordinateSystem3d wcs = Matrix3d.Identity.CoordinateSystem3d;
Plane wcsplane = new Plane(wcs.Origin, wcs.Xaxis, wcs.Yaxis);
Vector3d vec = (Vector3d)(pt2 - pt1);
return vec.AngleOnPlane(wcsplane);
}
private static double distance(Point3d from, Point3d to)
{
return from.DistanceTo(to);
}
private static Point3d inters(Point3d pt1, Point3d pt2, Point3d pt3, Point3d pt4)
{
using (Line3d l1 = new Line3d(pt1, pt2),
l2 = new Line3d(pt3, pt4))
{
return l1.IntersectWith(l2)[0];
}
}
private static Point3d myMath(Point3d pt1, Point3d pt2)
{
return new Point3d(pt1.X + pt2.X, pt1.Y + pt2.Y, pt1.Z + pt2.Z).DivideBy(2.0);
}
private static Point3d polarPoint(Point3d point, double angle, double distance)
{
return new Point3d(point.X + (distance * Math.Cos(angle)), point.Y + (distance * Math.Sin(angle)), point.Z);
}
}
tester func
[CommandMethod("doit")]
public void doit()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
try
{
Database db = HostApplicationServices.WorkingDatabase;
AcDb.TransactionManager tm = db.TransactionManager;
using (Transaction tr = tm.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite));
//new arc class
Arc3p arcp3p1 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0),true);
btr.AppendEntity(arcp3p1);
tr.AddNewlyCreatedDBObject(arcp3p1,true);
Arc3p arcp3p2 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0),true);
btr.AppendEntity(arcp3p2);
tr.AddNewlyCreatedDBObject(arcp3p2, true);
Arc3p arcp3p3 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0),false);
btr.AppendEntity(arcp3p3);
tr.AddNewlyCreatedDBObject(arcp3p3, true);
Arc3p arcp3p4 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0), false);
btr.AppendEntity(arcp3p4);
tr.AddNewlyCreatedDBObject(arcp3p4, true);
tr.Commit();
}
}
catch (SystemException ex)
{
ed.WriteMessage("\n" + ex.Message);
ed.WriteMessage("\n" + ex.StackTrace);
}
}
-
That's a goer Dan.
I did both versions as I thought I would be getting ucs points back from a user, but I think the op has the most common use for an arc function, feeding it wcs points. The interesting point about wcs points is that you don't know (unless there is another clue somewhere) what plane the points should be in, so you need to make a new plane for every 3 points
-
That's a goer Dan.
I did both versions as I thought I would be getting ucs points back from a user, but I think the op has the most common use for an arc function, feeding it wcs points. The interesting point about wcs points is that you don't know (unless there is another clue somewhere) what plane the points should be in, so you need to make a new plane for every 3 points
That is interesting, something I’ll need to goof around with. According to the docs, all coordinates must be in WCS..
-
Does doing a transformby() in the instance give the desired results?
Arc3p arcp3p1 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0),true);
arcp3p1.TransformBy(ed.CurrentUserCoordinateSystem);
btr.AppendEntity(arcp3p1);
tr.AddNewlyCreatedDBObject(arcp3p1,true);
-
All coord's are stored in the db as wcs points for simplicity (else you would need to store a xform matrix as well) so all user picked points - if picked in any other ucs than wcs (quick test agains sys var) need the UcsToWcs mojo on them before creating entities, this puts the points back to wcs for correct/expected results.
hth.
-
ArcFromCenter successfully adds an arc from 3 ucs points, which is then transformed.
According to the docs, all coordinates must be in WCS
In this case the 3 points are taken to be in wcs and added as such.
The other function already has the points in wcs so doesn't need to be transformed. However the normal needs to be adjusted. The odd thing I found was that I usually have to insert an entity at 0,0 change the norm, then give it the correct insertion point. With an arc seems to be above all that.
-
here is another version of my class :roll:
public class Arc3p : Arc
{
// Fields
private const double halfapi = 1.570796325;
private const double pi = 3.14159265;
//
private Point3d m_startPoint;
private Point3d m_centerPoint;
private Point3d m_endPoint;
// Methods
public Arc3p()
{
}
public Arc3p(Point3d startPoint, Point3d centerPoint, Point3d endPoint, bool centerIsMidPoint)
{
if (centerIsMidPoint)
{
if (CounterClockWise(startPoint, centerPoint, endPoint))
{
m_startPoint = endPoint;
m_centerPoint = centerPoint;
m_endPoint = startPoint;
}
else
{
m_startPoint = startPoint;
m_centerPoint = centerPoint;
m_endPoint = endPoint;
}
Point3d p1 = myMath(m_startPoint, m_centerPoint);
Point3d p2 = myMath(m_centerPoint, m_endPoint);
Point3d cp = inters(polarPoint(p1, halfapi + angle(m_startPoint, m_centerPoint), 1.0), p1,
polarPoint(p2, halfapi + angle(m_centerPoint, m_endPoint), 1.0), p2);
base.Center = cp;
base.Radius = distance(cp, m_startPoint);
base.StartAngle = angle(cp, m_startPoint);
base.EndAngle = angle(cp, m_endPoint);
}
else
{
base.Center = centerPoint;
base.Radius = distance(centerPoint, startPoint);
base.StartAngle = angle(centerPoint, startPoint);
base.EndAngle = angle(centerPoint, endPoint);
}
}
public Arc3p(IntPtr umanagedObjPtr, bool autoDelete)
: base(umanagedObjPtr, autoDelete)
{
}
public Arc3p(Point3d Center, double radius, double startAngle, double endAngle)
: base(Center, radius, startAngle, endAngle)
{
}
public Arc3p(Point3d Center, Vector3d normal, double radius, double startAngle, double endAngle)
: base(Center, normal, radius, startAngle, endAngle)
{
}
private static double angle(Point3d pt1, Point3d pt2)
{
CoordinateSystem3d wcs = Matrix3d.Identity.CoordinateSystem3d;
Plane wcsplane = new Plane(wcs.Origin, wcs.Xaxis, wcs.Yaxis);
Vector3d vec = (Vector3d)(pt2 - pt1);
return vec.AngleOnPlane(wcsplane);
}
private static double distance(Point3d from, Point3d to)
{
return from.DistanceTo(to);
}
private static Point3d inters(Point3d pt1, Point3d pt2, Point3d pt3, Point3d pt4)
{
using (Line3d l1 = new Line3d(pt1, pt2),
l2 = new Line3d(pt3, pt4))
{
return l1.IntersectWith(l2)[0];
}
}
private static Point3d myMath(Point3d pt1, Point3d pt2)
{
return new Point3d(pt1.X + pt2.X, pt1.Y + pt2.Y, pt1.Z + pt2.Z).DivideBy(2.0);
}
private static Point3d polarPoint(Point3d point, double angle, double distance)
{
return new Point3d(point.X + (distance * Math.Cos(angle)),
point.Y + (distance * Math.Sin(angle)), point.Z);
}
//SixFeet6
public static bool CounterClockWise(Point3d pa, Point3d pb, Point3d pc)
{
return (((((pa[0] * pb[1]) - (pb[0] * pa[1])) +
((pb[0] * pc[1]) - (pc[0] * pb[1]))) +
((pc[0] * pa[1]) - (pa[0] * pc[1]))) < 0.0);
}
}