Example #1
0
        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();
        }
Example #2
0
        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();
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
        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);
        }