/// <summary> /// Initializes a new instance of the <see cref="LooseObjectHolder"/> /// instance wrapping the actual loose objects and possible their layout. /// </summary> /// <param name="looseObjects">The actual loose configurations objects.</param> /// <param name="layout">The layout of these loose objects.</param> public LooseObjectHolder(IEnumerable <LooseConfigurationObject> looseObjects, LooseObjectLayout layout) { LooseObjects = looseObjects?.ToList() ?? throw new ArgumentNullException(nameof(looseObjects)); ObjectMap = new ConfigurationObjectMap(looseObjects); Layout = layout; // Make sure the objects match the layout if (!LooseObjects.Select(looseObject => looseObject.ObjectType).SequenceEqual(layout.ObjectTypes())) { throw new GeoGenException($"The loose objects don't match the specified layout {layout}."); } // Make sure they are distinct if (LooseObjects.AnyDuplicates()) { throw new GeoGenException("The loose objects are not distinct."); } }
/// <summary> /// Constructs analytic objects having a given layout. These objects are arranged randomly in a /// way that objects not too close or far from each other and the generated layouts are quite uniform, /// for example a random triangle is scalene and acute, a random quadrilateral has its angles ordered /// uniformly. This is good for finding theorems in multiple pictures, because it makes it very improbable /// that the limited imprecise floating point arithmetics will fail. /// </summary> /// <param name="layout">The layout of loose objects to be drawn.</param> /// <returns>The constructed analytic objects. Their count depends on the layout.</returns> public static IAnalyticObject[] ConstructUniformLayout(LooseObjectLayout layout) { // Switch based on the layout switch (layout) { // In line segment case everything is fixed case LooseObjectLayout.LineSegment: // Return the points in an array return(new IAnalyticObject[] { new Point(0, 0), new Point(1, 0) }); // With three points we'll create a random acute scalene triangle case LooseObjectLayout.Triangle: { // Create the points var(point1, point2, point3) = RandomLayoutsHelpers.ConstructRandomScaleneAcuteTriangle(); // Return them in an array return(new IAnalyticObject[] { point1, point2, point3 }); } // In quadrilateral case we will create a random uniform convex one case LooseObjectLayout.Quadrilateral: { // Create the points var(point1, point2, point3, point4) = RandomLayoutsHelpers.ConstructRandomUniformConvexQuadrilateral(); // Return them in an array return(new IAnalyticObject[] { point1, point2, point3, point4 }); } // In cyclic quadrilateral case we will create a random uniform one case LooseObjectLayout.CyclicQuadrilateral: { // Create the points var(point1, point2, point3, point4) = RandomLayoutsHelpers.ConstructRandomUniformCyclicQuadrilateral(); // Return them in an array return(new IAnalyticObject[] { point1, point2, point3, point4 }); } // In line and point case the line is fixed and the point is arbitrary case LooseObjectLayout.LineAndPoint: { // Create the objects var(line, point) = RandomLayoutsHelpers.ConstructLineAndRandomPointNotLyingOnIt(); // Return them in an array return(new IAnalyticObject[] { line, point }); } // In line and two points case the line is fixed and the points are arbitrary case LooseObjectLayout.LineAndTwoPoints: { // Create the objects var(line, point1, point2) = RandomLayoutsHelpers.ConstructLineAndTwoRandomPointsNotLyingOnIt(); // Return them in an array return(new IAnalyticObject[] { line, point1, point2 }); } // In right triangle case the right angle will be at the first point case LooseObjectLayout.RightTriangle: { // Create the points var(point1, point2, point3) = RandomLayoutsHelpers.ConstructRandomRightTriangle(); // Return them in an array return(new IAnalyticObject[] { point1, point2, point3 }); } // Unhandled cases default: throw new ConstructorException($"Unhandled value of {nameof(LooseObjectLayout)}: {layout}."); } }
/// <summary> /// Initializes a new instance of the <see cref="Configuration"/> class that consists of given objects. /// The loose objects will be automatically detected and will have a specified layout. /// </summary> /// <param name="layout">The layout of the loose objects./>.</param> /// <param name="objects">The objects of the configuration.</param> private Configuration(LooseObjectLayout layout, params ConfigurationObject[] objects) : this(new LooseObjectHolder(objects.OfType <LooseConfigurationObject>().ToList(), layout), objects.OfType <ConstructedConfigurationObject>().ToList()) { }
/// <summary> /// Gets the types of objects required by this layout. /// </summary> /// <param name="layout">The layout.</param> /// <returns>The list of object types.</returns> public static IReadOnlyList <ConfigurationObjectType> ObjectTypes(this LooseObjectLayout layout) => // Switch based on the layout layout switch {