// A D // /\ /\ // / \ / \ // / \ / \ // /______\ /______\ // B C E F // // In order for two triangles to be congruent, we require the following: // Triangle(A, B, C), Triangle(D, E, F), // Congruent(Angle(A, B, C), Angle(D, E, F)), // Congruent(Angle(A, C, B), Angle(D, F, E)) -> Congruent(Angle(B, A, C), Angle(E, D, F)), // public static List <EdgeAggregator> Instantiate(GroundedClause c) { annotation.active = EngineUIBridge.JustificationSwitch.TWO_PAIRS_CONGRUENT_ANGLES_IMPLY_THIRD_PAIR_CONGRUENT; List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // Do we have a segment or triangle? if (!(c is CongruentAngles) && !(c is Triangle)) { return(newGrounded); } if (c is CongruentAngles) { CongruentAngles newCas = c as CongruentAngles; // Reflexive relationships will not relate two distinct triangles if (newCas.IsReflexive()) { return(newGrounded); } // Check all combinations of triangles to see if they have congruent pairs // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { foreach (CongruentAngles oldCas in candidateCongruent) { newGrounded.AddRange(CheckAndGenerateThirdCongruentPair(candidateTriangles[i], candidateTriangles[j], newCas, oldCas)); } } } candidateCongruent.Add(newCas); } else if (c is Triangle) { Triangle newTri = c as Triangle; // Check all combinations of triangles to see if they have congruent pairs // This congruence must include the new segment congruence for (int i = 0; i < candidateCongruent.Count - 1; i++) { for (int j = i + 1; j < candidateCongruent.Count; j++) { foreach (Triangle oldTri in candidateTriangles) { newGrounded.AddRange(CheckAndGenerateThirdCongruentPair(newTri, oldTri, candidateCongruent[i], candidateCongruent[j])); } } } candidateTriangles.Add(newTri); } return(newGrounded); }
// // Construct the AngleBisector if we have // // V---------------A // / \ // / \ // / \ // B C // // Congruent(Angle, A, V, C), Angle(C, V, B)), Segment(V, C)) -> AngleBisector(Angle(A, V, B) // // private static List <EdgeAggregator> InstantiateToDef(CongruentAngles cas, Segment segment) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // Find the shared segment between the two angles; we know it is valid if we reach this point Segment shared = cas.AreAdjacent(); // The bisector must align with the given segment if (!segment.IsCollinearWith(shared)) { return(newGrounded); } // We need a true bisector in which the shared vertex of the angles in between the endpoints of this segment if (!segment.PointLiesOnAndBetweenEndpoints(cas.ca1.GetVertex())) { return(newGrounded); } // // Create the overall angle which is being bisected // Point vertex = cas.ca1.GetVertex(); Segment newRay1 = cas.ca1.OtherRayEquates(shared); Segment newRay2 = cas.ca2.OtherRayEquates(shared); Angle combinedAngle = new Angle(newRay1.OtherPoint(vertex), vertex, newRay2.OtherPoint(vertex)); // Determine if the segment is a straight angle (we don't want an angle bisector here, we would want a segment bisector) if (newRay1.IsCollinearWith(newRay2)) { return(newGrounded); } // The bisector cannot be of the form: // \ // \ // V---------------A // / // / // B if (!combinedAngle.IsOnInteriorExplicitly(segment.Point1) && !combinedAngle.IsOnInteriorExplicitly(segment.Point2)) { return(newGrounded); } AngleBisector newAB = new AngleBisector(combinedAngle, segment); // For hypergraph List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(segment); antecedent.Add(cas); newGrounded.Add(new EdgeAggregator(antecedent, newAB, annotation)); return(newGrounded); }
// // Just generate the new triangle // private static EdgeAggregator GenerateCongruentSides(Triangle tri, CongruentAngles cas) { GeometricCongruentSegments newConSegs = new GeometricCongruentSegments(tri.OtherSide(cas.ca1), tri.OtherSide(cas.ca2)); List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(cas); antecedent.Add(tri); return(new EdgeAggregator(antecedent, newConSegs, annotation)); }
// // AnglePairRelation(Angle(1), Angle(2)), // AnglePairRelation(Angle(3), Angle(4)), // Congruent(Angle(2), Angle(4)) -> Congruent(Angle(1), Angle(3)) // AnglePairRelation(Angle(1), Angle(4)), // AnglePairRelation(Angle(2), Angle(3)), // // | / // |1 / // | / 2 // |/____________________ // | / // |3 / // | / 4 // |/____________________ // // // AnglePairRelation(Angle(1), Angle(2)), // AnglePairRelation(Angle(3), Angle(4)), // Congruent(Angle(2), Angle(4)) -> Congruent(Angle(1), Angle(3)) // AnglePairRelation(Angle(1), Angle(4)), // AnglePairRelation(Angle(2), Angle(3)), // // / / // / / // 1 / /\ 2 // ____________/ /__\__________________ // / / // / / // 3 / /\ 4 // ____________/ /__\__________________ // public static List <EdgeAggregator> Instantiate(GroundedClause c) { compAnnotation.active = EngineUIBridge.JustificationSwitch.RELATIONS_OF_CONGRUENT_ANGLES_ARE_CONGRUENT; suppAnnotation.active = EngineUIBridge.JustificationSwitch.RELATIONS_OF_CONGRUENT_ANGLES_ARE_CONGRUENT; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (!(c is CongruentAngles) && !(c is AnglePairRelation)) { return(newGrounded); } if (c is CongruentAngles) { CongruentAngles cas = c as CongruentAngles; // We are not interested in reflexive relationships implying congruences or any complementary or supplementary relations. if (cas.IsReflexive()) { return(newGrounded); } for (int i = 0; i < candRelation.Count - 1; i++) { for (int j = i + 1; j < candRelation.Count; j++) { newGrounded.AddRange(IndirectRelations(cas, candRelation[i], candRelation[j])); } } candCongruentAngles.Add(cas); } else if (c is AnglePairRelation) { AnglePairRelation newRelation = c as AnglePairRelation; foreach (AnglePairRelation relation in candRelation) { newGrounded.AddRange(DirectRelations(relation, newRelation)); foreach (CongruentAngles cas in candCongruentAngles) { newGrounded.AddRange(IndirectRelations(cas, relation, newRelation)); } } candRelation.Add(newRelation); } return(newGrounded); }
// // Intersection(M, Segment(A,B), Segment(C, D)), // Intersection(N, Segment(A,B), Segment(E, F)), // Congruent(Angle(A, N, F), Angle(A, M, D)) -> Parallel(Segment(C, D), Segment(E, F)) // // B // / // C-----------/-----------D // / M // / // E---------/-----------F // / N // A // public static List <EdgeAggregator> Instantiate(GroundedClause c) { annotation.active = EngineUIBridge.JustificationSwitch.CONGRUENT_CORRESPONDING_ANGLES_IMPLY_PARALLEL; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (!(c is CongruentAngles) && !(c is Intersection)) { return(newGrounded); } if (c is CongruentAngles) { CongruentAngles conAngles = c as CongruentAngles; if (conAngles.IsReflexive()) { return(newGrounded); } // Find two candidate lines cut by the same transversal for (int i = 0; i < candIntersection.Count - 1; i++) { for (int j = i + 1; j < candIntersection.Count; j++) { newGrounded.AddRange(CheckAndGenerateCorrespondingAnglesImplyParallel(candIntersection[i], candIntersection[j], conAngles)); } } candAngles.Add(conAngles); } else if (c is Intersection) { Intersection newIntersection = c as Intersection; // Find two candidate lines cut by the same transversal foreach (Intersection inter in candIntersection) { foreach (CongruentAngles cas in candAngles) { newGrounded.AddRange(CheckAndGenerateCorrespondingAnglesImplyParallel(newIntersection, inter, cas)); } } candIntersection.Add(newIntersection); } return(newGrounded); }
// // Intersection(M, Segment(A,B), Segment(C, D)), // Congruent(Angle(C, M, B), Angle(D, M, B)) -> Perpendicular(Segment(A, B), Segment(C, D)) // // B // / // C-----------/-----------D // / M // / // A public static List <EdgeAggregator> Instantiate(GroundedClause c) { annotation.active = EngineUIBridge.JustificationSwitch.CONGRUENT_ADJACENT_ANGLES_IMPLY_PERPENDICULAR; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (c is CongruentAngles) { CongruentAngles conAngles = c as CongruentAngles; // We are interested in adjacent angles, not reflexive if (conAngles.IsReflexive()) { return(newGrounded); } // Any candidates congruent angles need to be adjacent to each other. if (conAngles.AreAdjacent() == null) { return(newGrounded); } // Find two candidate lines cut by the same transversal foreach (Intersection inter in candIntersection) { newGrounded.AddRange(CheckAndGenerateCongruentAdjacentImplyPerpendicular(inter, conAngles)); } candAngles.Add(conAngles); } else if (c is Intersection) { Intersection newIntersection = c as Intersection; if (!newIntersection.IsStraightAngleIntersection()) { return(newGrounded); } foreach (CongruentAngles cas in candAngles) { newGrounded.AddRange(CheckAndGenerateCongruentAdjacentImplyPerpendicular(newIntersection, cas)); } candIntersection.Add(newIntersection); } return(newGrounded); }
// A // /\ // / \ // / \ // /______\ // B C // // In order for two triangles to be Similar, we require the following: // Triangle(A, B, C), Triangle(D, E, F), // Congruent(Angle(B, C, A), Angle(E, F, D)) // Congruent(Angle(A, B, C), Angle(D, E, F)) -> Similar(Triangle(A, B, C), Triangle(D, E, F)), // Proportional(Segment(A, C), Angle(D, F)), // Proportional(Segment(A, B), Segment(D, E)), // Proportional(Segment(B, C), Segment(E, F)) // Congruent(Angle(C, A, B), Angle(F, D, E)), // public static List <EdgeAggregator> Instantiate(GroundedClause clause) { annotation.active = EngineUIBridge.JustificationSwitch.AA_SIMILARITY; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (clause is CongruentAngles) { CongruentAngles newCas = clause as CongruentAngles; // Check all combinations of triangles to see if they are congruent // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { foreach (CongruentAngles oldCas in candidateAngles) { newGrounded.AddRange(InstantiateAASimilarity(candidateTriangles[i], candidateTriangles[j], oldCas, newCas)); } } } candidateAngles.Add(newCas); } // If this is a new triangle, check for triangles which may be congruent to this new triangle else if (clause is Triangle) { Triangle newTriangle = clause as Triangle; // Check all combinations of triangles to see if they are congruent // This congruence must include the new segment congruence foreach (Triangle oldTri in candidateTriangles) { for (int m = 0; m < candidateAngles.Count - 1; m++) { for (int n = m + 1; n < candidateAngles.Count; n++) { newGrounded.AddRange(InstantiateAASimilarity(newTriangle, oldTri, candidateAngles[m], candidateAngles[n])); } } } candidateTriangles.Add(newTriangle); } return(newGrounded); }
private static List <EdgeAggregator> InstantiateCongruent(GroundedClause c) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (c is CongruentAngles) { CongruentAngles cas = c as CongruentAngles; // We are interested in adjacent angles, not reflexive if (cas.IsReflexive()) { return(newGrounded); } if (cas.AreAdjacent() == null) { return(newGrounded); } // // The candidate must equates to a given segment; that is, find the proper segment // The segment must pass through the actual vertex of the adjacent angles // foreach (Segment segment in candidateSegments) { newGrounded.AddRange(InstantiateToDef(cas, segment)); } // Did not unify so add to the candidate list if (!newGrounded.Any()) { candidateCongruent.Add(cas); } } else if (c is Segment) { Segment segment = c as Segment; foreach (CongruentAngles cas in candidateCongruent) { newGrounded.AddRange(InstantiateToDef(cas, segment)); } candidateSegments.Add(segment); } return(newGrounded); }
/// <summary> /// Figure out what possible angle combinations are before showing the window. /// </summary> protected override void OnShow() { options = new Dictionary <Angle, List <Angle> >(); //Get a list of all congruent angle givens List <GroundedClause> cangs = new List <GroundedClause>(); foreach (GroundedClause gc in currentGivens) { CongruentAngles cang = gc as CongruentAngles; if (cang != null) { cangs.Add(cang); } } //Pick a first angle... foreach (Angle a1 in parser.backendParser.implied.angles) { List <Angle> possible = new List <Angle>(); //... and see what other angles are viable second options. foreach (Angle a2 in parser.backendParser.implied.angles) { if (a1.measure == a2.measure) { CongruentAngles cang = new CongruentAngles(a1, a2); if (!a1.StructurallyEquals(a2) && !StructurallyContains(cangs, cang)) { possible.Add(a2); } } } //If we found a possible list of combinations, add it to the dictionary if (possible.Count > 0) { options.Add(a1, possible); } } //Set the options of the angle1 combo box angle1.ItemsSource = null; //Graphical refresh angle1.ItemsSource = options.Keys; }
// // Acquires all of the applicable congruent segments as well as congruent angles. Then checks for SAS // private static List <EdgeAggregator> CheckAndGenerateThirdCongruentPair(Triangle tri1, Triangle tri2, CongruentAngles cas1, CongruentAngles cas2) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // We have eliminated all reflexive relationships at this point // The congruent relations should not share any angles if (cas1.AngleShared(cas2) != null) { return(newGrounded); } // Both congruent pairs of angles must relate both triangles if (!cas1.LinksTriangles(tri1, tri2)) { return(newGrounded); } if (!cas2.LinksTriangles(tri1, tri2)) { return(newGrounded); } Angle firstAngleTri1 = tri1.AngleBelongs(cas1); Angle secondAngleTri1 = tri1.AngleBelongs(cas2); Angle firstAngleTri2 = tri2.AngleBelongs(cas1); Angle secondAngleTri2 = tri2.AngleBelongs(cas2); Angle thirdAngle1 = tri1.OtherAngle(firstAngleTri1, secondAngleTri1); Angle thirdAngle2 = tri2.OtherAngle(firstAngleTri2, secondAngleTri2); CongruentAngles newCas = new CongruentAngles(thirdAngle1, thirdAngle2); // Hypergraph List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(tri1); antecedent.Add(tri2); antecedent.Add(cas1); antecedent.Add(cas2); newGrounded.Add(new EdgeAggregator(antecedent, newCas, annotation)); return(newGrounded); }
// // Implements 'transitivity' with right angles; that is, we may know two angles are congruent and if one is a right angle, the other is well // // Congruent(Angle(A, B, C), Angle(D, E, F), RightAngle(A, B, C) -> RightAngle(D, E, F) // public static List <EdgeAggregator> InstantiateToRightAngle(RightAngle ra, CongruentAngles cas, GroundedClause original) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // The congruent must have the given angle in order to generate if (!cas.HasAngle(ra)) { return(newGrounded); } Angle toBeRight = cas.OtherAngle(ra); Strengthened newRightAngle = new Strengthened(toBeRight, new RightAngle(toBeRight)); List <GroundedClause> antecedent = Utilities.MakeList <GroundedClause>(original); antecedent.Add(cas); newGrounded.Add(new EdgeAggregator(antecedent, newRightAngle, transAnnotation)); return(newGrounded); }
private static List<EdgeAggregator> InstantiateToTheorem(GroundedClause clause) { List<EdgeAggregator> newGrounded = new List<EdgeAggregator>(); if (clause is Quadrilateral) { Quadrilateral quad = clause as Quadrilateral; if (!quad.IsStrictQuadrilateral()) return newGrounded; for (int i = 0; i < candidateCongruent.Count - 1; i++) { for (int j = i + 1; j < candidateCongruent.Count; j++) { newGrounded.AddRange(InstantiateToTheorem(quad, candidateCongruent[i], candidateCongruent[j])); } } candidateQuadrilateral.Add(quad); } else if (clause is CongruentAngles) { CongruentAngles newCas = clause as CongruentAngles; if (newCas.IsReflexive()) return newGrounded; foreach (Quadrilateral quad in candidateQuadrilateral) { foreach (CongruentAngles oldCas in candidateCongruent) { newGrounded.AddRange(InstantiateToTheorem(quad, newCas, oldCas)); } } candidateCongruent.Add(newCas); } return newGrounded; }
// // Supplementary(Angle(A, B, D), Angle(B, A, C)) // Congruent(Angle(A, B, D), Angle(B, A, C)) -> RightAngle(Angle(A, B, D)) // -> RightAngle(Angle(B, A, C)) // // C D // | | // |____________| // A B // public static List <EdgeAggregator> Instantiate(GroundedClause c) { annotation.active = EngineUIBridge.JustificationSwitch.CONGRUENT_SUPPLEMENTARY_ANGLES_IMPLY_RIGHT_ANGLES; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (c is CongruentAngles) { CongruentAngles conAngles = c as CongruentAngles; // We are interested in adjacent angles, not reflexive if (conAngles.IsReflexive()) { return(newGrounded); } foreach (Supplementary suppAngles in candSupplementary) { newGrounded.AddRange(CheckAndGenerateSupplementaryCongruentImplyRightAngles(suppAngles, conAngles)); } candCongruent.Add(conAngles); } else if (c is Supplementary) { Supplementary supplementary = c as Supplementary; foreach (CongruentAngles cc in candCongruent) { newGrounded.AddRange(CheckAndGenerateSupplementaryCongruentImplyRightAngles(supplementary, cc)); } candSupplementary.Add(supplementary); } return(newGrounded); }
private static List<EdgeAggregator> InstantiateToTheorem(Quadrilateral quad, CongruentAngles cas1, CongruentAngles cas2) { List<EdgeAggregator> newGrounded = new List<EdgeAggregator>(); // Are the pairs on the opposite side of this quadrilateral? if (!quad.HasOppositeCongruentAngles(cas1)) return newGrounded; if (!quad.HasOppositeCongruentAngles(cas2)) return newGrounded; // // Create the new Rhombus object // Strengthened newParallelogram = new Strengthened(quad, new Parallelogram(quad)); // For hypergraph List<GroundedClause> antecedent = new List<GroundedClause>(); antecedent.Add(quad); antecedent.Add(cas1); antecedent.Add(cas2); newGrounded.Add(new EdgeAggregator(antecedent, newParallelogram, annotation)); return newGrounded; }
// // All right angles are supplementary. // public static List <EdgeAggregator> InstantiateToSupplementary(CongruentAngles cas) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (cas.IsReflexive()) { return(newGrounded); } if (!(cas.ca1 is RightAngle) || !(cas.ca2 is RightAngle)) { return(newGrounded); } Supplementary supp = new Supplementary(cas.ca1, cas.ca2); supp.SetNotASourceNode(); supp.SetNotAGoalNode(); supp.SetClearDefinition(); newGrounded.Add(new EdgeAggregator(Utilities.MakeList <GroundedClause>(cas), supp, annotation)); return(newGrounded); }
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); }
// // A // / \ // B---C // // Triangle(A, B, C), Congruent(\angle ABC, \angle ACB) -> Congruent(Segment(A, B), Segment(A, C)) // public static List <EdgeAggregator> Instantiate(GroundedClause c) { annotation.active = EngineUIBridge.JustificationSwitch.CONGRUENT_ANGLES_IN_TRIANGLE_IMPLY_CONGRUENT_SIDES; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (!MayUnifyWith(c)) { return(newGrounded); } // // Unify // if (c is CongruentAngles) { CongruentAngles cas = c as CongruentAngles; // Only generate or add to possible congruent pairs if this is a non-reflexive relation if (!cas.IsReflexive()) { for (int t = 0; t < candTris.Count; t++) { if (candTris[t].HasAngle(cas.ca1) && candTris[t].HasAngle(cas.ca2)) { newGrounded.Add(GenerateCongruentSides(candTris[t], cas)); // There should be only one possible Isosceles triangle from this congruent angles // So we can remove this relationship and triangle from consideration candTris.RemoveAt(t); return(newGrounded); } } candAngs.Add(cas); } return(new List <EdgeAggregator>()); } else if (c is Triangle) { Triangle newTriangle = c as Triangle; // // Do any of the congruent segment pairs merit calling this new triangle isosceles? // for (int ca = 0; ca < candAngs.Count; ca++) { // No need to check for this, in theory, since we never add any reflexive expressions to the list if (!candAngs[ca].IsReflexive()) { if (newTriangle.HasAngle(candAngs[ca].ca1) && newTriangle.HasAngle(candAngs[ca].ca2)) { newGrounded.Add(GenerateCongruentSides(newTriangle, candAngs[ca])); return(newGrounded); } } } // Add the the list of candidates if it was not determined isosceles now. candTris.Add(newTriangle); } return(newGrounded); }
// A // /) // / ) // / ) // center: O ) // \ ) // \ ) // \) // C // // D // /) // / ) // / ) // center: Q ) // \ ) // \ ) // \) // F // // Congruent(Angle(AOC), Angle(DQF)) -> Congruent(Arc(A, C), Arc(D, F)) // private static List <EdgeAggregator> InstantiateForwardPartOfTheorem(CongruentAngles cas) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // // Determine if the angles are central angles. // List <Circle> circles1 = Circle.IsCentralAngle(cas.ca1); //Circle circle1 = null; Circle.IsCentralAngle(cas.ca1); if (!circles1.Any()) { return(newGrounded); } List <Circle> circles2 = Circle.IsCentralAngle(cas.ca2); //Circle circle2 = null; Circle.IsCentralAngle(cas.ca2); if (!circles2.Any()) { return(newGrounded); } //Construct arc congruences between congruent circles foreach (Circle c1 in circles1) { foreach (Circle c2 in circles2) { if (c1.radius == c2.radius) { Arc a1 = Arc.GetInterceptedArc(c1, cas.ca1); Arc a2 = Arc.GetInterceptedArc(c2, cas.ca2); if (a1 != null & a2 != null) { GeometricCongruentArcs gcas = new GeometricCongruentArcs(a1, a2); // For hypergraph List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(a1); antecedent.Add(a2); antecedent.Add(cas); newGrounded.Add(new EdgeAggregator(antecedent, gcas, forwardAnnotation)); } } } } // // Construct the arc congruence by acquiring the arc endpoints. // //Point endpt11, endpt12, garbage; //circle1.FindIntersection(cas.ca1.ray1, out endpt11, out garbage); //if (endpt11 == null) return newGrounded; //circle1.FindIntersection(cas.ca1.ray2, out endpt12, out garbage); //if (endpt12 == null) return newGrounded; //Point endpt21, endpt22; //circle1.FindIntersection(cas.ca2.ray1, out endpt21, out garbage); //if (endpt21 == null) return newGrounded; //circle1.FindIntersection(cas.ca2.ray2, out endpt22, out garbage); //if (endpt22 == null) return newGrounded; //Arc arc1 = Arc.GetFigureMinorArc(circle1, endpt11, endpt12); //Arc arc2 = Arc.GetFigureMinorArc(circle2, endpt21, endpt22); //if (arc1 == null || arc2 == null) return newGrounded; return(newGrounded); }
// // In order for two triangles to be Similar, we require the following: // Triangle(A, B, C), Triangle(D, E, F), // Proportional(Segment(A, B), Segment(D, E)), // Congruent(Angle(A, B, C), Angle(D, E, F)), // Proportional(Segment(B, C), Segment(E, F)) -> Similar(Triangle(A, B, C), Triangle(D, E, F)), // Proportional(Segment(A, C), Angle(D, F)), // Congruent(Angle(C, A, B), Angle(F, D, E)), // Congruent(Angle(B, C, A), Angle(E, F, D)) // // Note: we need to figure out the proper order of the sides to guarantee similarity // public static List <EdgeAggregator> Instantiate(GroundedClause clause) { annotation.active = EngineUIBridge.JustificationSwitch.SAS_SIMILARITY; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // If this is a new segment, check for Similar triangles with this new piece of information if (clause is SegmentRatioEquation) { SegmentRatioEquation newProp = clause as SegmentRatioEquation; // Check all combinations of triangles to see if they are Similar // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { foreach (CongruentAngles cas in candidateCongruentAngles) { newGrounded.AddRange(CollectAndCheckSAS(candidateTriangles[i], candidateTriangles[j], cas, newProp)); } } } // Add this segment to the list of possible clauses to unify later candidatePropSegmentEquations.Add(newProp); } else if (clause is CongruentAngles) { CongruentAngles newCas = clause as CongruentAngles; // Check all combinations of triangles to see if they are Similar // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { foreach (SegmentRatioEquation eq in candidatePropSegmentEquations) { newGrounded.AddRange(CollectAndCheckSAS(candidateTriangles[i], candidateTriangles[j], newCas, eq)); } } } // Add this segment to the list of possible clauses to unify later candidateCongruentAngles.Add(newCas); } // If this is a new triangle, check for triangles which may be Similar to this new triangle else if (clause is Triangle) { Triangle newTriangle = clause as Triangle; foreach (Triangle oldTriangle in candidateTriangles) { foreach (CongruentAngles cas in candidateCongruentAngles) { foreach (SegmentRatioEquation eq in candidatePropSegmentEquations) { newGrounded.AddRange(CollectAndCheckSAS(newTriangle, oldTriangle, cas, eq)); } } } // Add this triangle to the list of possible clauses to unify later candidateTriangles.Add(newTriangle); } return(newGrounded); }
// // // private static List <EdgeAggregator> CollectAndCheckSAS(Triangle ct1, Triangle ct2, CongruentAngles cas, SegmentRatioEquation sre) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // Proportions must actually equate //if (!pss1.ProportionallyEquals(pss2)) return newGrounded; //// The smaller and larger segments of the proportionality must be distinct, respectively. //if (!pss1.IsDistinctFrom(pss2)) return newGrounded; // The proportional relationships need to link the given triangles if (!cas.LinksTriangles(ct1, ct2)) { return(newGrounded); } if (!sre.LinksTriangles(ct1, ct2)) { return(newGrounded); } //if (!pss1.LinksTriangles(ct1, ct2)) return newGrounded; //if (!pss2.LinksTriangles(ct1, ct2)) return newGrounded; // The smaller segments must belong to one triangle, same for larger segments. //if (!(ct1.HasSegment(pss1.smallerSegment) && ct1.HasSegment(pss2.smallerSegment) && // ct2.HasSegment(pss1.largerSegment) && ct2.HasSegment(pss2.largerSegment)) && // !(ct2.HasSegment(pss1.smallerSegment) && ct2.HasSegment(pss2.smallerSegment) && // ct1.HasSegment(pss1.largerSegment) && ct1.HasSegment(pss2.largerSegment))) // return newGrounded; KeyValuePair <Segment, Segment> segsTri1 = sre.GetSegments(ct1); KeyValuePair <Segment, Segment> segsTri2 = sre.GetSegments(ct2); //Segment seg1Tri1 = ct1.GetSegment(pss1); //Segment seg2Tri1 = ct1.GetSegment(pss2); //Segment seg1Tri2 = ct2.GetSegment(pss1); //Segment seg2Tri2 = ct2.GetSegment(pss2); // Avoid redundant segments, if they arise if (segsTri1.Key.StructurallyEquals(segsTri1.Value)) { return(newGrounded); } if (segsTri2.Key.StructurallyEquals(segsTri2.Value)) { return(newGrounded); } //if (seg1Tri1.StructurallyEquals(seg2Tri1)) return newGrounded; //if (seg1Tri2.StructurallyEquals(seg2Tri2)) return newGrounded; Angle angleTri1 = ct1.AngleBelongs(cas); Angle angleTri2 = ct2.AngleBelongs(cas); // Check both triangles if this is the included angle; if it is, we have SAS if (!angleTri1.IsIncludedAngle(segsTri1.Key, segsTri1.Value)) { return(newGrounded); } if (!angleTri2.IsIncludedAngle(segsTri2.Key, segsTri2.Value)) { return(newGrounded); } // // Generate Similar Triangles // Point vertex1 = angleTri1.GetVertex(); Point vertex2 = angleTri2.GetVertex(); // Construct a list of pairs to return; this is the correspondence from triangle 1 to triangle 2 List <KeyValuePair <Point, Point> > pairs = new List <KeyValuePair <Point, Point> >(); // The vertices of the angles correspond pairs.Add(new KeyValuePair <Point, Point>(vertex1, vertex2)); // For the segments, look at the congruences and select accordingly pairs.Add(new KeyValuePair <Point, Point>(segsTri1.Key.OtherPoint(vertex1), segsTri2.Key.OtherPoint(vertex2))); pairs.Add(new KeyValuePair <Point, Point>(segsTri1.Value.OtherPoint(vertex1), segsTri2.Value.OtherPoint(vertex2))); List <GroundedClause> simTriAntecedent = new List <GroundedClause>(); simTriAntecedent.Add(ct1); simTriAntecedent.Add(ct2); simTriAntecedent.Add(cas); simTriAntecedent.Add(sre); newGrounded.AddRange(GenerateCorrespondingParts(pairs, simTriAntecedent, annotation)); return(newGrounded); }
// // Checks for SAS given the 5 values // private static List <EdgeAggregator> InstantiateSAS(Triangle tri1, Triangle tri2, CongruentSegments css1, CongruentSegments css2, CongruentAngles cas) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // // All congruence pairs must minimally relate the triangles // if (!css1.LinksTriangles(tri1, tri2)) { return(newGrounded); } if (!css2.LinksTriangles(tri1, tri2)) { return(newGrounded); } if (!cas.LinksTriangles(tri1, tri2)) { return(newGrounded); } // Is this angle an 'extension' of the actual triangle angle? If so, acquire the normalized version of // the angle, using only the triangle vertices to represent the angle Angle angleTri1 = tri1.NormalizeAngle(tri1.AngleBelongs(cas)); Angle angleTri2 = tri2.NormalizeAngle(tri2.AngleBelongs(cas)); Segment seg1Tri1 = tri1.GetSegment(css1); Segment seg1Tri2 = tri2.GetSegment(css1); Segment seg2Tri1 = tri1.GetSegment(css2); Segment seg2Tri2 = tri2.GetSegment(css2); if (!angleTri1.IsIncludedAngle(seg1Tri1, seg2Tri1) || !angleTri2.IsIncludedAngle(seg1Tri2, seg2Tri2)) { return(newGrounded); } // // Construct the corrsesponding points between the triangles // List <Point> triangleOne = new List <Point>(); List <Point> triangleTwo = new List <Point>(); triangleOne.Add(angleTri1.GetVertex()); triangleTwo.Add(angleTri2.GetVertex()); triangleOne.Add(seg1Tri1.OtherPoint(angleTri1.GetVertex())); triangleTwo.Add(seg1Tri2.OtherPoint(angleTri2.GetVertex())); triangleOne.Add(seg2Tri1.OtherPoint(angleTri1.GetVertex())); triangleTwo.Add(seg2Tri2.OtherPoint(angleTri2.GetVertex())); // // Construct the new clauses: congruent triangles and CPCTC // GeometricCongruentTriangles gcts = new GeometricCongruentTriangles(new Triangle(triangleOne), new Triangle(triangleTwo)); // Hypergraph List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(tri1); antecedent.Add(tri2); antecedent.Add(css1); antecedent.Add(css2); antecedent.Add(cas); newGrounded.Add(new EdgeAggregator(antecedent, gcts, annotation)); // Add all the corresponding parts as new congruent clauses newGrounded.AddRange(CongruentTriangles.GenerateCPCTC(gcts, triangleOne, triangleTwo)); return(newGrounded); }
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> CheckAndGenerateSupplementaryCongruentImplyRightAngles(Supplementary supplementary, CongruentAngles conAngles) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); //The given pairs must contain the same angles (i.e., the angles must be both supplementary AND congruent) if (!((supplementary.angle1.Equals(conAngles.ca1) && supplementary.angle2.Equals(conAngles.ca2)) || (supplementary.angle2.Equals(conAngles.ca1) && supplementary.angle1.Equals(conAngles.ca2)))) { return(newGrounded); } //if (!(supplementary.StructurallyEquals(conAngles))) return newGrounded; // // Now we have two supplementary and congruent angles, which must be right angles // Strengthened streng = new Strengthened(supplementary.angle1, new RightAngle(supplementary.angle1)); Strengthened streng2 = new Strengthened(supplementary.angle2, new RightAngle(supplementary.angle2)); // Construct hyperedges List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(supplementary); antecedent.Add(conAngles); newGrounded.Add(new EdgeAggregator(antecedent, streng, annotation)); newGrounded.Add(new EdgeAggregator(antecedent, streng2, annotation)); return(newGrounded); }
// // Checks for AA given the 4 values // private static List <EdgeAggregator> InstantiateAASimilarity(Triangle tri1, Triangle tri2, CongruentAngles cas1, CongruentAngles cas2) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); // // All congruence pairs must minimally relate the triangles // if (!cas1.LinksTriangles(tri1, tri2)) { return(newGrounded); } if (!cas2.LinksTriangles(tri1, tri2)) { return(newGrounded); } // Is this angle an 'extension' of the actual triangle angle? If so, acquire the normalized version of // the angle, using only the triangle vertices to represent the angle Angle angle1Tri1 = tri1.NormalizeAngle(tri1.AngleBelongs(cas1)); Angle angle1Tri2 = tri2.NormalizeAngle(tri2.AngleBelongs(cas1)); Angle angle2Tri1 = tri1.NormalizeAngle(tri1.AngleBelongs(cas2)); Angle angle2Tri2 = tri2.NormalizeAngle(tri2.AngleBelongs(cas2)); // The angles for each triangle must be distinct if (angle1Tri1.Equals(angle2Tri1) || angle1Tri2.Equals(angle2Tri2)) { return(newGrounded); } // // Construct the corrsesponding points between the triangles // List <Point> triangleOne = new List <Point>(); List <Point> triangleTwo = new List <Point>(); triangleOne.Add(angle1Tri1.GetVertex()); triangleTwo.Add(angle1Tri2.GetVertex()); triangleOne.Add(angle2Tri1.GetVertex()); triangleTwo.Add(angle2Tri2.GetVertex()); // We know the segment endpoint mappings above, now acquire the opposite point triangleOne.Add(tri1.OtherPoint(new Segment(angle1Tri1.GetVertex(), angle2Tri1.GetVertex()))); triangleTwo.Add(tri2.OtherPoint(new Segment(angle1Tri2.GetVertex(), angle2Tri2.GetVertex()))); // // Construct the new clauses: similar triangles and resultant components // GeometricSimilarTriangles simTris = new GeometricSimilarTriangles(new Triangle(triangleOne), new Triangle(triangleTwo)); // Hypergraph edge List <GroundedClause> antecedent = new List <GroundedClause>(); antecedent.Add(tri1); antecedent.Add(tri2); antecedent.Add(cas1); antecedent.Add(cas2); newGrounded.Add(new EdgeAggregator(antecedent, simTris, annotation)); // Add all the corresponding parts as new Similar clauses newGrounded.AddRange(SimilarTriangles.GenerateComponents(simTris, triangleOne, triangleTwo)); return(newGrounded); }
public static List <EdgeAggregator> InstantiateToRightAngle(GroundedClause clause) { List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (clause is AngleEquation) { AngleEquation eq = clause as AngleEquation; //Filter for acceptable equations - both sides atomic int atomicity = eq.GetAtomicity(); if (atomicity != Equation.BOTH_ATOMIC) { return(newGrounded); } //Check that the terms equate an angle to a measure List <GroundedClause> lhs = eq.lhs.CollectTerms(); List <GroundedClause> rhs = eq.rhs.CollectTerms(); Angle angle = null; NumericValue value = null; if (lhs[0] is Angle && rhs[0] is NumericValue) { angle = lhs[0] as Angle; value = rhs[0] as NumericValue; } else if (rhs[0] is Angle && lhs[0] is NumericValue) { angle = rhs[0] as Angle; value = lhs[0] as NumericValue; } else { return(newGrounded); } //Verify that the angle is a right angle if (!Utilities.CompareValues(value.DoubleValue, 90.0)) { return(newGrounded); } Strengthened newRightAngle = new Strengthened(angle, new RightAngle(angle)); List <GroundedClause> antecedent = Utilities.MakeList <GroundedClause>(clause); newGrounded.Add(new EdgeAggregator(antecedent, newRightAngle, defAnnotation)); return(newGrounded); } else if (clause is CongruentAngles) { CongruentAngles cas = clause as CongruentAngles; // Not interested in reflexive relationships in this case if (cas.IsReflexive()) { return(newGrounded); } foreach (RightAngle ra in candidateRightAngles) { newGrounded.AddRange(InstantiateToRightAngle(ra, cas, ra)); } foreach (Strengthened streng in candidateStrengthened) { newGrounded.AddRange(InstantiateToRightAngle(streng.strengthened as RightAngle, cas, streng)); } candidateCongruentAngles.Add(clause as CongruentAngles); } else if (clause is RightAngle) { RightAngle ra = clause as RightAngle; foreach (CongruentAngles oldCas in candidateCongruentAngles) { newGrounded.AddRange(InstantiateToRightAngle(ra, oldCas, ra)); } candidateRightAngles.Add(ra); } else if (clause is Strengthened) { Strengthened streng = clause as Strengthened; // Only intrerested in right angles if (!(streng.strengthened is RightAngle)) { return(newGrounded); } foreach (CongruentAngles oldCas in candidateCongruentAngles) { newGrounded.AddRange(InstantiateToRightAngle(streng.strengthened as RightAngle, oldCas, streng)); } candidateStrengthened.Add(streng); } return(newGrounded); }
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 C // // In order for two triangles to be congruent, we require the following: // Triangle(A, B, C), Triangle(D, E, F), // Congruent(Angle(A, B, C), Angle(D, E, F)), // Congruent(Segment(B, C), Segment(E, F)), // Congruent(Angle(A, C, B), Angle(D, F, E)) -> Congruent(Triangle(A, B, C), Triangle(D, E, F)), // Congruent(Segment(A, B), Angle(D, E)), // Congruent(Segment(A, C), Angle(D, F)), // Congruent(Angle(B, A, C), Angle(E, D, F)), // public static List <EdgeAggregator> Instantiate(GroundedClause clause) { annotation.active = EngineUIBridge.JustificationSwitch.ASA; // The list of new grounded clauses if they are deduced List <EdgeAggregator> newGrounded = new List <EdgeAggregator>(); if (clause is CongruentSegments) { CongruentSegments newCss = clause as CongruentSegments; // Check all combinations of triangles to see if they are congruent // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { for (int m = 0; m < candidateAngles.Count - 1; m++) { for (int n = m + 1; n < candidateAngles.Count; n++) { newGrounded.AddRange(InstantiateASA(candidateTriangles[i], candidateTriangles[j], candidateAngles[m], candidateAngles[n], newCss)); } } } } // Add this segment to the list of possible clauses to unify later candidateSegments.Add(newCss); } else if (clause is CongruentAngles) { CongruentAngles newCas = clause as CongruentAngles; // Except for reflexive congruent triangle (a triangle and itself), reflexive angles cannot lead to congruency if (newCas.IsReflexive()) { return(newGrounded); } // Check all combinations of triangles to see if they are congruent // This congruence must include the new segment congruence for (int i = 0; i < candidateTriangles.Count - 1; i++) { for (int j = i + 1; j < candidateTriangles.Count; j++) { foreach (CongruentSegments css in candidateSegments) { foreach (CongruentAngles oldCas in candidateAngles) { newGrounded.AddRange(InstantiateASA(candidateTriangles[i], candidateTriangles[j], oldCas, newCas, css)); } } } } candidateAngles.Add(newCas); } // If this is a new triangle, check for triangles which may be congruent to this new triangle else if (clause is Triangle) { Triangle newTriangle = clause as Triangle; // Check all combinations of triangles to see if they are congruent // This congruence must include the new segment congruence foreach (Triangle oldTri in candidateTriangles) { for (int m = 0; m < candidateAngles.Count - 1; m++) { for (int n = m + 1; n < candidateAngles.Count; n++) { foreach (CongruentSegments css in candidateSegments) { newGrounded.AddRange(InstantiateASA(newTriangle, oldTri, candidateAngles[m], candidateAngles[n], css)); } } } } candidateTriangles.Add(newTriangle); } return(newGrounded); }