public static void SampleArc(Ellipse_Input ei, Ellipse_Output[] eo, bool big, bool clockwise, double resolution, out System.Drawing.PointF[] pointys) { List <System.Drawing.PointF> pts = new List <System.Drawing.PointF>(); SampleArc(ei, eo, big, clockwise, resolution, (x, y) => pts.Add(new System.Drawing.PointF((float)x, (float)y))); pointys = pts.ToArray(); }
public static void FindArc(Ellipse_Input ein, Ellipse_Output[] eoa, bool largeArc, bool clockwise, out int useSol, out double angleStart, out double angleSpan, out String debug) { // "Tests" String testString = String.Format("Test(new float[] {0}, new float[] {1}, false, true);", "{" + eoa[0].T1 + "f," + eoa[1].T1 + "f}", "{" + eoa[0].T2 + "f," + eoa[1].T2 + "f}"); //Test( new float[] { 119.9997276704309f, 0.00027269609041701644f }, new float[] { -179.99990015473779f, -60.000099478751331f }, false, true); //Test(new float[] { 3.43008202371647E-09f, 3.43008202371647E-09f }, new float[] { 179.99999999657f, 179.99999999657f }, false, true); // need vars... useSol = -1; // has t1 and t2; angleSpan = float.NaN; // go from eoa[use].T1 by useDx angleStart = float.NaN; debug = ""; bool gotIt = false; int fnd = 0; for (int i = 0; i < 2; i++) { float t1 = (float)eoa[i].T1; float t2 = (float)eoa[i].T2; foreach (var dt in GetAngles(t1, t2)) { debug += String.Format("t1={0:f1}, t2={1:f1}, dt={2:f1} ", t1, t2, dt); bool?cw, lr; if (ArcTry(t1, t2, dt, out cw, out lr)) { fnd++; debug += " TRUE " + (cw.HasValue ? cw.Value ? "cw" : "acw" : "cw&acw") + ", " + (lr.HasValue ? lr.Value ? "l" : "s" : "l&s"); if (!gotIt && (!cw.HasValue || cw.Value == clockwise) && (!lr.HasValue || lr.Value == largeArc)) { useSol = i; angleStart = t1 + ein.theta; angleSpan = dt; gotIt = true; debug += " FOUND"; } } debug += "\n"; } } if (!gotIt || fnd < 4) { throw new NotImplementedException(); } }
static void SampleArc(Ellipse_Input ei, Ellipse_Output[] eo, bool big, bool clockwise, double resolution, Assignor ass) { int usl; double t1, dt; String dummy; GeometryLib.Ellipse.FindArc(ei, eo, big, clockwise, out usl, out t1, out dt, out dummy); var us = eo[usl]; double s_rot = Math.Sin(-(ei.theta * Math.PI) / 180.0); double c_rot = Math.Cos(-(ei.theta * Math.PI) / 180.0); double rt1 = t1 * Math.PI / 180.0; double rdt = dt * Math.PI / 180.0; foreach (double theta_now in EllipseUtil.GetThetas(rt1, rdt, resolution, ei.rx, ei.ry)) { double s = Math.Sin(theta_now); double c = Math.Cos(theta_now); double x_now = c * us.rx; double y_now = s * us.ry; ass(x_now * c_rot - y_now * s_rot + us.X, x_now * s_rot + y_now * c_rot + us.Y); } }
static double tol = 1e-4; // that will do for subpixel stuff! FIXME there will be scale transform problems? public static IEnumerable <Ellipse_Output> Get_X0Y0(Ellipse_Input input) { if (input.rx < 0) { throw new ArgumentException("Ellipse_Input x-radius cannot be less than zero"); } if (input.ry < 0) { throw new ArgumentException("Ellipse_Input y-radius cannot be less than zero"); } double x1 = input.x1; double y1 = input.y1; double x2 = input.x2; double y2 = input.y2; double rx = input.rx; double ry = input.ry; double s = Math.Sin(Math.PI * input.theta / 180); double c = Math.Cos(Math.PI * input.theta / 180); double dx = x1 - x2; double dy = y1 - y2; double dxy = x1 * y1 - x2 * y2; double dx2 = x1 * x1 - x2 * x2; double dy2 = y1 * y1 - y2 * y2; // correct theta input.theta = AddAngle(input.theta % 360, 0); // Correct rx and ry, because they may be too small to fit on the points double ms = Math.Abs(s), mc = Math.Abs(c), mdx = Math.Abs(dx), mdy = Math.Abs(dy); double wid_x = mdx * mc + mdy * ms; double wid_y = mdy * mc + mdx * ms; if (rx < wid_x) { rx = wid_x; } if (ry < wid_y) { ry = wid_y; } double Cx = ry * ry * c * c + rx * rx * s * s; double Cy = ry * ry * s * s + rx * rx * c * c; double Cxy = s * c * (rx * rx - ry * ry); double Dx = 2.0 * Cx * dx + 2.0 * Cxy * dy; double Dy = 2.0 * Cy * dy + 2.0 * Cxy * dx; double Dxy = Cx * dx2 + Cy * dy2 + 2.0 * Cxy * dxy; // Alright, we get into trouble when dx=dy=0, unsolvable. there is also no arc to draw ;). // WE run into a parametric problem when cos(theta)*sin(theta) = 0, and either dy=0 or dy=0, and must // solve in a different manner, due to divide by-zero errors!. // Simplified solutions needed // - dx and dy are zero, so we need to just pick two angles on the ellipse and offset that are there. if (Math.Abs(dx) < tol && Math.Abs(dy) < tol) { // Just pick a couple stupid solutions with no delta theta FIXME input angle... // so, whats the angles for left and right of centre? double rcentre = AddAngle(0, input.theta); double lcentre = rcentre + 180; double dcentre = rx * Math.Abs(Math.Cos(Math.PI * rcentre / 180)) + ry * Math.Abs(Math.Sin(Math.PI * rcentre / 180)); yield return(new Ellipse_Output(input.x1 - dcentre, input.y1, rcentre, rcentre, rx, ry, false)); yield return(new Ellipse_Output(input.x1 + dcentre, input.y1, lcentre, lcentre, rx, ry, false)); yield break; } // - This means we have a line, and again we need to just pick a couple solutions for that line // - note, this means our code mayy have streched rx or ry by the tolerance...so it will be slightly arcy.. if (Math.Abs(rx) < tol || Math.Abs(ry) < tol) { // it's not necessary for dx or dy to be zero, but rx or ry will be zero, and a (respectively) horizontal or vertical line // rotated clockwise by the theta of length ry or rx respectly should join the two points. // infact we should have sqrt(dx^2+dy^2) = 2*(rx +ry). // so we'll shrink if need be, assume its got the right angle and put the centre var ln = Math.Sqrt(dx * dx + dy * dy); if (rx > ry) { rx += (ln - 2 * rx) / 2; } if (ry > rx) { ry += (ln - 2 * ry) / 2; } // of the ellipse at the midpoint of the two points double Xmid = (x1 + x2) / 2; double Ymid = (y1 + y2) / 2; // figuring out which is the starting and ending theta to use double t1u = 0, t2u = 0; if (rx > ry) { t1u = Get_Angle(x1 - Xmid, y1 - Ymid) + input.theta; t2u = Get_Angle(x2 - Xmid, y2 - Ymid) + input.theta; // Just return it twice! yield return(new Ellipse_Output(Xmid, Ymid, t1u, t2u, rx, ry, false)); yield return(new Ellipse_Output(Xmid, Ymid, t1u, t2u, rx, ry, false)); } else if (ry > rx) { t1u = Get_Angle(x1 - Xmid, y1 - Ymid) + input.theta; t2u = Get_Angle(x2 - Xmid, y2 - Ymid) + input.theta; // Just return it twice! yield return(new Ellipse_Output(Xmid, Ymid, t1u, t2u, rx, ry, false)); yield return(new Ellipse_Output(Xmid, Ymid, t1u, t2u, rx, ry, false)); } yield break; } // There's two ways to get solutions...we'll keep small numbers out of the bottom of fractions (i.e zeros) bool err = false; if (Math.Abs(Dx) < Math.Abs(Dy)) { double T1 = Cx * x1 - Cy * (Dx / Dy) * (y1 - (Dxy / Dy)) + Cxy * (y1 - (Dxy / Dy) - x1 * (Dx / Dy)); double dis = Cx + Cy * ((Dx * Dx) / (Dy * Dy)) - 2.0 * Cxy * (Dx / Dy) - Math.Pow(y1 - (Dxy / Dy) + x1 * (Dx / Dy), 2.0); //if (Math.Abs(dis) < tol) dis = 0; if (dis < 0) { err = true; dis = 0; } double T2 = rx * ry * Math.Sqrt(dis); double T3 = Cx + Cy * ((Dx * Dx) / (Dy * Dy)) - 2.0 * Cxy * (Dx / Dy); double Xs1 = (T1 + T2) / T3; double Xs2 = (T1 - T2) / T3; double Ys1 = (Dxy - Xs1 * Dx) / Dy; double Ys2 = (Dxy - Xs2 * Dx) / Dy; var th = input.theta; yield return(new Ellipse_Output(Xs1, Ys1, Get_Angle(x1 - Xs1, y1 - Ys1), Get_Angle(x2 - Xs1, y2 - Ys1), rx, ry, err)); yield return(new Ellipse_Output(Xs2, Ys2, Get_Angle(x1 - Xs2, y1 - Ys2), Get_Angle(x2 - Xs2, y2 - Ys2), rx, ry, err)); } else { double T1 = Cy * y1 - Cx * (Dy / Dx) * (x1 - (Dxy / Dx)) + Cxy * (x1 - (Dxy / Dx) - y1 * (Dy / Dx)); double dis = Cy + Cx * ((Dy * Dy) / (Dx * Dx)) - 2.0 * Cxy * (Dy / Dx) - Math.Pow(x1 - (Dxy / Dx) + y1 * (Dy / Dx), 2.0); //if (Math.Abs(dis) < tol) dis = 0; // allow a bit of negative if (dis < 0) { err = true; dis = 0; } double T2 = rx * ry * Math.Sqrt(dis); double T3 = Cy + Cx * ((Dy * Dy) / (Dx * Dx)) - 2.0 * Cxy * (Dy / Dx); double Ys1 = (T1 + T2) / T3; double Ys2 = (T1 - T2) / T3; double Xs1 = (Dxy - Ys1 * Dy) / Dx; double Xs2 = (Dxy - Ys2 * Dy) / Dx; var th = input.theta; yield return(new Ellipse_Output(Xs1, Ys1, Get_Angle(x1 - Xs1, y1 - Ys1), Get_Angle(x2 - Xs1, y2 - Ys1), rx, ry, err)); yield return(new Ellipse_Output(Xs2, Ys2, Get_Angle(x1 - Xs2, y1 - Ys2), Get_Angle(x2 - Xs2, y2 - Ys2), rx, ry, err)); } //Console.WriteLine("dx={0}", dx); //Console.WriteLine("dy={0}", dy); //Console.WriteLine("dxy={0}", dxy); //Console.WriteLine("dx2={0}", dx2); //Console.WriteLine("dy2={0}\n", dy2); //Console.WriteLine("Dx={0}", Dx); //Console.WriteLine("Dy={0}", Dy); //Console.WriteLine("Dxy={0}\n", Dxy); }