/// <inheritdoc/> protected override IAnalyticObject Construct(IAnalyticObject[] input) { // Get the points var A = (Point)input[0]; var B = (Point)input[1]; var C = (Point)input[2]; // If the points are collinear, the construction can't be done if (AnalyticHelpers.AreCollinear(A, B, C)) { return(null); } // Otherwise construct the circumcircle return(new Circle(A, B, C)); }
/// <inheritdoc/> protected override IAnalyticObject Construct(IAnalyticObject[] input) { // Get the points var A = (Point)input[0]; var B = (Point)input[1]; var C = (Point)input[2]; // If they are collinear, don't perform the construction // (it would be possible, but it would be unnecessarily // equivalent to the perpendicular line construction) if (AnalyticHelpers.AreCollinear(A, B, C)) { return(null); } // Otherwise construct the result return(AnalyticHelpers.InternalAngleBisector(A, B, C)); }
/// <inheritdoc/> protected override IAnalyticObject Construct(IAnalyticObject[] input) { // Pull the points var A = (Point)input[0]; var B = (Point)input[1]; var C = (Point)input[2]; var D = (Point)input[3]; // Make sure A, C, D makes a circle according to the definition of the construction if (AnalyticHelpers.AreCollinear(A, C, D)) { return(null); } // Now we can create the circle var circleACD = new Circle(A, C, D); // Create the line var lineAB = new Line(A, B); // Let's intersect them and take the intersection different from the common point var intersections = circleACD.IntersectWith(lineAB).Where(intersection => intersection != A).ToArray(); // If there is no such intersection, then the line is probably tangent to this circle if (intersections.Length == 0) { return(null); } // If there are two such intersections, then the precision system has really failed... if (intersections.Length == 2) { return(null); } // Otherwise we can take the only intersection as the result return(intersections[0]); }
/// <inheritdoc/> protected override IAnalyticObject Construct(IAnalyticObject[] input) { // Pull the points var A = (Point)input[0]; var B = (Point)input[1]; var C = (Point)input[2]; var D = (Point)input[3]; var E = (Point)input[4]; // Make sure the points that should make circles are not collinear if (AnalyticHelpers.AreCollinear(A, B, C) || AnalyticHelpers.AreCollinear(A, D, E)) { return(null); } // Now we can create the circles var circleABC = new Circle(A, B, C); var circleADE = new Circle(A, D, E); // Let's intersect them and take the intersection different from the common point var intersections = circleABC.IntersectWith(circleADE).Where(intersection => intersection != A).ToArray(); // If there is no such intersection, then the circles are probably tangent if (intersections.Length == 0) { return(null); } // If there are two intersection, then the precision system has really failed... if (intersections.Length == 2) { return(null); } // Otherwise we can take the only intersection as the result return(intersections[0]); }
/// <inheritdoc/> protected override IAnalyticObject Construct(IAnalyticObject[] input) { #region Verify layout // First we need to verify that the objects match the layout switch (_construction.Configuration.LooseObjectsHolder.Layout) { // Two points should be always fine case LooseObjectLayout.LineSegment: break; // Make sure the points are not collinear case LooseObjectLayout.Triangle: // If yes, the construction shouldn't be possible if (AnalyticHelpers.AreCollinear((Point)input[0], (Point)input[1], (Point)input[2])) { return(null); } break; // Make sure no three points are collinear case LooseObjectLayout.Quadrilateral: // Get the points var point1 = (Point)input[0]; var point2 = (Point)input[1]; var point3 = (Point)input[2]; var point4 = (Point)input[3]; // Verify any three of them if (AnalyticHelpers.AreCollinear(point1, point2, point3) || AnalyticHelpers.AreCollinear(point1, point2, point4) || AnalyticHelpers.AreCollinear(point1, point3, point4) || AnalyticHelpers.AreCollinear(point2, point3, point4)) { // If some three are collinear, the construction shouldn't be possible return(null); } break; // Make sure the point doesn't lie on the line case LooseObjectLayout.LineAndPoint: // If yes, the construction shouldn't be possible if (((Line)input[0]).Contains((Point)input[1])) { return(null); } break; // Make sure neither of the points lies on the line case LooseObjectLayout.LineAndTwoPoints: // Get the line var line = (Line)input[0]; // If at least one point lies on the line, the construction // shouldn't be possible if (line.Contains((Point)input[1]) || line.Contains((Point)input[2])) { return(null); } break; // Unhandled cases default: throw new ConstructorException($"Unhandled value of {nameof(LooseObjectLayout)}: {_construction.Configuration.LooseObjectsHolder.Layout}"); } #endregion // Initialize an internal picture in which we're going to construct // the configuration that defines our composed construction var internalPicture = new Picture(); // Add the loose objects to the picture _construction.Configuration.LooseObjects.Zip(input).ForEach(pair => { // Safely try to add them internalPicture.TryAdd(pair.First, pair.Second, out var equalObject); // If there is an equal object, then we have a weird problem if (equalObject != default) { throw new ConstructorException("The input for a composed construction doesn't contain distinct objects! This must be a bug..."); } }); // Add the constructed objects as well foreach (var constructedObject in _construction.Configuration.ConstructedObjects) { // For each one find the construction function var constructorFunction = _constructionResolver.Resolve(constructedObject.Construction).Construct(constructedObject); // Perform the construction var analyticObject = constructorFunction(internalPicture); // If it's not constructible, we can't do more if (analyticObject == null) { return(null); } // Otherwise add the object to the picture internalPicture.TryAdd(constructedObject, analyticObject, out var equalObject); // If there is an equal object, we say the construction is incorrect as well if (equalObject != null) { return(null); } } // If we are here, then the construction should be fine and the result // will be in the internal picture corresponding to the last object // of the configuration that defines our composed construction return(internalPicture.Get(_construction.Configuration.LastConstructedObject)); }