Beispiel #1
0
        public Kite(Segment left, Segment right, Segment top, Segment bottom,
            bool tlDiag = false, bool brDiag = false, Intersection inter = null)
            : base(left, right, top, bottom)
        {
            if (Utilities.CompareValues(left.Length, top.Length) && Utilities.CompareValues(right.Length, bottom.Length))
            {
                pairASegment1 = left;
                pairASegment2 = top;

                pairBSegment1 = right;
                pairBSegment2 = bottom;
            }
            else if (Utilities.CompareValues(left.Length, bottom.Length) && Utilities.CompareValues(right.Length, top.Length))
            {
                pairASegment1 = left;
                pairASegment2 = bottom;

                pairBSegment1 = right;
                pairBSegment2 = top;
            }
            else
            {
                throw new ArgumentException("Quadrilateral does not define a kite; no two adjacent sides are equal lengths: " + this);
            }

            //Set the diagonal and intersection values
            if (!tlDiag) this.SetTopLeftDiagonalInValid();
            if (!brDiag) this.SetBottomRightDiagonalInValid();
            this.SetIntersection(inter);
        }
Beispiel #2
0
        public Square(Segment left, Segment right, Segment top, Segment bottom, 
            bool tlDiag = false, bool brDiag = false, Intersection inter = null)
            : base(left, right, top, bottom)
        {
            if (!Utilities.CompareValues(topLeftAngle.measure, 90))
            {
                throw new ArgumentException("Quadrilateral is not a Square; angle does not measure 90^o: " + topLeftAngle);
            }
            if (!Utilities.CompareValues(topRightAngle.measure, 90))
            {
                throw new ArgumentException("Quadrilateral is not a Square; angle does not measure 90^o: " + topRightAngle);
            }

            if (!Utilities.CompareValues(bottomLeftAngle.measure, 90))
            {
                throw new ArgumentException("Quadrilateral is not a Square; angle does not measure 90^o: " + bottomLeftAngle);
            }

            if (!Utilities.CompareValues(bottomRightAngle.measure, 90))
            {
                throw new ArgumentException("Quadrilateral is not a Square; angle does not measure 90^o: " + bottomRightAngle);
            }

            //Set the diagonal and intersection values
            if (!tlDiag) this.SetTopLeftDiagonalInValid();
            if (!brDiag) this.SetBottomRightDiagonalInValid();
            this.SetIntersection(inter);
        }
Beispiel #3
0
        //
        // If a common segment exists (a transversal that cuts across both intersections), return that common segment
        //
        public Segment CommonSegment(Intersection thatInter)
        {
            if (lhs.StructurallyEquals(thatInter.lhs) || lhs.IsCollinearWith(thatInter.lhs)) return lhs;
            if (lhs.StructurallyEquals(thatInter.rhs) || lhs.IsCollinearWith(thatInter.rhs)) return lhs;
            if (rhs.StructurallyEquals(thatInter.lhs) || rhs.IsCollinearWith(thatInter.lhs)) return rhs;
            if (rhs.StructurallyEquals(thatInter.rhs) || rhs.IsCollinearWith(thatInter.rhs)) return rhs;

            return null;
        }
Beispiel #4
0
        public Perpendicular(Intersection inter)
            : base(inter.intersect, inter.lhs, inter.rhs)
        {
            // Check if truly perpendicular
            if (lhs.CoordinatePerpendicular(rhs) == null)
            {
                throw new ArgumentException("Intersection is not perpendicular: " + inter.ToString());
            }

            originalInter = inter;
        }
        //
        // Chair Corresponding
        //
        // |     |                  |
        // |_____|____   leftInter  |_________ tipOfT
        // |                        |     |
        // |                        |     |
        //                         off   tipOfT
        //
        //                                bottomInter
        private static List<EdgeAggregator> InstantiateChairIntersection(Parallel parallel, Intersection inter1, Point off, Intersection inter2, Point bottomTip)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            Segment transversal = inter1.AcquireTransversal(inter2);
            Point tipOfT1 = inter1.CreatesTShape();
            Point tipOfT2 = inter2.CreatesTShape();

            Point leftTip = null;
            Intersection leftInter = null;
            Intersection bottomInter = null;

            if (transversal.PointLiesOn(tipOfT1))
            {
                leftInter = inter1;
                bottomInter = inter2;
                leftTip = tipOfT1;
            }
            // thatInter is leftInter
            else if (transversal.PointLiesOn(tipOfT2))
            {
                leftInter = inter2;
                bottomInter = inter1;
                leftTip = tipOfT2;
            }

            //
            // Generate the new congruence
            //
            List<CongruentAngles> newAngleRelations = new List<CongruentAngles>();

            // CTA: Hack fix to alleviate exception thrown from improper congruent constructions.
            GeometricCongruentAngles gca = null;
            try
            {
                gca = new GeometricCongruentAngles(new Angle(leftTip, bottomInter.intersect, bottomTip),
                                                   new Angle(bottomInter.intersect, leftInter.intersect, off));
            }
            catch (Exception e)
            {
                if (Utilities.DEBUG) System.Diagnostics.Debug.WriteLine(e.ToString());

                return newGrounded;
            }

            newAngleRelations.Add(gca);

            return MakeRelations(newAngleRelations, parallel, inter1, inter2);
        }
Beispiel #6
0
        public Rectangle(Segment a, Segment b, Segment c, Segment d, 
            bool tlDiag = false, bool brDiag = false, Intersection inter = null)
            : base(a, b, c, d)
        {
            foreach (Angle angle in angles)
            {
                if (!Utilities.CompareValues(angle.measure, 90))
                {
                    throw new ArgumentException("Quadrilateral is not a Rectangle; angle does not measure 90^o: " + angle);
                }
            }

            //Set the diagonal and intersection values
            if (!tlDiag) this.SetTopLeftDiagonalInValid();
            if (!brDiag) this.SetBottomRightDiagonalInValid();
            this.SetIntersection(inter);
        }
Beispiel #7
0
        //
        // Returns the exact transversal between the intersections
        //
        public Segment AcquireTransversal(Intersection thatInter)
        {
            // The two intersections should not be at the same vertex
            if (intersect.Equals(thatInter.intersect)) return null;

            Segment common = CommonSegment(thatInter);
            if (common == null) return null;

            // A legitimate transversal must belong to both intersections (is a subsegment of one of the lines)
            Segment transversal = new Segment(this.intersect, thatInter.intersect);

            Segment thisTransversal = this.GetCollinearSegment(transversal);
            Segment thatTransversal = thatInter.GetCollinearSegment(transversal);

            if (!thisTransversal.HasSubSegment(transversal)) return null;
            if (!thatTransversal.HasSubSegment(transversal)) return null;

            return transversal;
        }
        private static List<EdgeAggregator> CheckAndGenerateCongruentAdjacentImplyPerpendicular(Intersection intersection, CongruentAngles conAngles)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The given angles must belong to the intersection. That is, the vertex must align and all rays must overlay the intersection.
            if (!intersection.InducesBothAngles(conAngles)) return newGrounded;

            //
            // Now we have perpendicular scenario
            //
            Strengthened streng = new Strengthened(intersection, new Perpendicular(intersection));

            // Construct hyperedge
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(intersection);
            antecedent.Add(conAngles);

            newGrounded.Add(new EdgeAggregator(antecedent, streng, annotation));

            return newGrounded;
        }
Beispiel #9
0
        //TODO: Need to find a way to determine the validity of diagonals, and to find the intersection if both diagonals are valid
        //These values are determined for base quadrilaterals by the Implied Component Calculator in the UI parser, but are never
        //computed for the specialized quads
        public Rhombus(Segment left, Segment right, Segment top, Segment bottom,
            bool tlDiag = false, bool brDiag = false, Intersection inter = null)
            : base(left, right, top, bottom)
        {
            if (!Utilities.CompareValues(top.Length, left.Length))
            {
                throw new ArgumentException("Quadrilateral is not a Rhombus; sides are not equal length: " + top + " " + left);
            }
            if (!Utilities.CompareValues(top.Length, right.Length))
            {
                throw new ArgumentException("Quadrilateral is not a Rhombus; sides are not equal length: " + top + " " + right);
            }
            if (!Utilities.CompareValues(top.Length, bottom.Length))
            {
                throw new ArgumentException("Quadrilateral is not a Rhombus; sides are not equal length: " + top + " " + bottom);
            }

            //Set the diagonal and intersection values
            if (!tlDiag) this.SetTopLeftDiagonalInValid();
            if (!brDiag) this.SetBottomRightDiagonalInValid();
            this.SetIntersection(inter);
        }
        public static List<GenericInstantiator.EdgeAggregator> GeneratePerpendicularBisector(GroundedClause tri, AngleBisector ab, Intersection inter)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            IsoscelesTriangle isoTri = (tri is Strengthened ? (tri as Strengthened).strengthened : tri) as IsoscelesTriangle;

            if (tri is EquilateralTriangle)
            {

            }

            // Does the Angle Bisector occur at the vertex angle (non-base angles) of the Isosceles triangle?
            try
            {
                if (!ab.angle.GetVertex().Equals(isoTri.GetVertexAngle().GetVertex())) return newGrounded;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }

            // Is the intersection point between the endpoints of the base of the triangle?
            if (!Segment.Between(inter.intersect, isoTri.baseSegment.Point1, isoTri.baseSegment.Point2)) return newGrounded;

            // Does this intersection define this angle bisector situation? That is, the bisector and base must align with the intersection
            if (!inter.ImpliesRay(ab.bisector)) return newGrounded;
            if (!inter.HasSegment(isoTri.baseSegment)) return newGrounded;

            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(tri);
            antecedent.Add(ab);
            antecedent.Add(inter);

            // PerpendicularBisector(M, Segment(M, C), Segment(A, B))
            Strengthened newPerpB = new Strengthened(inter, new PerpendicularBisector(inter, ab.bisector));
            newGrounded.Add(new EdgeAggregator(antecedent, newPerpB, annotation));

            return newGrounded;
        }
        //     leftTop    rightTop
        //         |         |
        //         |_________|
        //         |         |
        //         |         |
        //   leftBottom rightBottom
        //
        private static List<EdgeAggregator> GenerateH(Parallel parallel, Intersection crossingInterLeft, Intersection crossingInterRight)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            Segment transversal = crossingInterLeft.AcquireTransversal(crossingInterRight);

            //
            // Find tops and bottoms
            //
            Segment crossingLeftParallel = crossingInterLeft.OtherSegment(transversal);
            Segment crossingRightParallel = crossingInterRight.OtherSegment(transversal);

            //
            // Determine which points are on the same side of the transversal.
            //
            Segment testingCrossSegment = new Segment(crossingLeftParallel.Point1, crossingRightParallel.Point1);
            Point intersection = transversal.FindIntersection(testingCrossSegment);

            Point leftTop = crossingLeftParallel.Point1;
            Point leftBottom = crossingLeftParallel.Point2;

            Point rightTop = null;
            Point rightBottom = null;
            if (transversal.PointLiesOnAndBetweenEndpoints(intersection))
            {
                rightTop = crossingRightParallel.Point2;
                rightBottom = crossingRightParallel.Point1;
            }
            else
            {
                rightTop = crossingRightParallel.Point1;
                rightBottom = crossingRightParallel.Point2;
            }

            //
            // Generate the new congruences
            //
            List<CongruentAngles> newAngleRelations = new List<CongruentAngles>();

            GeometricCongruentAngles gca = new GeometricCongruentAngles(new Angle(leftTop, crossingInterLeft.intersect, crossingInterRight.intersect),
                                                                        new Angle(rightBottom, crossingInterRight.intersect, crossingInterLeft.intersect));
            newAngleRelations.Add(gca);
            gca = new GeometricCongruentAngles(new Angle(rightTop, crossingInterRight.intersect, crossingInterLeft.intersect),
                                               new Angle(leftBottom, crossingInterLeft.intersect, crossingInterRight.intersect));
            newAngleRelations.Add(gca);

            return MakeRelations(newAngleRelations, parallel, crossingInterLeft, crossingInterRight);
        }
        //                 offCross
        //                     |
        // leftCross     ______|______   rightCross
        //                     |
        // leftStands     _____|_____    rightStands
        //
        private static List<EdgeAggregator> GenerateFlying(Parallel parallel, Intersection inter1, Intersection inter2, Point offCross)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            //
            // Determine which is the crossing intersection and which stands on the endpoints
            //
            Intersection crossingInter = null;
            Intersection standsInter = null;
            if (inter1.Crossing())
            {
                crossingInter = inter1;
                standsInter = inter2;
            }
            else if (inter2.Crossing())
            {
                crossingInter = inter2;
                standsInter = inter1;
            }

            // Determine the side of the crossing needed for the angle
            Segment transversal = inter1.AcquireTransversal(inter2);

            Segment parallelStands = standsInter.OtherSegment(transversal);
            Segment parallelCrossing = crossingInter.OtherSegment(transversal);

            // Determine point orientation in the plane
            Point leftStands = parallelStands.Point1;
            Point rightStands = parallelStands.Point2;
            Point leftCross = null;
            Point rightCross = null;

            Segment crossingTester = new Segment(leftStands, parallelCrossing.Point1);
            Point intersection = transversal.FindIntersection(crossingTester);
            if (transversal.PointLiesOnAndBetweenEndpoints(intersection))
            {
                leftCross = parallelCrossing.Point2;
                rightCross = parallelCrossing.Point1;
            }
            else
            {
                leftCross = parallelCrossing.Point1;
                rightCross = parallelCrossing.Point2;
            }

            //
            // Generate the new congruence
            //
            List<CongruentAngles> newAngleRelations = new List<CongruentAngles>();

            GeometricCongruentAngles gca = new GeometricCongruentAngles(new Angle(rightCross, crossingInter.intersect, standsInter.intersect),
                                                                        new Angle(leftStands, standsInter.intersect, crossingInter.intersect));
            newAngleRelations.Add(gca);

            gca = new GeometricCongruentAngles(new Angle(leftCross, crossingInter.intersect, standsInter.intersect),
                                               new Angle(rightStands, standsInter.intersect, crossingInter.intersect));
            newAngleRelations.Add(gca);

            return MakeRelations(newAngleRelations, parallel, inter1, inter2);
        }
Beispiel #13
0
 public SegmentBisector(Intersection b, Segment bisec)
     : base()
 {
     bisected = b;
     bisector = bisec;
 }
Beispiel #14
0
        //                   top
        //                    o
        //  offStands  oooooooe
        //                    e
        //offEndpoint   eeeeeee
        //                    o
        //                 bottom
        //                       Returns: <offEndpoint, offStands>
        public KeyValuePair <Point, Point> CreatesSimplePIShape(Intersection thatInter)
        {
            KeyValuePair <Point, Point> nullPair = new KeyValuePair <Point, Point>(null, null);

            // A valid transversal is required for this shape
            if (!this.CreatesAValidTransversalWith(thatInter))
            {
                return(nullPair);
            }

            // Restrict to desired combination
            if (this.StandsOnEndpoint() && thatInter.StandsOnEndpoint())
            {
                return(nullPair);
            }

            //
            // Determine which is the stands and which is the endpoint
            //
            Intersection endpointInter = null;
            Intersection standsInter   = null;

            if (this.StandsOnEndpoint() && thatInter.StandsOn())
            {
                endpointInter = this;
                standsInter   = thatInter;
            }
            else if (thatInter.StandsOnEndpoint() && this.StandsOn())
            {
                endpointInter = this;
                standsInter   = thatInter;
            }
            else
            {
                return(nullPair);
            }

            //
            // Avoid Some shapes
            //
            Segment transversal       = this.AcquireTransversal(thatInter);
            Segment transversalStands = standsInter.GetCollinearSegment(transversal);

            Point top    = null;
            Point bottom = null;

            if (Segment.Between(standsInter.intersect, transversalStands.Point1, endpointInter.intersect))
            {
                top    = transversalStands.Point1;
                bottom = transversalStands.Point2;
            }
            else
            {
                top    = transversalStands.Point2;
                bottom = transversalStands.Point1;
            }

            // Avoid: ____  Although this shouldn't happen since both intersections do not stand on endpoints
            //        ____|
            //
            // Also avoid Simple F-Shape
            //
            if (transversal.HasPoint(top) || transversal.HasPoint(bottom))
            {
                return(nullPair);
            }

            // Determine S shape
            Point offStands = standsInter.CreatesTShape();

            Segment parallelEndpoint = endpointInter.OtherSegment(transversal);
            Point   offEndpoint      = parallelEndpoint.OtherPoint(endpointInter.intersect);


            Segment crossingTester = new Segment(offStands, offEndpoint);
            Point   intersection   = transversal.FindIntersection(crossingTester);

            // S-shape    // PI-Shape
            return(transversal.PointLiesOnAndBetweenEndpoints(intersection) ? nullPair : new KeyValuePair <Point, Point>(offEndpoint, offStands));
        }
        //
        // Acquire all intersections from the maximal segment list
        //
        private void ConstructMaximalSegmentSegmentIntersections()
        {
            for (int s1 = 0; s1 < maximalSegments.Count - 1; s1++)
            {
                for (int s2 = s1 + 1; s2 < maximalSegments.Count; s2++)
                {
                    // An intersection should not be between collinear segments
                    if (!maximalSegments[s1].IsCollinearWith(maximalSegments[s2]))
                    {
                        // The point must be 'between' both segment endpoints
                        Point numericInter = maximalSegments[s1].FindIntersection(maximalSegments[s2]);
                        if (maximalSegments[s1].PointLiesOnAndBetweenEndpoints(numericInter) &&
                            maximalSegments[s2].PointLiesOnAndBetweenEndpoints(numericInter))
                        {
                            // The actual point in the figure
                            Point knownPt = GeometryTutorLib.Utilities.GetStructurally<Point>(allFigurePoints, numericInter);

                            Intersection newInter = new Intersection(knownPt, maximalSegments[s1], maximalSegments[s2]);

                            GeometryTutorLib.Utilities.AddStructurallyUnique<Intersection>(ssIntersections, newInter);
                        }
                    }
                }
            }
        }
Beispiel #16
0
 public void SetIntersection(Intersection diag)
 {
     diagonalIntersection = diag;
 }
        private static List<EdgeAggregator> MakeRelations(List<CongruentAngles> newAngleRelations, Parallel parallel, Intersection inter1, Intersection inter2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(parallel);
            antecedent.Add(inter1);
            antecedent.Add(inter2);

            foreach (CongruentAngles newAngles in newAngleRelations)
            {
                newGrounded.Add(new EdgeAggregator(antecedent, newAngles, annotation));
            }

            return newGrounded;
        }
Beispiel #18
0
        //
        // Creates an F-Shape
        //   top
        //    _____ offEnd     <--- Stands on Endpt
        //   |
        //   |_____ offStands  <--- Stands on
        //   |
        //   |
        //  bottom
        //   Order of non-collinear points is order of intersections: <this, that>
        public KeyValuePair <Point, Point> CreatesFShape(Intersection thatInter)
        {
            KeyValuePair <Point, Point> nullPair = new KeyValuePair <Point, Point>(null, null);

            // A valid transversal is required for this shape
            if (!this.CreatesAValidTransversalWith(thatInter))
            {
                return(nullPair);
            }

            // Avoid both standing on an endpoint
            if (this.StandsOnEndpoint() && thatInter.StandsOnEndpoint())
            {
                return(nullPair);
            }

            Intersection endpt    = null;
            Intersection standsOn = null;

            if (this.StandsOnEndpoint() && thatInter.StandsOn())
            {
                endpt    = this;
                standsOn = thatInter;
            }
            else if (thatInter.StandsOnEndpoint() && this.StandsOn())
            {
                endpt    = thatInter;
                standsOn = this;
            }
            else
            {
                return(nullPair);
            }

            Segment transversal       = this.AcquireTransversal(thatInter);
            Segment transversalStands = standsOn.GetCollinearSegment(transversal);

            //
            // Determine Top and bottom to avoid PI shape
            //
            Point top    = null;
            Point bottom = null;

            if (Segment.Between(standsOn.intersect, transversalStands.Point1, endpt.intersect))
            {
                bottom = transversalStands.Point1;
                top    = transversalStands.Point2;
            }
            else
            {
                bottom = transversalStands.Point2;
                top    = transversalStands.Point1;
            }

            // Avoid: ____  Although this shouldn't happen since both intersections do not stand on endpoints
            //        ____|
            if (transversal.HasPoint(top) && transversal.HasPoint(bottom))
            {
                return(nullPair);
            }

            // Also avoid Simple PI-Shape
            //
            if (!transversal.HasPoint(top) && !transversal.HasPoint(bottom))
            {
                return(nullPair);
            }

            // Find the two points that make the points of the F
            Segment parallelEndPt  = endpt.OtherSegment(transversal);
            Segment parallelStands = standsOn.OtherSegment(transversal);

            Point offEnd    = transversal.PointLiesOn(parallelEndPt.Point1) ? parallelEndPt.Point2 : parallelEndPt.Point1;
            Point offStands = transversal.PointLiesOn(parallelStands.Point1) ? parallelStands.Point2 : parallelStands.Point1;

            // Check this is not a crazy F
            //        _____
            //       |
            //   ____|
            //       |
            //       |
            Point intersection = transversal.FindIntersection(new Segment(offEnd, offStands));

            if (transversal.PointLiesOnAndBetweenEndpoints(intersection))
            {
                return(nullPair);
            }

            // Return in the order of 'off' points: <this, that>
            return(this.Equals(endpt) ? new KeyValuePair <Point, Point>(offEnd, offStands) : new KeyValuePair <Point, Point>(offStands, offEnd));
        }
Beispiel #19
0
        //
        // Creates a Topped F-Shape
        //            top
        // offLeft __________ offEnd    <--- Stands on
        //             |
        //             |_____ off       <--- Stands on
        //             |
        //             |
        //           bottom
        //
        //   Returns: <bottom, off>
        public KeyValuePair <Intersection, Point> CreatesToppedFShape(Intersection thatInter)
        {
            KeyValuePair <Intersection, Point> nullPair = new KeyValuePair <Intersection, Point>(null, null);

            // A valid transversal is required for this shape
            if (!this.CreatesAValidTransversalWith(thatInter))
            {
                return(nullPair);
            }

            // Avoid both standing on an endpoint OR crossing
            if (this.StandsOnEndpoint() || thatInter.StandsOnEndpoint())
            {
                return(nullPair);
            }
            if (this.Crossing() || thatInter.Crossing())
            {
                return(nullPair);
            }

            Segment transversal = this.AcquireTransversal(thatInter);

            Intersection standsOnTop    = null;
            Intersection standsOnBottom = null;

            // Top has 2 points on the transversal; bottom has 3
            Segment nonTransversalThis = this.OtherSegment(transversal);
            Segment nonTransversalThat = thatInter.OtherSegment(transversal);

            if (transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThis.Point1) ||
                transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThis.Point2))
            {
                //             |
                //         ____|                <--- Stands on
                //             |
                //             |_____ off       <--- Stands on
                //             |
                //             |
                if (transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThat.Point1) ||
                    transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThat.Point2))
                {
                    return(nullPair);
                }

                standsOnBottom = this;
                standsOnTop    = thatInter;
            }
            else if (transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThat.Point1) ||
                     transversal.PointLiesOnAndBetweenEndpoints(nonTransversalThat.Point2))
            {
                standsOnBottom = this;
                standsOnTop    = thatInter;
            }
            else
            {
                return(nullPair);
            }

            // Check that the bottom extends the transversal
            if (!standsOnBottom.GetCollinearSegment(transversal).HasStrictSubSegment(transversal))
            {
                return(nullPair);
            }

            Point off = standsOnBottom.OtherSegment(transversal).OtherPoint(standsOnBottom.intersect);

            return(new KeyValuePair <Intersection, Point>(standsOnBottom, off));
        }
        //
        // Creates a basic S-Shape with standsOnEndpoints
        //
        //                  ______ offThat
        //                 |
        //   offThis ______|
        //
        // Return <offThis, offThat>
        private static List<EdgeAggregator> GenerateSimpleS(Parallel parallel, Intersection inter1, Point offThis, Intersection inter2, Point offThat)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            //
            // Generate the new congruence
            //
            List<CongruentAngles> newAngleRelations = new List<CongruentAngles>();

            GeometricCongruentAngles gca = new GeometricCongruentAngles(new Angle(offThat, inter2.intersect, inter1.intersect),
                                                                        new Angle(offThis, inter1.intersect, inter2.intersect));
            newAngleRelations.Add(gca);

            return MakeRelations(newAngleRelations, parallel, inter1, inter2);
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // One Secant, One Tangent
        // Intersection(X, AD, BC), Tangent(Circle(O), BC) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateOneSecantOneTangentTheorem(Intersection inter, Tangent tangent, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan = tangent.intersection as CircleSegmentIntersection;

            // Is the tangent segment part of the intersection?
            if (!inter.HasSegment(tan.segment)) return newGrounded;

            // Acquire the chord that the intersection creates.
            Segment secant = inter.OtherSegment(tan.segment);

            Circle circle = tan.theCircle;
            Segment chord = circle.ContainsChord(secant);

            // Check if this segment never intersects the circle or doesn't create a chord.
            if (chord == null) return newGrounded;

            //
            // Get the near / far points out of the chord
            //
            Point closeChordPt = null;
            Point farChordPt = null;
            if (Segment.Between(chord.Point1, chord.Point2, inter.intersect))
            {
                closeChordPt = chord.Point1;
                farChordPt = chord.Point2;
            }
            else
            {
                closeChordPt = chord.Point2;
                farChordPt = chord.Point1;
            }

            //
            // Acquire the arcs
            //
            // Get the close arc first which we know exactly how it is constructed AND that it's a minor arc.
            Arc closeArc = Arc.GetFigureMinorArc(circle, closeChordPt, tan.intersect);

            // The far arc MAY be a major arc; if it is, the first candidate arc will contain the close arc.
            Arc farArc = Arc.GetFigureMinorArc(circle, farChordPt, tan.intersect);

            if (farArc.HasMinorSubArc(closeArc))
            {
                farArc = Arc.GetFigureMajorArc(circle, farChordPt, tan.intersect);
            }

            Angle theAngle = Angle.AcquireFigureAngle(new Angle(closeChordPt, inter.intersect, tan.intersect));

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original);
            antecedent.Add(inter);
            antecedent.Add(closeArc);
            antecedent.Add(farArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        //
        // Creates a Topped F-Shape
        //            top
        // oppSide __________       <--- Stands on
        //             |
        //             |_____ off   <--- Stands on
        //             |
        //             |
        //           bottom
        //
        //   Returns: <bottom, off>
        private static List<EdgeAggregator> GenerateToppedFShape(Parallel parallel, Intersection inter1, Intersection inter2, Intersection bottom, Point off)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            Intersection top = inter1.Equals(bottom) ? inter2 : inter1;

            // Determine the side of the top intersection needed for the angle
            Segment transversal = inter1.AcquireTransversal(inter2);

            Segment parallelTop = top.OtherSegment(transversal);
            Segment parallelBottom = bottom.OtherSegment(transversal);

            Segment crossingTester = new Segment(off, parallelTop.Point1);
            Point intersection = transversal.FindIntersection(crossingTester);

            Point oppSide = transversal.PointLiesOnAndBetweenEndpoints(intersection) ? parallelTop.Point1 : parallelTop.Point2;

            //
            // Generate the new congruence
            //
            List<CongruentAngles> newAngleRelations = new List<CongruentAngles>();

            GeometricCongruentAngles gca = new GeometricCongruentAngles(new Angle(off, bottom.intersect, top.intersect),
                                                                        new Angle(oppSide, top.intersect, bottom.intersect));
            newAngleRelations.Add(gca);

            return MakeRelations(newAngleRelations, parallel, inter1, inter2);
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // Two tangents:
        // Intersection(X, AD, BC), Tangent(Circle(O), BC), Tangent(Circle(O), AD) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateTwoTangentsTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan1 = tangent1.intersection as CircleSegmentIntersection;
            CircleSegmentIntersection tan2 = tangent2.intersection as CircleSegmentIntersection;

            if (tan1.StructurallyEquals(tan2)) return newGrounded;

            // Do the tangents apply to the same circle?
            if (!tan1.theCircle.StructurallyEquals(tan2.theCircle)) return newGrounded;

            Circle circle = tan1.theCircle;

            // Do these tangents work with this intersection?
            if (!inter.HasSegment(tan1.segment) || !inter.HasSegment(tan2.segment)) return newGrounded;

            // Overkill? Do the tangents intersect at the same point as the intersection's intersect point?
            if (!tan1.segment.FindIntersection(tan2.segment).StructurallyEquals(inter.intersect)) return newGrounded;

            //
            // Get the arcs
            //
            Arc minorArc = new MinorArc(circle, tan1.intersect, tan2.intersect);
            Arc majorArc = new MajorArc(circle, tan1.intersect, tan2.intersect);

            Angle theAngle = new Angle(tan1.intersect, inter.intersect, tan2.intersect);

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(majorArc, minorArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original1);
            antecedent.Add(original2);
            antecedent.Add(inter);
            antecedent.Add(majorArc);
            antecedent.Add(minorArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        private static List<EdgeAggregator> CheckAndGenerateParallelImplyAlternateInterior(Intersection inter1, Intersection inter2, Parallel parallel)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The two intersections should not be at the same vertex
            if (inter1.intersect.Equals(inter2.intersect)) return newGrounded;

            // Determine the transversal
            Segment transversal = inter1.AcquireTransversal(inter2);
            if (transversal == null) return newGrounded;

            //
            // Ensure the non-traversal segments align with the parallel segments
            //
            Segment parallel1 = inter1.OtherSegment(transversal);
            Segment parallel2 = inter2.OtherSegment(transversal);

            // The non-transversals should not be the same (coinciding)
            if (parallel1.IsCollinearWith(parallel2)) return newGrounded;

            Segment coincidingParallel1 = parallel.CoincidesWith(parallel1);
            Segment coincidingParallel2 = parallel.CoincidesWith(parallel2);

            // The pair of non-transversals needs to align exactly with the parallel pair of segments
            if (coincidingParallel1 == null || coincidingParallel2 == null) return newGrounded;

            // Both intersections should not be referring to an intersection point on the same parallel segment
            if (parallel.segment1.PointLiesOn(inter1.intersect) && parallel.segment1.PointLiesOn(inter2.intersect)) return newGrounded;
            if (parallel.segment2.PointLiesOn(inter1.intersect) && parallel.segment2.PointLiesOn(inter2.intersect)) return newGrounded;

            // The resultant candidate parallel segments shouldn't share any vertices
            if (coincidingParallel1.SharedVertex(coincidingParallel2) != null) return newGrounded;

            if (inter1.StandsOnEndpoint() && inter2.StandsOnEndpoint())
            {
                //
                // Creates a basic S-Shape with standsOnEndpoints
                //
                //   offThis   ______
                //                   |
                //   offThat   ______|
                //
                // Return <offThis, offThat>
                KeyValuePair<Point, Point> cShapePoints = inter1.CreatesBasicCShape(inter2);
                if (cShapePoints.Key != null && cShapePoints.Value != null) return newGrounded;

                //
                // Creates a basic S-Shape with standsOnEndpoints
                //
                //                  ______ offThat       _______
                //                 |                     \
                //   offThis ______|                 _____\
                //
                // Return <offThis, offThat>
                KeyValuePair<Point, Point> sShapePoints = inter1.CreatesBasicSShape(inter2);
                if (sShapePoints.Key != null && sShapePoints.Value != null)
                {
                    return GenerateSimpleS(parallel, inter1, sShapePoints.Key, inter2, sShapePoints.Value);
                }

                return newGrounded;
            }

            //     _______/________
            //           /
            //          /
            //   ______/_______
            //        /
            if (inter1.Crossing() && inter2.Crossing()) return GenerateDualCrossings(parallel, inter1, inter2);

            // No alt int in this case:
            // Creates an F-Shape
            //   top
            //    _____ offEnd     <--- Stands on Endpt
            //   |
            //   |_____ offStands  <--- Stands on
            //   |
            //   |
            //  bottom
            KeyValuePair<Point, Point> fShapePoints = inter1.CreatesFShape(inter2);
            if (fShapePoints.Key != null && fShapePoints.Value != null) return newGrounded;

            // Alt. Int if an H-Shape
            //
            // |     |
            // |_____|
            // |     |
            // |     |
            //
            if (inter1.CreatesHShape(inter2)) return GenerateH(parallel, inter1, inter2);

            // Creates an S-Shape
            //
            //         |______
            //         |
            //   ______|
            //         |
            //
            //   Order of non-collinear points is order of intersections: <this, that>
            KeyValuePair<Point, Point> standardSShapePoints = inter1.CreatesStandardSShape(inter2);
            if (standardSShapePoints.Key != null && standardSShapePoints.Value != null)
            {
                return GenerateSimpleS(parallel, inter1, standardSShapePoints.Key, inter2, standardSShapePoints.Value);
            }

            // Corresponding if a flying-Shape
            //
            // |     |
            // |_____|___ offCross
            // |     |
            // |     |
            //
            Point offCross = inter1.CreatesFlyingShapeWithCrossing(inter2);
            if (offCross != null)
            {
                return GenerateFlying(parallel, inter1, inter2, offCross);
            }

            //
            // Creates a shape like an extended t
            //     offCross                          offCross
            //      |                                   |
            // _____|____                         ______|______
            //      |                                   |
            //      |_____ offStands     offStands _____|
            //
            // Returns <offStands, offCross>
            KeyValuePair<Point, Point> tShapePoints = inter1.CreatesCrossedTShape(inter2);
            if (tShapePoints.Key != null && tShapePoints.Value != null)
            {
                return GenerateCrossedT(parallel, inter1, inter2, tShapePoints.Key, tShapePoints.Value);
            }

            //
            // Creates a Topped F-Shape
            //            top
            // offLeft __________ offEnd    <--- Stands on
            //             |
            //             |_____ off       <--- Stands on
            //             |
            //             |
            //           bottom
            //
            //   Returns: <bottom, off>
            KeyValuePair<Intersection, Point> toppedFShapePoints = inter1.CreatesToppedFShape(inter2);
            if (toppedFShapePoints.Key != null && toppedFShapePoints.Value != null)
            {
                return GenerateToppedFShape(parallel, inter1, inter2, toppedFShapePoints.Key, toppedFShapePoints.Value);
            }

            return newGrounded;
        }
        //                    \ A
        //                     \
        //                      \
        //   center: O          / P
        //                     /
        //                    / B
        //
        // Tangent(Circle(O), Segment(B, P)),
        // Tangent(Circle(O), Segment(A, P)),
        // Intersection(AP, BP) -> Congruent(Segment(A, P), Segment(P, B))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Do the tangents apply to the same circle?
            if (!tangent1.intersection.theCircle.StructurallyEquals(tangent2.intersection.theCircle)) return newGrounded;

            // Do the tangents have components the are part of the third intersection
            if (!inter.HasSegment((tangent1.intersection as CircleSegmentIntersection).segment)) return newGrounded;
            if (!inter.HasSegment((tangent2.intersection as CircleSegmentIntersection).segment)) return newGrounded;

            Segment segment1 = Segment.GetFigureSegment(inter.intersect, tangent1.intersection.intersect);
            Segment segment2 = Segment.GetFigureSegment(inter.intersect, tangent2.intersection.intersect);

            GeometricCongruentSegments gcs = new GeometricCongruentSegments(segment1, segment2);

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original1);
            antecedent.Add(original2);
            antecedent.Add(inter);

            newGrounded.Add(new EdgeAggregator(antecedent, gcs, annotation));

            return newGrounded;
        }
        //
        // Generate all covering intersection clauses; that is, generate maximal intersections (a subset of all intersections)
        //
        private void CalculateIntersections()
        {
            //
            // Iterate over all polygons
            //
            for (int sidesIndex = Polygon.MIN_POLY_INDEX; sidesIndex < Polygon.MAX_EXC_POLY_INDEX; sidesIndex++)
            {
                foreach (Polygon poly in polygons[sidesIndex])
                {
                    //
                    // Add intersection clauses for all sides the polygon
                    //
                    List<Segment> sides = poly.orderedSides;
                    for (int s1 = 0; s1 < sides.Count - 1; s1++)
                    {
                        for (int s2 = s1 + 1; s2 < sides.Count; s2++)
                        {
                            // The shared vertex must be a vertex of the polygon
                            Point vertex = sides[s1].SharedVertex(sides[s2]);
                            if (vertex != null && poly.points.Contains(vertex))
                            {
                                GeometryTutorLib.Utilities.AddStructurallyUnique(ssIntersections, new Intersection(vertex, sides[s1], sides[s2]));
                            }
                        }
                    }

                    //
                    // Handle quadrilateral diagonals
                    //
                    if (poly is Quadrilateral)
                    {
                        Quadrilateral quad = poly as Quadrilateral;

                        if (GetMaximalProblemSegment(quad.bottomLeftTopRightDiagonal) == null)
                        {
                            quad.SetBottomRightDiagonalInValid();
                        }

                        if (GetMaximalProblemSegment(quad.topLeftBottomRightDiagonal) == null)
                        {
                            quad.SetTopLeftDiagonalInValid();
                        }

                        // If both diagonals exist in the figure, create an intersection and provide the quadrilateral with the intersection.
                        if (quad.TopLeftDiagonalIsValid() && quad.BottomRightDiagonalIsValid())
                        {
                            // The calculated intersection
                            Point inter = quad.bottomLeftTopRightDiagonal.FindIntersection(quad.topLeftBottomRightDiagonal);

                            // The actual point in the figure
                            Point knownPt = GeometryTutorLib.Utilities.GetStructurally<Point>(allFigurePoints, inter);

                            if (knownPt == null)
                            {
                                throw new Exception("Expected to find the point (did not):");
                            }

                            Intersection diagInter = new Intersection(knownPt, quad.bottomLeftTopRightDiagonal, quad.topLeftBottomRightDiagonal);

                            GeometryTutorLib.Utilities.AddStructurallyUnique<Intersection>(ssIntersections, diagInter);

                            quad.SetIntersection(diagInter);
                        }
                    }
                }
            }

            CalculateMaximalMinimalSegments();
            ConstructMaximalSegmentSegmentIntersections();
        }
Beispiel #27
0
 //public PerpendicularBisector(Point i, Segment l, Segment bisector, string just) : base(i, l, bisector, just)
 //{
 //    this.bisector = bisector;
 //}
 public PerpendicularBisector(Intersection inter, Segment bisector) : base(inter)
 {
     this.bisector = bisector;
 }
        private static List<EdgeAggregator> CheckAndGenerateProportionality(Triangle tri, Intersection inter1,
                                                                            Intersection inter2, Parallel parallel)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The two intersections should not be at the same vertex
            if (inter1.intersect.Equals(inter2.intersect)) return newGrounded;

            //
            // Do these intersections share a segment? That is, do they share the transversal?
            //
            Segment transversal = inter1.AcquireTransversal(inter2);
            if (transversal == null) return newGrounded;

            //
            // Is the transversal a side of the triangle? It should not be.
            //
            if (tri.LiesOn(transversal)) return newGrounded;

            //
            // Determine if one parallel segment is a side of the triangle (which must occur)
            //
            Segment coinciding = tri.DoesParallelCoincideWith(parallel);
            if (coinciding == null) return newGrounded;

            // The transversal and common segment must be distinct
            if (coinciding.IsCollinearWith(transversal)) return newGrounded;

            //
            // Determine if the simplified transversal is within the parallel relationship.
            //
            Segment parallelTransversal = parallel.OtherSegment(coinciding);
            Segment simpleParallelTransversal = new Segment(inter1.intersect, inter2.intersect);

            if (!parallelTransversal.IsCollinearWith(simpleParallelTransversal)) return newGrounded;

            //            A
            //           /\
            //          /  \
            //         /    \
            //  off1  /------\ off2
            //       /        \
            //    B /__________\ C

            //
            // Both intersections should create a T-shape.
            //
            Point off1 = inter1.CreatesTShape();
            Point off2 = inter2.CreatesTShape();
            if (off1 == null || off2 == null) return newGrounded;

            // Get the intersection segments which should coincide with the triangle sides
            KeyValuePair<Segment, Segment> otherSides = tri.OtherSides(coinciding);

            // The intersections may be outside this triangle
            if (otherSides.Key == null || otherSides.Value == null) return newGrounded;

            Segment side1 = inter1.OtherSegment(transversal);
            Segment side2 = inter2.OtherSegment(transversal);

            // Get the actual sides of the triangle
            Segment triangleSide1 = null;
            Segment triangleSide2 = null;
            if (side1.IsCollinearWith(otherSides.Key) && side2.IsCollinearWith(otherSides.Value))
            {
                triangleSide1 = otherSides.Key;
                triangleSide2 = otherSides.Value;
            }
            else if (side1.IsCollinearWith(otherSides.Value) && side2.IsCollinearWith(otherSides.Key))
            {
                triangleSide1 = otherSides.Value;
                triangleSide2 = otherSides.Key;
            }
            else return newGrounded;

            // Verify the opposing parts of the T are on the opposite sides of the triangle
            if (!triangleSide1.PointLiesOnAndExactlyBetweenEndpoints(off2)) return newGrounded;
            if (!triangleSide2.PointLiesOnAndExactlyBetweenEndpoints(off1)) return newGrounded;

            //
            // Construct the new proprtional relationship and resultant equation
            //
            Point sharedVertex = triangleSide1.SharedVertex(triangleSide2);
            SegmentRatio newProp1 = new SegmentRatio(new Segment(sharedVertex, off2), triangleSide1);
            SegmentRatio newProp2 = new SegmentRatio(new Segment(sharedVertex, off1), triangleSide2);

            GeometricSegmentRatioEquation newEq = new GeometricSegmentRatioEquation(newProp1, newProp2);

            // Construct hyperedge
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(tri);
            antecedent.Add(inter1);
            antecedent.Add(inter2);
            antecedent.Add(parallel);

            newGrounded.Add(new EdgeAggregator(antecedent, newEq, annotation));

            return newGrounded;
        }
Beispiel #29
0
        //
        // Creates a Chair
        //
        // |     |                  |
        // |_____|____   leftInter  |_________ tipOfT
        // |                        |     |
        // |                        |     |
        //                         off   tipOfT
        //
        //                                bottomInter
        //
        //                                               <leftInter, bottomInter>
        // Returns the legs of the chair in specific ordering: <off, bottomTip>
        public KeyValuePair <Point, Point> CreatesChairShape(Intersection thatInter)
        {
            KeyValuePair <Point, Point> nullPair = new KeyValuePair <Point, Point>(null, null);

            // A valid transversal is required for this shape
            if (!this.CreatesAValidTransversalWith(thatInter))
            {
                return(nullPair);
            }

            // Both intersections must be standing on (and not endpoints)
            if (!this.StandsOn() || !thatInter.StandsOn())
            {
                return(nullPair);
            }
            if (this.StandsOnEndpoint() || thatInter.StandsOnEndpoint())
            {
                return(nullPair);
            }

            Point thisTipOfT = this.CreatesTShape();
            Point thatTipOfT = thatInter.CreatesTShape();

            Segment transversal = this.AcquireTransversal(thatInter);

            Intersection leftInter   = null;
            Intersection bottomInter = null;

            // Avoid:
            // |
            // |______
            // |     |
            // |     |
            // this is leftInter
            Point bottomTip = null;

            if (transversal.PointLiesOn(thisTipOfT))
            {
                if (transversal.PointLiesOnAndBetweenEndpoints(thisTipOfT))
                {
                    return(nullPair);
                }

                leftInter   = this;
                bottomInter = thatInter;
                bottomTip   = thisTipOfT;
            }
            // thatInter is leftInter
            else if (transversal.PointLiesOn(thatTipOfT))
            {
                if (transversal.PointLiesOnAndBetweenEndpoints(thatTipOfT))
                {
                    return(nullPair);
                }

                leftInter   = thatInter;
                bottomInter = this;
                bottomTip   = thisTipOfT;
            }
            // Otherwise, this indicates a PI-shaped scenario
            else
            {
                return(nullPair);
            }

            //
            // Returns the bottom of the legs of the chair
            //
            Segment parallelLeft   = leftInter.OtherSegment(transversal);
            Segment crossingTester = new Segment(parallelLeft.Point1, bottomTip);
            Point   intersection   = transversal.FindIntersection(crossingTester);

            Point off = transversal.PointLiesOnAndBetweenEndpoints(intersection) ? parallelLeft.Point2 : parallelLeft.Point1;

            return(new KeyValuePair <Point, Point>(off, bottomTip));
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // Two Secants
        // Intersection(X, AD, BC) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateTwoSecantsTheorem(Intersection inter, Circle circle)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Is this intersection explicitly outside the circle? That is, the point of intersection exterior?
            if (!circle.PointIsExterior(inter.intersect)) return newGrounded;

            //
            // Get the chords
            //
            Segment chord1 = circle.ContainsChord(inter.lhs);
            Segment chord2 = circle.ContainsChord(inter.rhs);

            if (chord1 == null || chord2 == null) return newGrounded;

            Point closeChord1Pt = null;
            Point closeChord2Pt = null;
            Point farChord1Pt = null;
            Point farChord2Pt = null;
            if (Segment.Between(chord1.Point1, chord1.Point2, inter.intersect))
            {
                closeChord1Pt = chord1.Point1;
                farChord1Pt = chord1.Point2;
            }
            else
            {
                closeChord1Pt = chord1.Point2;
                farChord1Pt = chord1.Point1;
            }

            if (Segment.Between(chord2.Point1, chord2.Point2, inter.intersect))
            {
                closeChord2Pt = chord2.Point1;
                farChord2Pt = chord2.Point2;
            }
            else
            {
                closeChord2Pt = chord2.Point2;
                farChord2Pt = chord2.Point1;
            }

            //
            // Get the arcs
            //
            Arc closeArc = Arc.GetFigureMinorArc(circle, closeChord1Pt, closeChord2Pt);
            Arc farArc = Arc.GetFigureMinorArc(circle, farChord1Pt, farChord2Pt);

            Angle theAngle = Angle.AcquireFigureAngle(new Angle(closeChord1Pt, inter.intersect, closeChord2Pt));

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            //GeometricAngleEquation gaeq = new GeometricAngleEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));
            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(inter);
            antecedent.Add(circle);
            antecedent.Add(closeArc);
            antecedent.Add(farArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
 private static List<GroundedClause> MakeAntecedent(Intersection inter, Angle angle1, Angle angle2)
 {
     List<GroundedClause> antecedent = Utilities.MakeList<GroundedClause>(inter);
     antecedent.Add(angle1);
     antecedent.Add(angle2);
     return antecedent;
 }
        private static List<EdgeAggregator> CheckAndGenerateCorrespondingAnglesImplyParallel(Intersection inter1, Intersection inter2, CongruentAngles conAngles)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The two intersections should not be at the same vertex
            if (inter1.intersect.Equals(inter2.intersect)) return newGrounded;

            Segment transversal = inter1.CommonSegment(inter2);

            if (transversal == null) return newGrounded;

            Angle angleI = inter1.GetInducedNonStraightAngle(conAngles);
            Angle angleJ = inter2.GetInducedNonStraightAngle(conAngles);

            //
            // Do we have valid intersections and congruent angle pairs
            //
            if (angleI == null || angleJ == null) return newGrounded;

            //
            // Check to see if they are, in fact, Corresponding Angles
            //
            Segment parallelCand1 = inter1.OtherSegment(transversal);
            Segment parallelCand2 = inter2.OtherSegment(transversal);

            // The resultant candidate parallel segments shouldn't share any vertices
            if (parallelCand1.SharedVertex(parallelCand2) != null) return newGrounded;

            // Numeric hack to discount any non-parallel segments
            if (!parallelCand1.IsParallelWith(parallelCand2)) return newGrounded;

            // A sanity check that the '4th' point does not lie on the other intersection (thus creating an obvious triangle and thus not parallel lines)
            Point fourthPoint1 = parallelCand1.OtherPoint(inter1.intersect);
            Point fourthPoint2 = parallelCand2.OtherPoint(inter2.intersect);
            if (fourthPoint1 != null && fourthPoint2 != null)
            {
                if (parallelCand1.PointLiesOn(fourthPoint2) || parallelCand2.PointLiesOn(fourthPoint1)) return newGrounded;
            }

            // Both angles should NOT be in the interioir OR the exterioir; a combination is needed.
            bool ang1Interior = angleI.OnInteriorOf(inter1, inter2);
            bool ang2Interior = angleJ.OnInteriorOf(inter1, inter2);
            if (ang1Interior && ang2Interior) return newGrounded;
            if (!ang1Interior && !ang2Interior) return newGrounded;

            //
            // Are these angles on the same side of the transversal?
            //
            //
            // Make a simple transversal from the two intersection points
            Segment simpleTransversal = new Segment(inter1.intersect, inter2.intersect);

            // Find the rays the lie on the transversal
            Segment rayNotOnTransversalI = angleI.OtherRayEquates(simpleTransversal);
            Segment rayNotOnTransversalJ = angleJ.OtherRayEquates(simpleTransversal);

            Point pointNotOnTransversalNorVertexI = rayNotOnTransversalI.OtherPoint(angleI.GetVertex());
            Point pointNotOnTransversalNorVertexJ = rayNotOnTransversalJ.OtherPoint(angleJ.GetVertex());

            // Create a segment from these two points so we can compare distances
            Segment crossing = new Segment(pointNotOnTransversalNorVertexI, pointNotOnTransversalNorVertexJ);

            //
            // Will this crossing segment actually intersect the real transversal in the middle of the two segments It should NOT.
            //
            Point intersection = transversal.FindIntersection(crossing);

            if (Segment.Between(intersection, inter1.intersect, inter2.intersect)) return newGrounded;

            //
            // Now we have an alternate interior scenario
            //
            GeometricParallel newParallel = new GeometricParallel(parallelCand1, parallelCand2);

            // Construct hyperedge
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(inter1);
            antecedent.Add(inter2);
            antecedent.Add(conAngles);

            newGrounded.Add(new EdgeAggregator(antecedent, newParallel, annotation));

            return newGrounded;
        }
        //  A      B
        //   \    /
        //    \  /
        //     \/
        //     /\ X
        //    /  \
        //   /    \
        //  C      D
        //
        // Intersection(X, Segment(A, D), Segment(B, C)) -> Supplementary(Angle(A, X, B), Angle(B, X, D))
        //                                                  Supplementary(Angle(B, X, D), Angle(D, X, C))
        //                                                  Supplementary(Angle(D, X, C), Angle(C, X, A))
        //                                                  Supplementary(Angle(C, X, A), Angle(A, X, B))
        //
        public static List<EdgeAggregator> InstantiateToSupplementary(Intersection inter)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The situation looks like this:
            //  |
            //  |
            //  |_______
            //
            if (inter.StandsOnEndpoint()) return newGrounded;

            // The situation looks like this:
            //       |
            //       |
            //  _____|_______
            //
            if (inter.StandsOn())
            {
                Point up = null;
                Point left = null;
                Point right = null;
                if (inter.lhs.HasPoint(inter.intersect))
                {
                    up = inter.lhs.OtherPoint(inter.intersect);
                    left = inter.rhs.Point1;
                    right = inter.rhs.Point2;
                }
                else
                {
                    up = inter.rhs.OtherPoint(inter.intersect);
                    left = inter.lhs.Point1;
                    right = inter.lhs.Point2;
                }

                // Gets the single angle object from the original figure
                Angle newAngle1 = Angle.AcquireFigureAngle(new Angle(left, inter.intersect, up));
                Angle newAngle2 = Angle.AcquireFigureAngle(new Angle(right, inter.intersect, up));

                Supplementary supp = new Supplementary(newAngle1, newAngle2);
                supp.SetNotASourceNode();
                supp.SetNotAGoalNode();
                supp.SetClearDefinition();

                newGrounded.Add(new EdgeAggregator(MakeAntecedent(inter, supp.angle1, supp.angle2), supp, annotation));
            }

            //
            // The situation is standard and results in 4 supplementary relationships
            //
            else
            {
                Angle newAngle1 = Angle.AcquireFigureAngle(new Angle(inter.lhs.Point1, inter.intersect, inter.rhs.Point1));
                Angle newAngle2 = Angle.AcquireFigureAngle(new Angle(inter.lhs.Point1, inter.intersect, inter.rhs.Point2));
                Angle newAngle3 = Angle.AcquireFigureAngle(new Angle(inter.lhs.Point2, inter.intersect, inter.rhs.Point1));
                Angle newAngle4 = Angle.AcquireFigureAngle(new Angle(inter.lhs.Point2, inter.intersect, inter.rhs.Point2));

                List<Supplementary> newSupps = new List<Supplementary>();
                newSupps.Add(new Supplementary(newAngle1, newAngle2));
                newSupps.Add(new Supplementary(newAngle2, newAngle4));
                newSupps.Add(new Supplementary(newAngle3, newAngle4));
                newSupps.Add(new Supplementary(newAngle3, newAngle1));

                foreach (Supplementary supp in newSupps)
                {
                    supp.SetNotASourceNode();
                    supp.SetNotAGoalNode();
                    supp.SetClearDefinition();

                    newGrounded.Add(new EdgeAggregator(MakeAntecedent(inter, supp.angle1, supp.angle2), supp, annotation));
                }
            }

            return newGrounded;
        }
 //public PerpendicularBisector(Point i, Segment l, Segment bisector, string just) : base(i, l, bisector, just)
 //{
 //    this.bisector = bisector;
 //}
 public PerpendicularBisector(Intersection inter, Segment bisector)
     : base(inter)
 {
     this.bisector = bisector;
 }
        //
        //    A \      / B
        //       \    /
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    \ D
        //
        // Intersection(Segment(AD), Segment(BC)) -> 2 * Angle(CXA) = Arc(A, C) + Arc(B, D),
        //                                           2 * Angle(BXD) = Arc(A, C) + Arc(B, D),
        //                                           2 * Angle(AXB) = Arc(A, B) + Arc(C, D),
        //                                           2 * Angle(CXD) = Arc(A, B) + Arc(C, D)
        //
        public static List<EdgeAggregator> InstantiateTheorem(Intersection inter, Circle circle)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Is this intersection explicitly inside the circle? That is, the point of intersection interior?
            if (!circle.PointIsInterior(inter.intersect)) return newGrounded;

            //
            // Get the chords
            //
            Segment chord1 = circle.GetChord(inter.lhs);
            Segment chord2 = circle.GetChord(inter.rhs);

            if (chord1 == null || chord2 == null) return newGrounded;

            //
            // Group 1
            //
            Arc arc1 = Arc.GetFigureMinorArc(circle, chord1.Point1, chord2.Point1);
            Angle angle1 = Angle.AcquireFigureAngle(new Angle(chord1.Point1, inter.intersect, chord2.Point1));

            Arc oppArc1 = Arc.GetFigureMinorArc(circle, chord1.Point2, chord2.Point2);
            Angle oppAngle1 = Angle.AcquireFigureAngle(new Angle(chord1.Point2, inter.intersect, chord2.Point2));

            //
            // Group 2
            //
            Arc arc2 = Arc.GetFigureMinorArc(circle, chord1.Point1, chord2.Point2);
            Angle angle2 = Angle.AcquireFigureAngle(new Angle(chord1.Point1, inter.intersect, chord2.Point2));

            Arc oppArc2 = Arc.GetFigureMinorArc(circle, chord1.Point2, chord2.Point1);
            Angle oppAngle2 = Angle.AcquireFigureAngle(new Angle(chord1.Point2, inter.intersect, chord2.Point1));

            //
            // Construct each of the 4 equations.
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaeq1 = new GeometricAngleArcEquation(new Multiplication(two, angle1), new Addition(arc1, oppArc1));
            GeometricAngleArcEquation gaeq2 = new GeometricAngleArcEquation(new Multiplication(two, oppAngle1), new Addition(arc1, oppArc1));

            GeometricAngleArcEquation gaeq3 = new GeometricAngleArcEquation(new Multiplication(two, angle2), new Addition(arc2, oppArc2));
            GeometricAngleArcEquation gaeq4 = new GeometricAngleArcEquation(new Multiplication(two, oppAngle2), new Addition(arc2, oppArc2));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(inter);
            antecedent.Add(circle);

            newGrounded.Add(new EdgeAggregator(antecedent, gaeq1, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq2, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq3, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq4, annotation));

            return newGrounded;
        }