Beispiel #1
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 #2
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 #3
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);
        }