/// <summary> /// Composes a ContinuousMap implementing GetValueAt by first executing the provided delegate, then returning /// GetValueAt from this map. It is the opposite of "then". It is mathematically equivalent /// to <c>this ∘ param</c>. /// /// <see cref="Then{TIn,TIntermediate,TOut}"/> for more information on the performance of this method. /// </summary> /// <param name="outer">This. Map that should receive intermediate values and return final values. Nonnull.</param> /// <param name="inner">Func to receive values from GetValue calls and pass them to this. Nonnull.</param> /// <typeparam name="TIn">Input type of parameter, and of the composed map.</typeparam> /// <typeparam name="TIntermediate">Output type of parameter and input type of this.</typeparam> /// <typeparam name="TOut">Output type of the this and of the composed map.</typeparam> /// <returns>A ContinousMap (a ComposedMap, specifically) that acts like "right, then left".</returns> public static ComposedMap <TIn, TIntermediate, TOut> Compose <TIn, TIntermediate, TOut>( this ContinuousMap <TIntermediate, TOut> outer, Func <TIn, TIntermediate> inner) { return(new ComposedMap <TIn, TIntermediate, TOut>( new FunctionBackedContinuousMap <TIn, TIntermediate>(inner), outer)); }
/// <summary> /// Constructs a ShiftedMap2D whose input is shifted by a dvec2 and stretched by another dvec2. /// </summary> /// <param name="shift"> /// The vector by which the 2D map is shifted. /// </param> /// <param name="stretch"> /// The vector by which the 2D map's coordinates are multiplied. /// </param> /// <param name="function"> /// The ContinuousMap that is shifted and stretched. /// </param> public ShiftedMap2D(dvec2 shift, dvec2 stretch, ContinuousMap <dvec2, TOut> function) { DebugUtil.AssertAllFinite(shift, nameof(shift)); DebugUtil.AssertAllFinite(stretch, nameof(stretch)); this.Shift = shift; this.Stretch = stretch; this.Function = function; }
/// <summary> /// Construct a new MoldCastMap from a curve. /// </summary> /// <param name="raycastCurve"> /// The curve from which the rays are cast. A ray is cast out of each point on the curve. This could for /// example be the center curve of a Capsule, in which case the CurveMoldCastMap returns a height map that /// ensures that the Capsule is shaped like the moldSurface. /// </param> /// <param name="moldSurface"> /// The surface that defines the mold that shapes the height map that is returned by the MoldCastMap. Rays /// that are cast are checked whether they intersect this surface. /// </param> /// <param name="defaultRadius"> /// The height map that is returned when a ray does not intersect the moldSurface. This happens when the ray /// has missed the mold surface and shoots off to infinity. When that happens, return the length of /// defaultRadius instead, so that the heightmap is still defined. /// </param> /// <param name="direction"> /// The direction along the normal of the raycastSurface from which to cast each ray. This could either be /// outwards from the surface, or in the opposite direction. /// </param> /// <param name="maxDistance"> /// The maximum ray length before a ray is considered to be out of bounds. /// </param> public MoldCastMap(Curve raycastCurve, IRaytraceableSurface moldSurface, ContinuousMap <Vector2, float> defaultRadius, RayCastDirection direction = RayCastDirection.Outwards, float maxDistance = Single.PositiveInfinity) : this(new Capsule(raycastCurve, 0.0f), moldSurface, defaultRadius, direction, maxDistance) { }
/// <summary> /// Construct a new MoldCastMap from a curve. /// </summary> /// <param name="raycastCurve"> /// The curve from which the rays are cast. A ray is cast out of each point on the curve. This could for /// example be the center curve of a Capsule, in which case the CurveMoldCastMap returns a height map that /// ensures that the Capsule is shaped like the moldSurface. /// </param> /// <param name="moldSurface"> /// The surface that defines the mold that shapes the height map that is returned by the MoldCastMap. Rays /// that are cast are checked whether they intersect this surface. /// </param> /// <param name="defaultRadius"> /// The height map that is returned when a ray does not intersect the moldSurface. This happens when the ray /// has missed the mold surface and shoots off to infinity. When that happens, return the length of /// defaultRadius instead, so that the heightmap is still defined. /// </param> /// <param name="direction"> /// The direction along the normal of the raycastSurface from which to cast each ray. This could either be /// outwards from the surface, or in the opposite direction. /// </param> /// <param name="maxDistance"> /// The maximum ray length before a ray is considered to be out of bounds. /// </param> public MoldCastMap(Curve raycastCurve, IRaytraceableSurface moldSurface, ContinuousMap <dvec2, double> defaultRadius, RayCastDirection direction = RayCastDirection.Outwards, double maxDistance = Double.PositiveInfinity) : this(new Capsule(raycastCurve, 0.0), moldSurface, defaultRadius, direction, maxDistance) { }
/// <summary> /// Construct a new MoldCastMap. /// </summary> /// <param name="raycastSurface"> /// The surface from which the rays are cast. A ray is cast out of each point on the surface in the /// direction of the surface's normal. /// </param> /// <param name="moldSurface"> /// The surface that defines the mold that shapes the height map that is returned by the MoldCastMap. Rays /// that are cast are checked whether they intersect this surface. /// </param> /// <param name="defaultRadius"> /// The height map that is returned when a ray does not intersect the moldSurface. This happens when the ray /// has missed the mold surface and shoots off to infinity. When that happens, return the length of /// defaultRadius instead, so that the heightmap is still defined. /// </param> /// <param name="direction"> /// The direction along the normal of the raycastSurface from which to cast each ray. This could either be /// outwards from the surface, or in the opposite direction. /// </param> /// <param name="maxDistance"> /// The maximum ray length before a ray is considered to be out of bounds. /// </param> public MoldCastMap(Surface raycastSurface, IRaytraceableSurface moldSurface, ContinuousMap <Vector2, float> defaultRadius, RayCastDirection direction = RayCastDirection.Outwards, float maxDistance = Single.PositiveInfinity) { this.raycastSurface = raycastSurface; this.moldSurface = moldSurface; this.defaultRadius = defaultRadius; this.direction = direction; this.maxDistance = maxDistance; }
/// <summary> /// Construct a new MoldCastMap. /// </summary> /// <param name="raycastSurface"> /// The surface from which the rays are cast. A ray is cast out of each point on the surface in the /// direction of the surface's normal. /// </param> /// <param name="moldSurface"> /// The surface that defines the mold that shapes the height map that is returned by the MoldCastMap. Rays /// that are cast are checked whether they intersect this surface. /// </param> /// <param name="defaultRadius"> /// The height map that is returned when a ray does not intersect the moldSurface. This happens when the ray /// has missed the mold surface and shoots off to infinity. When that happens, return the length of /// defaultRadius instead, so that the heightmap is still defined. /// </param> /// <param name="direction"> /// The direction along the normal of the raycastSurface from which to cast each ray. This could either be /// outwards from the surface, or in the opposite direction. /// </param> /// <param name="maxDistance"> /// The maximum ray length before a ray is considered to be out of bounds. /// </param> public MoldCastMap(Surface raycastSurface, IRaytraceableSurface moldSurface, ContinuousMap <dvec2, double> defaultRadius, RayCastDirection direction = RayCastDirection.Outwards, double maxDistance = Double.PositiveInfinity) { this._raycastSurface = raycastSurface; this._moldSurface = moldSurface; this._defaultRadius = defaultRadius; this._direction = direction; this._maxDistance = maxDistance; }
/// <summary> /// Constructs a ComposedMap feeding the left map into the right map to produce a map from left.I to right.O. /// Due to the general ugliness of ComposedMap's full type name, you probably don't want to use this directly. /// Use left.Then(right) instead. /// </summary> /// <param name="left">Map from input value to an intermediate value. Nonnull.</param> /// <param name="right">Map from intermediate value to the final value. Nonnull.</param> /// <exception cref="ArgumentException">If either argument is null.</exception> public ComposedMap(ContinuousMap <TIn, TIntermediate> left, ContinuousMap <TIntermediate, TOut> right) { if (left == null) { throw new ArgumentException("ComposedMap constructor requires nonnull arguments", "left"); } if (right == null) { throw new ArgumentException("ComposedMap constructor requires nonnull arguments", "right"); } _left = left; _right = right; }
/// <summary> /// Constructs a ShiftedMap2D whose input is shifted by a dvec2. /// </summary> /// <param name="shift"> /// The vector by which the 2D map is shifted. /// </param> /// <param name="function"> /// The ContinuousMap that is shifted and stretched. /// </param> public ShiftedMap2D(dvec2 shift, ContinuousMap <dvec2, TOut> function) : this(shift, new dvec2(1.0, 1.0), function) { }
/// <summary> /// Constructs a ContinuousMap taking 2D input values, based on a ContinuousMap that takes 1D input values. /// <example>For example: /// <code> /// // Define an arbitrary 1D function: /// ContinuousMap{float, float} lineFunction = new QuadraticFunction(1.0f, 1.0f, 1.0f); /// /// Vector2 direction = new Vector2(0.0f, 1.0f); // Let the 2D function vary along the y-axis. /// ContinuousMap{Vector2, float} planeFunction = new DomainToVector2{float}(direction, function); /// </code> /// creates a 2D function described by a 1D quadratic function along the y-axis. The x-axis of the resulting /// function is therefore constant, while the output value varies along the y-axis, as specified by /// <c>direction</c>. /// </example> /// </summary> /// <param name="direction"> /// The direction in which the 1D function is placed onto the 2D domain. The magnitude of this vector /// has an effect on the scale of the function. /// </param> public DomainToVector2(dvec2 direction, ContinuousMap <double, TOut> function) { ParameterDirection = direction; Function = function; }
/// <summary> /// Composes a ContinuousMap generated by taking the output of the provided map and feeding it into this /// map. It is the opposite of "then". It is mathematically equivalent to <c>this ∘ param</c>. /// /// <see cref="Then{TIn,TIntermediate,TOut}"/> for more information on the performance of this method. /// </summary> /// <param name="outer">This. Map that should receive intermediate values and return final values. Nonnull.</param> /// <param name="inner">Map to receive values from GetValue calls and pass them to this. Nonnull.</param> /// <typeparam name="TIn">Input type of parameter, and of the composed map.</typeparam> /// <typeparam name="TIntermediate">Output type of parameter and input type of this.</typeparam> /// <typeparam name="TOut">Output type of the this and of the composed map.</typeparam> /// <returns>A ContinousMap (a ComposedMap, specifically) that acts like "right, then left".</returns> public static ComposedMap <TIn, TIntermediate, TOut> Compose <TIn, TIntermediate, TOut>( this ContinuousMap <TIntermediate, TOut> outer, ContinuousMap <TIn, TIntermediate> inner) { return(new ComposedMap <TIn, TIntermediate, TOut>(inner, outer)); }
/// <summary> /// Composes a ContinuousMap generated by taking the output of this map and sending it to a map created /// with a GetValueAt function implemented from the provided delegate (which can be a lambda). The /// output is another ContinousMap, so a chain of maps can be described with .Then().Then().Then()... /// </summary> /// <param name="left">This. Map that should receive input values. Nonnull.</param> /// <param name="right">Function taking values from this and return values in the composed map. Nonnull.</param> /// <typeparam name="TIn">Input type of This, and of the composed map.</typeparam> /// <typeparam name="TIntermediate">Output type of This and input type of the argument.</typeparam> /// <typeparam name="TOut">Output type of the argument function and of the composed map.</typeparam> /// <returns>A ContinousMap (a ComposedMap, specifically) that acts like "left, then right".</returns> public static ComposedMap <TIn, TIntermediate, TOut> Then <TIn, TIntermediate, TOut>(this ContinuousMap <TIn, TIntermediate> left, Func <TIntermediate, TOut> right) { return(new ComposedMap <TIn, TIntermediate, TOut>(left, new FunctionBackedContinuousMap <TIntermediate, TOut>(right))); }
/// <summary> /// Composes a ContinuousMap generated by taking the output of this map and sending it to the provided map. /// The output is another ContinuousMap, so a chain of maps can be described with .Then().Then().Then()... /// /// This should be much more convenient than the ComposedMap constructor, because the parameterized types /// should be completely autodeduced, getting them out of the middle of the expression. The resulting /// ComposedMap is lightweight (it is one pointer to each map), so it's okay to use it once and throw it /// away (by using left.Then(right).GetValueAt(x) in the middle of an expression). /// </summary> /// <param name="left">This. Map that should receive input values. Nonnull.</param> /// <param name="right">Map to receive values from this and return values in the composed map. Nonnull.</param> /// <typeparam name="TIn">Input type of This, and of the composed map.</typeparam> /// <typeparam name="TIntermediate">Output type of This and input type of the argument.</typeparam> /// <typeparam name="TOut">Output type of the argument map and of the composed map.</typeparam> /// <returns>A ContinousMap (a ComposedMap, specifically) that acts like "left, then right".</returns> public static ComposedMap <TIn, TIntermediate, TOut> Then <TIn, TIntermediate, TOut>(this ContinuousMap <TIn, TIntermediate> left, ContinuousMap <TIntermediate, TOut> right) { return(new ComposedMap <TIn, TIntermediate, TOut>(left, right)); }
/// <summary> /// Constructs a ContinuousMap taking 2D input values, based on a ContinuousMap that takes 1D input values. /// <example>For example: /// <code> /// // Define an arbitrary 1D function: /// ContinuousMap<float, float> lineFunction = new QuadraticFunction(1.0f, 1.0f, 1.0f); /// /// Vector2 direction = new Vector2(0.0f, 1.0f); // Let the 2D function vary along the y-axis. /// ContinuousMap<Vector2, float> planeFunction = new DomainToVector2<float>(direction, function); /// </code> /// creates a 2D function described by a 1D quadratic function along the y-axis. The x-axis of the resulting /// function is therefore constant, while the output value varies along the y-axis, as specified by /// <c>direction</c>. /// </example> /// </summary> /// <param name="direction"> /// The direction in which the 1D function is placed onto the 2D domain. The magnitude of this vector /// has an effect on the scale of the function. /// </param> public DomainToVector2(Vector2 direction, ContinuousMap <float, TOut> function) { this.ParameterDirection = direction; this.Function = function; }
/// <summary> /// Constructs a ShiftedMap2D whose input is shifted by a Vector2 and stretched by another Vector2. /// </summary> /// <param name="shift"> /// The vector by which the 2D map is shifted. /// </param> /// <param name="stretch"> /// The vector by which the 2D map's coordinates are multiplied. /// </param> /// <param name="function"> /// The ContinuousMap that is shifted and stretched. /// </param> public ShiftedMap2D(Vector2 shift, Vector2 stretch, ContinuousMap <Vector2, TOut> function) { this.Shift = shift; this.Stretch = stretch; this.Function = function; }
/// <summary> /// Constructs a ShiftedMap2D whose input is shifted by a Vector2. /// </summary> /// <param name="shift"> /// The vector by which the 2D map is shifted. /// </param> /// <param name="function"> /// The ContinuousMap that is shifted and stretched. /// </param> public ShiftedMap2D(Vector2 shift, ContinuousMap <Vector2, TOut> function) : this(shift, new Vector2(1.0f, 1.0f), function) { }