Beispiel #1
0
        public static Point2d[] EllipseEllipse(Ellipse2d el1, Ellipse2d el2)
        {
            //reduce this problem to a circle-ellipse problem by
            //rotating ellipse 1 down, scaling it to circle and then
            //rotate ellipse2 down.
            Transform2d tr = Transform2d.Rotate(-el1.Rotation) * Transform2d.Stretch(1.0, 1.0 / el1.Ratio);

            //dont modify originals:
            el1 = new Ellipse2d(el1);
            el2 = new Ellipse2d(el2);
            el1.Transform(tr);
            el2.Transform(tr);

            Point2d[] res = EllipseCircle(el2, new Circle2d(el1.X, el1.Y, el1.MajorRadius));

            if (res == null)
            {
                return(null);
            }

            Transform2d trinv = (tr).Inversed;

            for (int l = 0; l < res.Length; l++)
            {
                res[l] = res[l].GetTransformed(trinv);
            }

            return(res);
        }
Beispiel #2
0
        public Point2d GetTransformed(Transform2d t)
        {
            double tx, ty;

            t.Apply(X, Y, out tx, out ty, true);
            return(new Point2d(tx, ty));
        }
Beispiel #3
0
 public void Transform(Transform2d t)
 {
     for (int l = 0; l < pts.Count; l++)
     {
         pts[l] = pts[l].GetTransformed(t);
     }
 }
Beispiel #4
0
        public Point2d[] Perpendicular(Point2d from)
        {
            double      i, j; //i,j is from-point in standard space
            Transform2d tr = ToStandardPosition;

            tr.Apply(from.X, from.Y, out i, out j, true);

            //cubic coefficients gotten from langarnge multiplier minimizing distance from i,j to curve
            double[] xs = RealPolynomial.SolveCubic2(-1, 0.0, j - 0.25, 0.25 * i);
            if (xs == null)
            {
                return(null);
            }

            Point2d[] res = new Point2d[xs.Length];
            tr = tr.Inversed;
            int respos = 0;

            foreach (double x in xs)
            {
                tr.Apply(x, x * x, out i, out j, true);
                res[respos++] = new Point2d(i, j);
            }

            return(res);
        }
Beispiel #5
0
        public Vector2d GetTransformed(Transform2d t)
        {
            double tx, ty;

            t.Apply(X, Y, out tx, out ty, false);
            return(new Vector2d(tx, ty));
        }
Beispiel #6
0
        public override GeneralConic2d ToGeneralConic()
        {
            Transform2d    tr    = Transform2d.Scale(MajorRadius) * Transform2d.Rotate(Rotation) * Transform2d.Translate(center.X, center.Y);
            GeneralConic2d elcon = new GeneralConic2d(1, 0, 1.0 / (sigratio * sigratio), 0, 0, -1); //x^2+(1/b)^2-1=0 => unit ellipse

            elcon.Transform(tr);                                                                    //transform conic to position of ellipse
            return(elcon);                                                                          //TODO: optimize this function
        }
Beispiel #7
0
        public override GeneralConic2d ToGeneralConic()
        {
            Transform2d    tr  = Transform2d.Rotate(rotation) * Transform2d.Translate(vertex.X, vertex.Y);
            GeneralConic2d res = new GeneralConic2d(a, 0, 0, 0, -1, 0); //y=ax^2

            res.Transform(tr);
            return(res); //TODO: optimize this function
        }
Beispiel #8
0
        public override Point2d PointAt(double t)
        {
            double  f   = FocalDistance;
            Point2d res = new Point2d(t, a * t * t);

            //TODO: need to be optimized!!
            return(res.GetTransformed(Transform2d.Rotate(rotation) * Transform2d.Translate(vertex.X, vertex.Y)));
        }
Beispiel #9
0
        public override GeneralConic2d ToGeneralConic()
        {
            //TODO: test this function

            Transform2d    tr     = Transform2d.Scale(majoraxis.Length) * Transform2d.Rotate(Rotation) * Transform2d.Translate(center.X, center.Y);
            GeneralConic2d hypcon = new GeneralConic2d(1, 0, -1.0 / (ratio * ratio), 0, 0, -1); //x^2-(y/b)^2-1=0 => unit

            hypcon.Transform(tr);

            return(hypcon); //TODO: optimize this function
        }
Beispiel #10
0
        public static Point2d[] ParabolaParabola(Parabola2d pab1, Parabola2d pab2)  //tested ok
        {
            Transform2d tr = pab1.ToStandardPosition;

            pab2 = new Parabola2d(pab2); //copy for transformation
            pab2.Transform(tr);
            var ptset = StandardPosParabolaGeneralConic(pab2.ToGeneralConic());

            ptset.Transform(tr.Inversed);
            return(ptset.ToArray());
        }
Beispiel #11
0
        public bool Contains(Point2d pt)
        {
            Transform2d tr = ToStandardPosition;
            double      i, j;

            tr.Apply(pt.X, pt.Y, out i, out j, true);

            double dy = i * i - j; //y of parabola in std. pos subtracted with point y

            return(dy <= 0.0);
        }
Beispiel #12
0
        public static Point2d[] HyperbolaHyperbola(Hyperbola2d hyp1, Hyperbola2d hyp2)
        {
            Transform2d tr = hyp1.ToStandardPosition;

            hyp2 = new Hyperbola2d(hyp2); //copy for modification

            hyp2.Transform(tr);
            Point2dSet res = StdHyperbolaConic(hyp1.Ratio, hyp2);

            res.InverseTransform(tr);
            return(res.ToArray());
        }
Beispiel #13
0
        public override bool Transform(Transform2d t)
        {
            //TODO: only manages uniform transformations. Fix this.

            Vector2d rv = Vector2d.FromAngleAndLength(rotation, FocalDistance);

            rv       = rv.GetTransformed(t);
            rotation = rv.Angle;
            vertex   = vertex.GetTransformed(t);
            a        = 1.0 / (4 * rv.Length);
            return(true);
        }
Beispiel #14
0
        public override Vector2d Tangent(Point2d where)
        {
            Transform2d tr = Transform2d.Rotate(-rotation); // ToStandardPosition;

            where = where.GetTransformed(tr);
            Point2d stdvertex = vertex.GetTransformed(tr);

            double slope = 2 * a * (where.X - stdvertex.X); ///(4*FocalDistance); //from diffrentiation

            //TODO: reverse vector if wrong direction
            return(Vector2d.FromSlope(slope).GetTransformed(tr.Inversed));
        }
Beispiel #15
0
        public static Point2d[] ParabolaHyperbola(Parabola2d pab, Hyperbola2d hyp) //tested ok
        {
            Transform2d tr = pab.ToStandardPosition;                               //y=x^2

            hyp = new Hyperbola2d(hyp);                                            //copy for transformation
            hyp.Transform(tr);                                                     //to standard space of parabola for stabillity

            GeneralConic2d gencon = hyp.ToGeneralConic();
            var            ptset  = StandardPosParabolaGeneralConic(gencon);

            ptset.Transform(tr.Inversed);
            return(ptset.ToArray());
        }
Beispiel #16
0
        public override bool Transform(Transform2d t)
        {
            if (t.IsUniform)
            {
                return(false);
            }

            start = start.GetTransformed(t);
            end   = end.GetTransformed(t);

            if (t.Determinant < 0.0)
            {
                bulge = -bulge; //mirror
            }
            return(true);
        }
Beispiel #17
0
        public override bool Transform(Transform2d matrix)
        {
            double majax = MajorRadius;
            double minax = MinorRadius;
            double rot   = Rotation;
            bool   reverse;

            Ellipse_Transform(ref majax, ref minax, ref rot, ref center, matrix, out reverse);

            majoraxis = Vector2d.FromAngleAndLength(rot, majax);
            sigratio  = minax / majax;

            //TODO: clean up this code
            //TODO: handle reversed ellipse

            return(true);
        }
Beispiel #18
0
        public override bool Transform(Transform2d tr)
        {
            //Inspired by conmat.c from graphics gems V, but a lot simplified

            // Compute M' = Inv(TMat).M.Transpose(Inv(TMat))
            Matrix inv = tr.Inversed.ToMatrix();
            //Matrix conic = inv.Transposed * ToMatrix() * inv;
            Matrix conic = inv.Transposed * ToMatrix() * inv;

            a = conic[0, 0];           // return to conic form
            b = conic[0, 1] + conic[1, 0];
            c = conic[1, 1];
            d = conic[0, 2] + conic[2, 0];
            e = conic[1, 2] + conic[2, 1];
            f = conic[2, 2];

            return(true);
        }
Beispiel #19
0
        public static Point2d[] HyperbolaEllipse(Hyperbola2d hyp, Ellipse2d elp)
        {
            //TODO: this is probably more stable intersecting hyperbola with unitcircle. Rewrite.

            Transform2d tr = hyp.ToStandardPosition;

            hyp = new Hyperbola2d(hyp);
            elp = new Ellipse2d(elp);
            hyp.Transform(tr);
            elp.Transform(tr);

            GeneralConic2d hcon = new GeneralConic2d(1, 0.0, -1 / (hyp.B * hyp.B), 0.0, 0.0, -1);

            Point2dSet pset = new Point2dSet();

            pset.AddRange(ConicConic(hcon, elp.ToGeneralConic()));
            pset.Transform(tr.Inversed);
            return(pset.ToArray());
        }
Beispiel #20
0
        public static double[] ParabolaLineParamteric(Parabola2d pab, Line2d lin) //tested ok
        {
            double x1, y1, x2, y2;                                                //line points in parabola standard position

            Transform2d tr = pab.ToStandardPosition;                              //intersect line with y=x^2 => easier

            tr.Apply(lin.X1, lin.Y1, out x1, out y1, true);
            tr.Apply(lin.X2, lin.Y2, out x2, out y2, true);

            double dx = x2 - x1;
            double dy = y2 - y1;
            double c2 = -dx * dx;
            double c1 = dy - 2 * dx * x1;
            double c0 = y1 - x1 * x1;

            //y1-x1^2+t*(dy-2*dx*x1)-dx^2*t^2=0

            double[] ts = RealPolynomial.SolveQuadric(c2, c1, c0);

            return(ts);
        }
Beispiel #21
0
        public static Point2d[] EllipseEllipse2(Ellipse2d elp1, Ellipse2d elp2)
        {
            //TODO: check if this is better than EllipseEllipse in stabillity and replace it or remove this function

            Transform2d tr = elp1.ToStandardPosition;

            elp2 = new Ellipse2d(elp2); //dont alter the original ellipse
            elp2.Transform(tr);

            elp1 = new Ellipse2d(elp1);
            elp1.Transform(tr);

            GeneralConic2d con1 = new GeneralConic2d(1.0, 0.0, 1 / (elp1.Ratio * elp1.Ratio), 0.0, 0.0, -1.0);
            GeneralConic2d con2 = elp2.ToGeneralConic(); // GeneralConic2d.FromEllipse(elp2);

            Point2dSet pset = new Point2dSet();

            pset.AddRange(ConicConic(con1, con2));
            pset.Transform(tr.Inversed);
            return(pset.ToArray());
        }
Beispiel #22
0
        /// <summary>
        /// Intersects a line with a conic that is in standard position, that is, not rotated and
        /// centered at 0,0
        /// </summary>
        /// <param name="con"></param>
        /// <param name="lin"></param>
        /// <returns>A list of parameters on line that is intersection points, or null if no intersections</returns>
        private static double[] ConicLineParametric(GeneralConic2d con, Line2d lin)
        {
            //We construct a matrix so that: conic is unrotated (B term=0) and line starts at origo and has length=1.0
            //This is to improve stabillity of the equation

            double invlen = 1.0 / lin.Length;

            if (double.IsInfinity(invlen))
            {
                return(null);    //zero length line does not intersect
            }
            Transform2d tr = Transform2d.Translate(-lin.X1, -lin.Y1) * Transform2d.Rotate(-con.Rotation) * Transform2d.Scale(invlen);

            GeneralConic2d c = new GeneralConic2d(con);  //copy for modification
            double         x1 = lin.X2, y1 = lin.Y2;

            c.Transform(tr);
            tr.Apply(x1, y1, out x1, out y1, true); //transformed line end


            double t2 = y1 * y1 * c.C + x1 * x1 * c.A;
            double t1 = y1 * c.E + x1 * c.D;
            double t0 = c.F;

            double[] ts = RealPolynomial.SolveQuadric(t2, t1, t0);

            return(ts);

            /*double dx=lin.DX;
             * double dy=lin.DY;
             * double x0=lin.X1;
             * double y0=lin.Y1;
             *
             * double t2=con.C*dy*dy+con.A*dx*dx;
             * double t1=2*con.C*dy*y0+2*con.A*dx*x0+dy*con.E+con.D*dx;
             * double t0=con.C*y0*y0+con.E*y0+con.A*x0*x0+con.D*x0+con.F;
             *
             * return RealPolynomial.SolveQuadric(t2, t1, t0, 1e-9);*/
        }
Beispiel #23
0
        public override bool Transform(Transform2d t)
        {
            //transform hyperbola centered at origin, because it's more stable general conic
            Hyperbola2d hyp = new Hyperbola2d(this);

            hyp.center = Point2d.Origo;
            var gencon = hyp.ToGeneralConic();

            if (!gencon.Transform(new Transform2d(t.AX, t.AY, t.BX, t.BY, 0.0, 0.0)))
            {
                return(false);
            }

            hyp = gencon.Reduce() as Hyperbola2d;
            if (hyp == null)
            {
                return(false);
            }

            //now transform centerpoint separately,
            //and write bac to this
            center    = center.GetTransformed(t);
            ratio     = hyp.ratio;
            majoraxis = hyp.majoraxis;

            return(true);


            /* double majax = majoraxis.Length;
             * double minax = -majax * ratio;
             * double rot = Rotation;
             * bool reverse;
             * Hyperbola_Transform(ref majax, ref minax, ref rot, ref center, t, out reverse);
             *
             * majoraxis = Vector2d.FromAngleAndLength(rot, majax);
             * ratio = minax / majax;
             *
             * return true;*/
        }
Beispiel #24
0
        public static double[] HyperbolaLineParametric(Hyperbola2d hyp, Line2d lin)
        {
            // Computes intersection points with a hyperbola and a line
            // solved and created by Robert.P. 2013-02-11
            //
            // solution is created by transforming system to hyperbola standard position,
            // and then solving the system x^2/a^2-y^2/b^2-1=0 , x=x0+t*dx and y=y0+t*dy (note that a is 1 in std. pos.)

            Transform2d tr = hyp.ToStandardPosition;

            //extract standard spaced line
            double x0, y0, x1, y1, dx, dy, b = hyp.Ratio;

            tr.Apply(lin.X1, lin.Y1, out x0, out y0, true);
            tr.Apply(lin.X2, lin.Y2, out x1, out y1, true);
            dx = x1 - x0; dy = y1 - y0;

            double t2 = -dy * dy + b * b * dx * dx;
            double t1 = -2 * dy * y0 + 2 * b * b * dx * x0;
            double t0 = -y0 * y0 + b * b * x0 * x0 - b * b;

            return(RealPolynomial.SolveQuadric(t2, t1, t0, 0.0));
        }
Beispiel #25
0
        public static Circle2d[] LinePointPoint(Line2d li, Point2d pt1, Point2d pt2)
        {
            // max two solutions
            // solution created by Robert.P. 2013-02-07

            List <Circle2d> res = null;

            // transform problem so that we have a vertical line thru origo which simplifies stuff a lot
            Transform2d toorg = Transform2d.Translate(-li.X1, -li.Y1) * Transform2d.Rotate(-li.Angle + MathUtil.Deg90);
            Transform2d fromorg = toorg.Inversed;
            double      i, j, k, l;

            toorg.Apply(pt1.X, pt1.Y, out i, out j, true);
            toorg.Apply(pt2.X, pt2.Y, out k, out l, true);


            double y2 = 2 * k - 2 * i;
            double y1 = 4 * i * l - 4 * j * k;
            double y0 = -2 * i * l * l - 2 * i * k * k + (2 * j * j + 2 * i * i) * k;

            double[] ys = RealPolynomial.SolveQuadric(y2, y1, y0);
            if (ys == null)
            {
                return(null); //no solutions
            }
            foreach (double y in ys)
            {
                double xx = (y * y - 2 * j * y + j * j + i * i) / (2 * i), yy = y; //TODO: what if vertical line
                double rad = Math.Abs(xx);

                fromorg.Apply(xx, yy, out xx, out yy, true);
                AddResult(ref res, xx, yy, rad);
            }


            return(MakeResult(res));
        }
Beispiel #26
0
        public static Point2d[] EllipseCircle(Ellipse2d el, Circle2d ci)
        {
            Transform2d tr = el.ToStandardPosition;

            ci = new Circle2d(ci); //dont modify original circle, but this copy
            ci.Transform(tr);

            double b = el.Ratio, b2 = b * b, b4 = b2 * b2;
            double i = ci.Center.X, i2 = i * i, i4 = i2 * i2;
            double j = ci.Center.Y, j2 = j * j, j4 = j2 * j2;
            double r = ci.Radius, r2 = r * r, r4 = r2 * r2;

            double x4 = b4 - 2 * b2 + 1;
            double x3 = 4 * b2 * i - 4 * i;
            double x2 = b2 * (2 * r2 + 2 * j2 - 2 * i2 + 2) - 2 * r2 + 2 * j2 + 6 * i2 - 2 * b4;
            double x1 = 4 * i * r2 - 4 * i * j2 - 4 * i * i * i - 4 * b2 * i;
            double x0 = r4 + (-2 * j2 - 2 * i2) * r2 + b2 * (-2 * r2 - 2 * j2 + 2 * i2) + j4 + 2 * i2 * j2 + i4 + b4;
            //double[] xs = RealPolynomial.SolveQuartic2(x4, x3, x2, x1, x0, 1e-30);

            RealPolynomial rp = new RealPolynomial(x4, x3, x2, x1, x0);

            double[] xs = rp.FindRoots(true);

            if (xs == null)
            {
                return(null);               //no intersections
            }
            Point2dSet resultset = new Point2dSet();

            foreach (double x in xs)
            {
                //test the two possible y:s to be solutions for this x
                double y = (1 - x * x) * b2;
                if (y < 0.0)
                {
                    continue;
                }
                y = Math.Sqrt(y);

                for (int t = 0; t < 2; t++)                                             //test booth y solutions...
                {
                    double err  = x * x + y * y / b2 - 1.0;                             //on ellipse
                    double err2 = MathUtil.Square(x - i) + MathUtil.Square(y - j) - r2; //on circle
                    if (MathUtil.IsZero(err, 1e-7) && MathUtil.IsZero(err2, MathUtil.Epsilon))
                    {
                        resultset.Add(new Point2d(x, y));
                    }

                    y = -y;  // ...by inverting y in second turn
                }
            }

            if (resultset.Count == 0)
            {
                return(null);
            }

            resultset.Transform(tr.Inversed); //back to original position

            return(resultset.ToArray());
        }
Beispiel #27
0
        public static Circle2d[] CircleCircleCircle(Circle2d ci1, Circle2d ci2, Circle2d ci3)
        {
            // see http://www.arcenciel.co.uk/geometry/ for explanation

            List <Circle2d> result = null;
            double          r1, r2, r3, a, b, c, t, A, B, C;
            double          fRadius, xc, yc, distc1c2;

            double[] roots;

            // if all circles concentric, there are no solutions
            distc1c2 = ci1.Center.Distance(ci2.Center);
            if (MathUtil.IsZero(distc1c2) && MathUtil.IsZero(ci2.Center.Distance(ci3.Center)))
            {
                return(null);
            }

            // make sure first 2 circles are not concentric
            // if so swap ci2,ci3
            if (MathUtil.IsZero(distc1c2))
            {
                var tmp = ci2; ci2 = ci3; ci3 = ci2;
            }


            // transform input so that ci1 is at origo and ci2 is on xaxis
            Transform2d trans = Transform2d.Translate(Point2d.Origo - ci1.Center) * Transform2d.Rotate(-ci1.Center.Angle(ci2.Center));

            ci1 = new Circle2d(ci1);
            ci1.Transform(trans);
            ci2 = new Circle2d(ci2);
            ci2.Transform(trans);
            ci3 = new Circle2d(ci3);
            ci3.Transform(trans);



            // Negate the radii to get all combinations

            for (int iCase = 0; iCase < 8; ++iCase)
            {
                r1 = ((iCase & 1) == 0) ? ci1.Radius : -ci1.Radius;
                r2 = ((iCase & 2) == 0) ? ci2.Radius : -ci2.Radius;
                r3 = ((iCase & 4) == 0) ? ci3.Radius : -ci3.Radius;

                // special case where radii of first 2 circles are equal
                if (MathUtil.Equals(r1, r2))
                {
                    // Calculate x-cordinate of centre
                    xc = ci2.X / 2.0;

                    // if all radii are equal, there will be only one solution
                    if (MathUtil.Equals(r1, r3))
                    {
                        if (MathUtil.IsZero(ci3.Y))
                        {
                            continue;
                        }

                        // get y-coordinate of centre
                        yc = (ci3.X * ci3.X - 2.0 * xc * ci3.X + ci3.Y * ci3.Y) / (ci3.Y + ci3.Y);

                        // compute radius
                        A     = 1;
                        B     = 2 * r1;
                        C     = r1 * r1 - xc * xc - yc * yc;
                        roots = RealPolynomial.SolveQuadric(A, B, C);

                        if (roots.Length > 0)
                        {
                            fRadius = roots[0];
                            if (fRadius <= 0.0)
                            { //then try other root
                                if (roots.Length > 1)
                                {
                                    fRadius = roots[1];
                                    if (fRadius <= 0.0)
                                    {
                                        continue; //no posetive roots
                                    }
                                }
                            }
                            AddResult(ref result, xc, yc, fRadius);
                        }
                    }
                    else
                    {
                        // compute constants
                        double k = r1 * r1 - r3 * r3 + ci3.X * ci3.X + ci3.Y * ci3.Y - 2 * xc * ci3.X;
                        A = 4 * ((r1 - r3) * (r1 - r3) - ci3.Y * ci3.Y);
                        B = 4 * (k * (r1 - r3) - 2 * ci3.Y * ci3.Y * r1);
                        C = 4 * xc * xc * ci3.Y * ci3.Y + k * k - 4 * ci3.Y * ci3.Y * r1 * r1;

                        if (!MathUtil.IsZero(A))
                        {
                            roots = RealPolynomial.SolveQuadric(A, B, C);

                            foreach (double radius in roots)
                            {
                                yc = (2 * radius * (r1 - r3) + k) / (2 * ci3.Y);
                                AddResult(ref result, xc, yc, radius);
                            }
                        }
                    }
                    continue;
                } //end special case of r1==r2



                // Get constants
                a = 2 * (ci2.X * (r3 - r1) - ci3.X * (r2 - r1));
                b = 2 * ci3.Y * (r1 - r2);
                c = (r2 - r1) * (ci3.X * ci3.X + ci3.Y * ci3.Y - (r3 - r1) * (r3 - r1)) - (r3 - r1) * (ci2.X * ci2.X - (r2 - r1) * (r2 - r1));
                t = (ci2.X * ci2.X + r1 * r1 - r2 * r2) / 2.0;
                A = (r1 - r2) * (r1 - r2) * (a * a + b * b) - (ci2.X * ci2.X * b * b);
                B = 2 * (t * (r1 - r2) * (a * a + b * b) + a * c * ci2.X * (r1 - r2) - (r1 * ci2.X * ci2.X * b * b));
                C = t * t * (a * a + b * b) + (2 * a * c * ci2.X * t) + (c * c * ci2.X * ci2.X) - (r1 * r1 * ci2.X * ci2.X * b * b);

                // Calculate radius
                roots = RealPolynomial.SolveQuadric(A, B, C);
                if (roots == null)
                {
                    continue;
                }

                foreach (double radius in roots)
                {
                    if (radius < minradius || radius > maxradius)
                    {
                        continue;
                    }
                    // get x coordinate of centre (x2 may not be zero)
                    xc = (radius * (r1 - r2) + t) / ci2.X;

                    // get y coordinate of centre. b should never be 0, as
                    // r1=r2 is special case and y3 may not be zero
                    yc = (-a * xc - c) / b;
                    AddResult(ref result, xc, yc, radius);
                }
            }

            //convert back to original coordinate system by using the inverse
            //of the original matrix
            if (result != null)
            {
                trans = trans.Inversed;
                for (int l = 0; l < result.Count; l++)
                {
                    result[l].Transform(trans);
                }
                return(result.ToArray());
            }

            return(null);
        }
Beispiel #28
0
        public static Circle2d[] CircleCircleLine(Circle2d ci1, Circle2d ci2, Line2d li)
        {
            // see http://www.arcenciel.co.uk/geometry/ for explanation

            List <Circle2d> result = null;
            double          a1, b1, c1, t, r2, r3, a, b, c, u, s;
            double          A, B, C, xc, yc;

            //transform input so that c1 is at origo and c2 is on xaxis
            Transform2d trans = Transform2d.Translate(Point2d.Origo - ci1.Center) * Transform2d.Rotate(-ci1.Center.Angle(ci2.Center));

            ci1 = new Circle2d(ci1);
            ci1.Transform(trans);
            ci2 = new Circle2d(ci2);
            ci2.Transform(trans);
            li = new Line2d(li);
            li.Transform(trans);


            if (!li.ToEquation(out a1, out b1, out c1))
            {
                return(null); //degenerate line
            }
            for (int signcase = 0; signcase < 8; ++signcase)
            {
                t = ((signcase & 1) == 0) ? 1 : -1;

                r2 = ((signcase & 2) == 0) ? ci1.Radius : -ci1.Radius;

                r3 = ((signcase & 4) == 0) ? ci2.Radius : -ci2.Radius;



                // Get constants
                a = 2 * (a1 * (r2 - r3) - ci2.X * t);
                b = 2 * b1 * (r2 - r3);
                c = 2 * c1 * (r2 - r3) + t * (r2 * r2 - r3 * r3 + ci2.X * ci2.X);

                if (!MathUtil.IsZero(b))
                {
                    u = b1 * c - b * c1;
                    s = a1 * b - a * b1;
                    A = t * t * b * b * (a * a + b * b) - b * b * s * s;
                    B = 2 * (u * t * b * (a * a + b * b) + a * c * s * t * b - b * b * s * s * r2);
                    C = u * u * (a * a + b * b) + 2 * a * c * s * u + c * c * s * s - b * b * s * s * r2 * r2;
                }
                else
                {
                    u = a1 * c - a * c1;
                    s = a * b1;
                    A = a * a * (t * t * a * a - s * s);
                    B = 2 * a * a * (u * t * a - s * s * r2);
                    C = u * u * a * a + c * c * s * s - a * a * s * s * r2 * r2;
                }



                // Calculate radius
                double[] roots = RealPolynomial.SolveQuadric(A, B, C);
                if (roots != null)
                {
                    foreach (double radius in roots)
                    {
                        if (radius < minradius || radius > maxradius)
                        {
                            continue;
                        }

                        // compute x coordinates of centers
                        List <double> xsols = new List <double>();

                        if (!MathUtil.IsZero(ci2.X)) //circles are not concentric
                        {
                            xc = ((r2 + radius) * (r2 + radius) - (r3 + radius) * (r3 + radius) + ci2.X * ci2.X) / (2 * ci2.X);
                            xsols.Add(xc);
                        }
                        else // If circles are concentric there can be 2 solutions for x
                        {
                            A = (a1 * a1 + b1 * b1);
                            B = -2 * a1 * (radius * t - c1);
                            C = (radius * t - c1) * (radius * t - c1) - b1 * b1 * (r2 + radius) * (r2 + radius);

                            double[] roots2 = RealPolynomial.SolveQuadric(A, B, C);
                            if (roots2 != null)
                            {
                                foreach (double x in roots2)
                                {
                                    xsols.Add(x);
                                }
                            }
                        }



                        // now compute y coordinates from the calculated x:es
                        // and input the final solution
                        foreach (double x in xsols)
                        {
                            if (!MathUtil.IsZero(b1))
                            {
                                yc = (-a1 * x - c1 + radius * t) / b1;
                            }
                            else
                            {
                                double ycSquare = (r2 + radius) * (r2 + radius) - (x * x);
                                if (ycSquare < 0.0)
                                {
                                    continue;
                                }
                                yc = Math.Sqrt(ycSquare);
                            }

                            AddResult(ref result, x, yc, radius);
                            if (MathUtil.IsZero(b1))
                            {
                                AddResult(ref result, x, -yc, radius);
                            }
                        }
                    }
                }
            }


            //convert back to original coordinate system by using the inverse
            //of the original matrix
            if (result != null)
            {
                trans = trans.Inversed;
                for (int l = 0; l < result.Count; l++)
                {
                    result[l].Transform(trans);
                }
                return(result.ToArray());
            }

            return(null);
        }
Beispiel #29
0
        /// <summary>
        /// Returns all the perpendicular points on the ellipse from a given point 'from'
        /// </summary>
        public Point2d[] Perpendicular(Point2d from)
        {
            // Solved by Robert.P. in december 2012
            // Note on solutions:
            // Quartic coefficients gotten from applying lagrange multiplier to minimize (x-i)^2+(y-j)^2
            // with x^2/a^2+y^2/b^2-1=0 as constraint (a=1 because we work in standard position).
            // This gives a system of three equations F_x,F_y,F_lambda, which were solved with
            // resultant theory using 'eliminate' in maxima

            //work in standard position, retranslate solutions last
            Transform2d tostd = ToStandardPosition;

            from = from.GetTransformed(tostd);

            double b = sigratio, b2 = b * b, b4 = b2 * b2;
            double i = from.X, i2 = i * i;
            double j = from.Y, j2 = j * j;


            double x4 = b4 - 2 * b2 + 1;
            double x3 = 2 * b2 * i - 2 * i;
            double x2 = b2 * j2 + i2 - b4 + 2 * b2 - 1;
            double x1 = 2 * i - 2 * b2 * i;
            double x0 = -i2;

            double[] sols = RealPolynomial.SolveQuartic2(x4, x3, x2, x1, x0, 1e-16);

            if (sols == null)
            {
                return(null);
            }

            Point2dSet respts = new Point2dSet();

            foreach (double x in sols)
            {
                double y = (1 - x * x) * b2;
                if (y < 0.0)
                {
                    continue;
                }
                y = Math.Sqrt(y);


                for (int l = 0; l < 2; l++)
                {
                    //both posetive and negative y:s can be solutions. Check with each possible
                    //point that its perpendicular to ellipse (subtracting the inverse ellipse slope (=normal slope) with the slope from 'from' point)
                    double err;
                    err = y * (from.X - x) - x * b2 * (from.Y - y);
                    if (Math.Abs(err) < 1e-6)
                    {
                        respts.Add(new Point2d(x, y));
                    }

                    y = -y; //test negative solution as well
                }
            }

            respts.Transform(tostd.Inversed);
            return(respts.ToArray());
        }
Beispiel #30
0
        internal static void Ellipse_Transform(ref double a_rh, ref double a_rv, ref double a_offsetrot, ref Point2d endpoint, Transform2d a_mat, out bool a_ReverseWinding)
        {
            double rh, rv, rot;

            double[] m = new double[4]; // matrix representation of transformed ellipse
            double   s, c;              // sin and cos helpers (the former offset rotation)
            double   A, B, C;           // ellipse implicit equation:
            double   ac, A2, C2;        // helpers for angle and halfaxis-extraction.

            rh  = a_rh;
            rv  = a_rv;
            rot = a_offsetrot;

            s = Math.Sin(rot);
            c = Math.Cos(rot);

            // build ellipse representation matrix (unit circle transformation).
            // the 2x2 matrix multiplication with the upper 2x2 of a_mat is inlined.
            m[0] = a_mat.AX * +rh * c + a_mat.BX * rh * s;
            m[1] = a_mat.AY * +rh * c + a_mat.BY * rh * s;
            m[2] = a_mat.AX * -rv * s + a_mat.BX * rv * c;
            m[3] = a_mat.AY * -rv * s + a_mat.BY * rv * c;

            // to implict equation (centered)
            A = (m[0] * m[0]) + (m[2] * m[2]);
            C = (m[1] * m[1]) + (m[3] * m[3]);
            B = (m[0] * m[1] + m[2] * m[3]) * 2.0f;

            // precalculate distance A to C
            ac = A - C;

            // convert implicit equation to angle and halfaxis:
            if (MathUtil.IsZero(B)) //=not tilted
            {
                if (MathUtil.IsZero(ac) || A > C)
                {
                    a_offsetrot = 0;
                }
                else
                {
                    a_offsetrot = MathUtil.Deg90;
                }



                A2 = A;
                C2 = C;
            }
            else
            {
                if (MathUtil.IsZero(ac))
                {
                    A2          = A + B * 0.5f;
                    C2          = A - B * 0.5f;
                    a_offsetrot = MathUtil.PI / 4.0f;
                }
                else
                {
                    // Precalculate radical:
                    double K = 1 + B * B / (ac * ac);

                    // Clamp (precision issues might need this.. not likely, but better safe than sorry)
                    if (K < 0)
                    {
                        K = 0;
                    }
                    else
                    {
                        K = Math.Sqrt(K);
                    }

                    A2          = 0.5f * (A + C + K * ac);
                    C2          = 0.5f * (A + C - K * ac);
                    a_offsetrot = 0.5f * Math.Atan2(B, ac);
                }
            }

            // This can get slightly below zero due to rounding issues.
            // it's save to clamp to zero in this case (this yields a zero length halfaxis)
            if (A2 < 0)
            {
                A2 = 0;
            }
            else
            {
                A2 = Math.Sqrt(A2);
            }
            if (C2 < 0)
            {
                C2 = 0;
            }
            else
            {
                C2 = Math.Sqrt(C2);
            }

            // now A2 and C2 are half-axis:
            if (ac <= 0)
            {
                a_rv = A2;
                a_rh = C2;
            }
            else
            {
                a_rv = C2;
                a_rh = A2;
            }

            // The transformation matrix might contain a mirror-component, and the
            // winding order of the ellise needs to be changed.
            // check the sign of the upper 2x2 submatrix determinant to find out..
            a_ReverseWinding = ((a_mat.AX * a_mat.BY) - (a_mat.AY * a_mat.BX)) < 0 ? true : false;

            // finally, transform ellipse endpoint. This takes care about the
            // translational part which we ignored at the whole math-showdown above.
            endpoint = endpoint.GetTransformed(a_mat);
        }