// Return the shared angle in both congruences
        public Angle AngleShared(AnglePairRelation relation)
        {
            if (angle1.Equates(relation.angle1) || angle1.Equates(relation.angle2)) return angle1;
            if (angle2.Equates(relation.angle1) || angle2.Equates(relation.angle2)) return angle2;

            return null;
        }
        public override bool Equals(Object obj)
        {
            AnglePairRelation relation = obj as AnglePairRelation;

            if (relation == null)
            {
                return(false);
            }
            return((angle1.Equals(relation.angle1) && angle2.Equals(relation.angle2)) ||
                   (angle1.Equals(relation.angle2) && angle2.Equals(relation.angle1)) && base.Equals(relation));
        }
        public override bool StructurallyEquals(Object obj)
        {
            AnglePairRelation relation = obj as AnglePairRelation;

            if (relation == null)
            {
                return(false);
            }
            return((angle1.StructurallyEquals(relation.angle1) && angle2.StructurallyEquals(relation.angle2)) ||
                   (angle1.StructurallyEquals(relation.angle2) && angle2.StructurallyEquals(relation.angle1)));
        }
        // Return the shared angle in both congruences
        public Angle AngleShared(AnglePairRelation relation)
        {
            if (angle1.Equates(relation.angle1) || angle1.Equates(relation.angle2))
            {
                return(angle1);
            }
            if (angle2.Equates(relation.angle1) || angle2.Equates(relation.angle2))
            {
                return(angle2);
            }

            return(null);
        }
        private static List<EdgeAggregator> IndirectRelations(CongruentAngles cas, AnglePairRelation relation1, AnglePairRelation relation2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Do we have the same type of relation?
            if (relation1.GetType() != relation2.GetType()) return newGrounded;

            //
            // Determine the shared values amongst the relations
            //
            Angle shared1 = relation1.AngleShared(cas);
            if (shared1 == null) return newGrounded;

            Angle shared2 = cas.OtherAngle(shared1);
            if (!relation2.HasAngle(shared2)) return newGrounded;

            Angle otherAngle1 = relation1.OtherAngle(shared1);
            Angle otherAngle2 = relation2.OtherAngle(shared2);

            // Avoid generating a reflexive relationship
            if (otherAngle1.Equates(otherAngle2)) return newGrounded;

            //
            // Congruent(Angle(1), Angle(3))
            //
            // The other two angles from the relation pairs are then congruent
            GeometricCongruentAngles gcas = new GeometricCongruentAngles(otherAngle1, otherAngle2);

            // Avoid direct cyclic congruent angle generation
            if (cas.StructurallyEquals(gcas)) return newGrounded;

            // Construct hyperedge
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(cas);
            antecedent.Add(relation1);
            antecedent.Add(relation2);

            //
            // AnglePairRelation(Angle(1), Angle(4)),
            // AnglePairRelation(Angle(2), Angle(3)),
            //
            if (relation1 is Complementary && relation2 is Complementary)
            {
                Complementary comp1 = new Complementary(shared1, otherAngle2);
                Complementary comp2 = new Complementary(shared2, otherAngle1);

                newGrounded.Add(new EdgeAggregator(antecedent, comp1, compAnnotation));
                newGrounded.Add(new EdgeAggregator(antecedent, comp2, compAnnotation));
            }
            else if (relation1 is Supplementary && relation2 is Supplementary)
            {
                Supplementary supp1 = new Supplementary(shared1, otherAngle2);
                Supplementary supp2 = new Supplementary(shared2, otherAngle1);

                newGrounded.Add(new EdgeAggregator(antecedent, supp1, suppAnnotation));
                newGrounded.Add(new EdgeAggregator(antecedent, supp2, suppAnnotation));
            }
            else
            {
                throw new ArgumentException("RelationsOfCongruent:: Expected a supplementary or complementary angle, not " + relation1.GetType());
            }

            newGrounded.Add(new EdgeAggregator(antecedent, gcas, relation1 is Complementary ? compAnnotation : suppAnnotation));

            return newGrounded;
        }
        private static List<EdgeAggregator> DirectRelations(AnglePairRelation relation1, AnglePairRelation relation2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Do we have the same type of relation?
            if (relation1.GetType() != relation2.GetType()) return newGrounded;

            // Acquire the shared angle
            Angle shared = relation1.AngleShared(relation2);
            if (shared == null) return newGrounded;

            Angle otherAngle1 = relation1.OtherAngle(shared);
            Angle otherAngle2 = relation2.OtherAngle(shared);

            // Avoid generating a reflexive relationship
            if (otherAngle1.Equates(otherAngle2)) return newGrounded;

            // The other two angles are then congruent
            GeometricCongruentAngles gcas = new GeometricCongruentAngles(otherAngle1, otherAngle2);

            // Construct hyperedge
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(relation1);
            antecedent.Add(relation2);

            newGrounded.Add(new EdgeAggregator(antecedent, gcas, relation1 is Complementary ? compAnnotation : suppAnnotation));

            return newGrounded;
        }