/// <summary> /// Inflates balloon body and target point /// </summary> public static void InflateBalloon(ref Rectangle body, ref Point target, int deltaBody, int deltaTarget) { Point center = new Point(body.Left + body.Width / 2, body.Top + body.Height / 2); PolarPoint pp = new PolarPoint(center, target); body.Inflate(deltaBody, deltaBody); pp.R += deltaTarget; target = pp.Point; target.Offset(center.X, center.Y); }
/// <summary> /// Calculates callout balloon vertexes suitable for curve drawing /// </summary> /// <param name="body">Balloon body coordinates</param> /// <param name="target">A point of balloon leg attachment</param> /// <param name="legSweep">Length of balloon leg attachment breach at balloon body edge, expressed in radians (arc length). A value such as PI/16 yields good results</param> /// <returns>An array of vertex points</returns> public static Point[] VectorizeBalloon(Rectangle body, Point target, double legSweep) { List <Point> result = new List <Point>(); Point center = new Point(body.Left + body.Width / 2, body.Top + body.Height / 2); PolarPoint trg = new PolarPoint(center, target); Point legStart = CartesianUtils.FindRayFromRectangleCenterSideIntersection( body, CartesianUtils.WrapAngle(trg.Theta, -legSweep / 2)); Point legEnd = CartesianUtils.FindRayFromRectangleCenterSideIntersection( body, CartesianUtils.WrapAngle(trg.Theta, +legSweep / 2)); result.Add(new Point(body.Left, body.Top)); result.Add(new Point(body.Right, body.Top)); result.Add(new Point(body.Right, body.Bottom)); result.Add(new Point(body.Left, body.Bottom)); result.Add(legStart); result.Add(target); result.Add(legEnd); //reorder points by azimuth so the curve can close and look like a balloon result.Sort(delegate(Point p1, Point p2) { PolarPoint pp1 = new PolarPoint(center, p1); PolarPoint pp2 = new PolarPoint(center, p2); if (pp1.Theta > pp2.Theta) { return(-1); } else { return(+1); } } ); return(result.ToArray()); }
/// <summary> /// Calculates callout balloon vertexes suitable for curve drawing /// </summary> /// <param name="body">Balloon body coordinates</param> /// <param name="target">A point of balloon leg attachment</param> /// <param name="legSweep">Length of balloon leg attachment breach at balloon body edge, expressed in radians (arc length). A value such as PI/16 yields good results</param> /// <returns>An array of vertex points</returns> public static Point[] VectorizeBalloon(Rectangle body, Point target, double legSweep) { List<Point> result = new List<Point>(); Point center = new Point(body.Left + body.Width / 2, body.Top + body.Height / 2); PolarPoint trg = new PolarPoint(center, target); Point legStart = CartesianUtils.FindRayFromRectangleCenterSideIntersection( body, CartesianUtils.WrapAngle(trg.Theta, -legSweep / 2)); Point legEnd = CartesianUtils.FindRayFromRectangleCenterSideIntersection( body, CartesianUtils.WrapAngle(trg.Theta, +legSweep / 2)); result.Add(new Point(body.Left, body.Top)); result.Add(new Point(body.Right, body.Top)); result.Add(new Point(body.Right, body.Bottom)); result.Add(new Point(body.Left, body.Bottom)); result.Add(legStart); result.Add(target); result.Add(legEnd); //reorder points by azimuth so the curve can close and look like a balloon result.Sort(delegate(Point p1, Point p2) { PolarPoint pp1 = new PolarPoint(center, p1); PolarPoint pp2 = new PolarPoint(center, p2); if (pp1.Theta > pp2.Theta) return -1; else return +1; } ); return result.ToArray(); }
/// <summary> /// Returns a point of intersection between a ray cast from the center of a rectangle /// under certain polar coordinate angle and a rectangle side /// </summary> public static Point FindRayFromRectangleCenterSideIntersection(Rectangle rect, double theta) { Point center = new Point(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); double rayLength = rect.Width > rect.Height ? rect.Width : rect.Height; //make ray "infinite" in comparison to rect if (rayLength < 100) rayLength = 100; //safeguard PolarPoint rayEnd = new PolarPoint(rayLength, theta);//create ray "end" point double k = (rayEnd.Point.X!=0)? ((double)rayEnd.Point.Y) / ((double)rayEnd.Point.X) : 0; //get line incline aka. y = kx int x, y; List<Point> lst = new List<Point>(); //north x = center.X + ((k != 0) ? (int)((rect.Top - center.Y) / k) : 0); y = rect.Top; if ((x >= rect.Left) && (x <= rect.Right)) lst.Add(new Point(x, y)); //south x = center.X + ((k != 0) ? (int)((rect.Bottom - center.Y) / k) : 0); y = rect.Bottom; if ((x >= rect.Left) && (x <= rect.Right)) lst.Add(new Point(x, y)); //east x = rect.Right; y = center.Y + (int)(k * (rect.Right - center.X)); if ((y >= rect.Top) && (y <= rect.Bottom)) lst.Add(new Point(x, y)); //west x = rect.Left; y = center.Y + (int)(k * (rect.Left - center.X)); if ((y >= rect.Top) && (y <= rect.Bottom)) lst.Add(new Point(x, y)); Point minPoint = new Point(int.MaxValue, int.MaxValue); int minDistance = int.MaxValue; Point re = rayEnd.Point; //rayEnd is relative to absolute 0,0 re.Offset(center.X, center.Y); // need to make relative to rectangle center foreach (Point p in lst) //find closest point { int dst = Distance(p, re); if (dst < minDistance) { minPoint = p; minDistance = dst; } } return minPoint; }
public void PolarPointToPoint() { var polar = new PolarPoint(100D, Math.PI / 4); var decart = polar.Point; Assert.AreEqual(70D, Math.Floor((double)decart.X)); Assert.AreEqual(70D, Math.Floor((double)decart.Y)); }
/// <summary> /// Returns a point of intersection between a ray cast from the center of a rectangle /// under certain polar coordinate angle and a rectangle side /// </summary> public static Point FindRayFromRectangleCenterSideIntersection(Rectangle rect, double theta) { Point center = new Point(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); double rayLength = rect.Width > rect.Height ? rect.Width : rect.Height; //make ray "infinite" in comparison to rect if (rayLength < 100) { rayLength = 100; //safeguard } PolarPoint rayEnd = new PolarPoint(rayLength, theta); //create ray "end" point double k = (rayEnd.Point.X != 0)? ((double)rayEnd.Point.Y) / ((double)rayEnd.Point.X) : 0; //get line incline aka. y = kx int x, y; List <Point> lst = new List <Point>(); //north x = center.X + ((k != 0) ? (int)((rect.Top - center.Y) / k) : 0); y = rect.Top; if ((x >= rect.Left) && (x <= rect.Right)) { lst.Add(new Point(x, y)); } //south x = center.X + ((k != 0) ? (int)((rect.Bottom - center.Y) / k) : 0); y = rect.Bottom; if ((x >= rect.Left) && (x <= rect.Right)) { lst.Add(new Point(x, y)); } //east x = rect.Right; y = center.Y + (int)(k * (rect.Right - center.X)); if ((y >= rect.Top) && (y <= rect.Bottom)) { lst.Add(new Point(x, y)); } //west x = rect.Left; y = center.Y + (int)(k * (rect.Left - center.X)); if ((y >= rect.Top) && (y <= rect.Bottom)) { lst.Add(new Point(x, y)); } Point minPoint = new Point(int.MaxValue, int.MaxValue); int minDistance = int.MaxValue; Point re = rayEnd.Point; //rayEnd is relative to absolute 0,0 re.Offset(center.X, center.Y); // need to make relative to rectangle center foreach (Point p in lst) //find closest point { int dst = Distance(p, re); if (dst < minDistance) { minPoint = p; minDistance = dst; } } return(minPoint); }
public void PolarPointTheta() { var polar = new PolarPoint(100D, Math.PI); Assert.AreEqual(314D, Math.Floor(polar.Theta * 100D)); polar.Theta = 1.18D; Assert.AreEqual(118D, Math.Floor(polar.Theta * 100D)); }
public void PolarPointRadius() { var polar = new PolarPoint(100D, Math.PI); Assert.AreEqual(100D, polar.R); polar.R = 125D; Assert.AreEqual(125D, polar.R); }
public void PolarPointIsEqual() { var polar1 = new PolarPoint(100D, 1.2D); var polar2 = new PolarPoint(10D, 2.17D); var polar3 = new PolarPoint(100D, 1.2D); Assert.AreNotEqual(polar1, polar2); Assert.AreEqual(polar1, polar3); }
public void PolarPointInvalid() { try { var pp = new PolarPoint(100, 789); Assert.Fail(); } catch (NFXException ex) { Assert.IsTrue(ex.Message.Contains("angle")); } }
public void PointToPolarPoint() { var center = new Point(0, 0); var pnt = new Point(150, 0); var polar = new PolarPoint(center, pnt); Assert.AreEqual(150D, polar.R); Assert.AreEqual(0D, polar.Theta); }