/// <summary> /// Determines whether this <see cref="FarRectangle"/> contains the specified <see cref="FarPosition"/>. /// </summary> /// <param name="value"> /// The <see cref="FarPosition"/> to evaluate. /// </param> /// <param name="result"> /// On exit, is true if this <see cref="FarRectangle"/> entirely contains the specified /// <see cref="FarPosition"/>, or false if not. /// </param> public void Contains(ref FarPosition value, out bool result) { result = X <= value.X && value.X < (X + Width) && Y <= value.Y && value.Y < (Y + Height); }
/// <summary> /// Determines whether this <see cref="FarRectangle"/> contains the specified <see cref="FarPosition"/>. /// </summary> /// <param name="value"> /// The <see cref="FarPosition"/> to evaluate. /// </param> /// <returns> /// <c>true</c> if the rectangle contains the specified value; otherwise, <c>false</c>. /// </returns> public bool Contains(FarPosition value) { return(X <= value.X && value.X < (X + Width) && Y <= value.Y && value.Y < (Y + Height)); }
/// <summary>Clamps the specified value between the specified minimum and maximum.</summary> /// <param name="value">The value to clamp.</param> /// <param name="min">The minimum of the interval to clamp to.</param> /// <param name="max">The maximum of the interval to clamp to.</param> /// <returns>The clamped value.</returns> public static FarPosition Clamp(FarPosition value, FarPosition min, FarPosition max) { FarPosition result; FarValue.Clamp(ref value.X, ref min.X, ref max.X, out result.X); FarValue.Clamp(ref value.Y, ref min.Y, ref max.Y, out result.Y); return(result); }
/// <summary>Returns the component-wise maximum of the two specified values.</summary> /// <param name="value1">The first value.</param> /// <param name="value2">The second value.</param> /// <returns>The component-wise maximum.</returns> public static FarPosition Max(FarPosition value1, FarPosition value2) { FarPosition result; result.X = (value1.X > value2.X) ? value1.X : value2.X; result.Y = (value1.Y > value2.Y) ? value1.Y : value2.Y; return(result); }
/// <summary>Transforms the specified position by the specified matrix.</summary> /// <param name="position">The position to transform.</param> /// <param name="transform">The transformation to apply.</param> /// <returns>The result of the transformation.</returns> public static FarPosition Transform(FarPosition position, Matrix transform) { FarPosition result; result.X = position.X * transform.M11 + position.Y * transform.M21 + transform.M41; result.Y = position.X * transform.M12 + position.Y * transform.M22 + transform.M42; return(result); }
/// <summary> /// Performs a <see href="https://en.wikipedia.org/wiki/Smoothstep"/> /// interpolation between the specified values. /// </summary> /// <param name="value1">The value to interpolate from.</param> /// <param name="value2">The value to interpolate towards.</param> /// <param name="amount">The amount to interpolate.</param> /// <returns>The interpolated value.</returns> public static FarPosition SmoothStep(FarPosition value1, FarPosition value2, float amount) { FarPosition result; FarValue.SmoothStep(ref value1.X, ref value2.X, amount, out result.X); FarValue.SmoothStep(ref value1.Y, ref value2.Y, amount, out result.Y); return(result); }
/// <summary>Advance the sweep forward, yielding a new initial state.</summary> /// <param name="alpha">the new initial time</param> public void Advance(float alpha) { System.Diagnostics.Debug.Assert(Alpha0 < 1.0f); var beta = (alpha - Alpha0) / (1.0f - Alpha0); CenterOfMass0 = (1.0f - beta) * CenterOfMass0 + beta * CenterOfMass; Angle0 = (1.0f - beta) * Angle0 + beta * Angle; Alpha0 = alpha; }
/// <summary> /// Computes the dot product of the specified <see cref="FarPosition"/> and <see cref="Vector2"/>. /// </summary> /// <param name="value1">The first value.</param> /// <param name="value2">The second value.</param> /// <returns>The dot product.</returns> public static FarValue Dot(Vector2 value1, FarPosition value2) { return(value1.X * value2.X + value1.Y * value2.Y); // We could save two FarValue multiplications (one FarPosition multiplication), // but that would come at the cost of precision for positions primarily far // along a single axis: // ax + by //= ax + bx + by - bx //= x(a + b) + b(y - x) //= (a + b)(x + b/(a + b)(y - x)) //return (value1.X + value1.Y) * (value2.X + value1.Y / (value1.X + value1.Y) * (float)(value2.Y - value2.X)); }
/// <summary>Transforms a global coordinate to a local one.</summary> /// <param name="v">The world coordinate to apply the inverse transform to.</param> /// <returns>The result of the inverse transform (a local coordinate).</returns> public Vector2 ToLocal(WorldPoint v) { // ReSharper disable RedundantCast Necessary for FarPhysics. var px = (float)(v.X - Translation.X); var py = (float)(v.Y - Translation.Y); // ReSharper restore RedundantCast Vector2 result; result.X = Rotation.Cos * px + Rotation.Sin * py; result.Y = -Rotation.Sin * px + Rotation.Cos * py; return(result); }
/// <summary> /// Perform a line query on this index. This will return all entries in the index that are intersecting with the /// specified query line. /// </summary> /// <param name="start">The start point.</param> /// <param name="end">The end point.</param> /// <param name="t">The fraction along the line to consider.</param> /// <param name="results">The list to put the results into.</param> /// <returns></returns> public void Find(TPoint start, TPoint end, float t, ISet <T> results) { foreach (var cell in ComputeCells(IntersectionExtensions.BoundsFor(start, end, t))) { if (_cells.ContainsKey(cell.Item1)) { // Convert the query to the tree's local coordinate space. // ReSharper disable RedundantCast Necessary for FarCollections. var relativeStart = (Vector2)(start + cell.Item2); var relativeEnd = (Vector2)(end + cell.Item2); // ReSharper restore RedundantCast // And do the query. _cells[cell.Item1].Find(relativeStart, relativeEnd, t, results); } } }
/// <summary> /// Perform a circular query on this index. This will return all entries in the index that are in the specified range /// of the specified point, using the euclidean distance function (i.e. <c>sqrt(x*x+y*y)</c>). /// </summary> /// <param name="center">The query point near which to get entries.</param> /// <param name="radius">The maximum distance an entry may be away from the query point to be returned.</param> /// <param name="callback">The method to call for each found hit.</param> /// <returns></returns> /// <remarks> /// This checks for intersections of the query circle and the bounds of the entries in the index. Intersections /// (i.e. bounds not fully contained in the circle) will be returned, too. /// </remarks> public bool Find(TPoint center, float radius, SimpleQueryCallback <T> callback) { // Getting the full list and then iterating it seems to actually be faster // than injecting a delegate... /* * * // HashSet we might use for filtering duplicate results. We initialize it lazily. * HashSet<T> filter = null; * * // Compute the area bounds for that query to get the involved trees. * var queryBounds = IntersectionExtensions.BoundsFor(ref center, radius); * foreach (var cell in ComputeCells(queryBounds)) * { * // Only if the cell exists. * if (_entries.ContainsKey(cell.Item1)) * { * // Convert the query to the tree's local coordinate space. * var relativePoint = (Vector2)(center + cell.Item2); * * // And do the query. * if (!_entries[cell.Item1].Find(relativePoint, radius, * value => !Filter(value, ref filter) || callback(value))) * { * return false; * } * } * } * * /*/ ISet <T> results = new HashSet <T>(); Find(center, radius, results); foreach (var result in results) { if (!callback(result)) { return(false); } } //*/ return(true); }
/// <summary> /// Perform a circular query on this index. This will return all entries in the index that are in the specified range /// of the specified point, using the euclidean distance function (i.e. <c>sqrt(x*x+y*y)</c>). /// </summary> /// <param name="center">The query point near which to get entries.</param> /// <param name="radius">The maximum distance an entry may be away from the query point to be returned.</param> /// <param name="results"> </param> /// <remarks> /// This checks for intersections of the query circle and the bounds of the entries in the index. Intersections /// (i.e. bounds not fully contained in the circle) will be returned, too. /// </remarks> public void Find(TPoint center, float radius, ISet <T> results) { // Compute the area bounds for that query to get the involved trees. var queryBounds = IntersectionExtensions.BoundsFor(center, radius); foreach (var cell in ComputeCells(queryBounds)) { // Only if the cell exists. if (_cells.ContainsKey(cell.Item1)) { // Convert the query to the tree's local coordinate space. // ReSharper disable RedundantCast Necessary for FarCollections. var relativePoint = (Vector2)(center + cell.Item2); // ReSharper restore RedundantCast // And do the query. _cells[cell.Item1].Find(relativePoint, radius, results); } } }
/// <summary> /// Perform a line query on this index. This will return all entries in the index that are intersecting with the /// specified query line. /// <para> /// Note that the callback will be passed the fraction along the line that the hit occurred at, and may return /// the new maximum fraction up to which the search will run. If the returned fraction is exactly zero the search /// will be stopped. If the returned fraction is negative the hit will be ignored, that is the max fraction will /// not change. /// </para> /// </summary> /// <param name="start">The start of the line.</param> /// <param name="end">The end of the line.</param> /// <param name="t">The fraction along the line to consider.</param> /// <param name="callback">The method to call for each found hit.</param> /// <returns></returns> public bool Find(TPoint start, TPoint end, float t, LineQueryCallback <T> callback) { // HashSet we might use for filtering duplicate results. We initialize it lazily. HashSet <T> filter = null; foreach (var cell in ComputeCells(IntersectionExtensions.BoundsFor(start, end, t))) { if (_cells.ContainsKey(cell.Item1)) { // Convert the query to the tree's local coordinate space. // ReSharper disable RedundantCast Necessary for FarCollections. var relativeStart = (Vector2)(start + cell.Item2); var relativeEnd = (Vector2)(end + cell.Item2); // ReSharper restore RedundantCast // And do the query. if (!_cells[cell.Item1].Find( relativeStart, relativeEnd, t, (value, fraction) => { if (!Filter(value, ref filter)) { return(-1f); } return(t = callback(value, fraction)); })) { return(false); } } } return(true); }
/// <summary>Transforms the specified position by the specified matrix.</summary> /// <param name="position">The position to transform.</param> /// <param name="transform">The transformation to apply.</param> /// <param name="result">The result.</param> /// <returns>The result of the transformation.</returns> public static void Transform(ref FarPosition position, ref Matrix transform, out FarPosition result) { result.X = position.X * transform.M11 + position.Y * transform.M21 + transform.M41; result.Y = position.X * transform.M12 + position.Y * transform.M22 + transform.M42; }
/// <summary>Transforms the specified position by the specified matrix and translation.</summary> /// <param name="position">The position to transform.</param> /// <param name="transform">The transformation to apply.</param> /// <param name="result">The result of the transformation.</param> public static void Transform(ref FarPosition position, ref FarTransform transform, out FarPosition result) { var translatedPosition = position + transform.Translation; Transform(ref translatedPosition, ref transform.Matrix, out result); }
/// <summary>Transforms the specified position by the specified matrix and translation.</summary> /// <param name="position">The position to transform.</param> /// <param name="transform">The transformation to apply.</param> /// <returns>The result of the transformation.</returns> public static FarPosition Transform(FarPosition position, FarTransform transform) { return(Transform(position + transform.Translation, transform.Matrix)); }
/// <summary>Calculates the distance between two points.</summary> /// <param name="value1">The first point.</param> /// <param name="value2">The second point.</param> /// <returns>The distance between the two points.</returns> public static float Distance(FarPosition value1, FarPosition value2) { return(((Vector2)(value2 - value1)).Length()); }
/// <summary> /// Performs a <see href="https://en.wikipedia.org/wiki/Smoothstep"/> /// interpolation between the specified values. /// </summary> /// <param name="value1">The value to interpolate from.</param> /// <param name="value2">The value to interpolate towards.</param> /// <param name="amount">The amount to interpolate.</param> /// <param name="result">The interpolated value.</param> public static void SmoothStep( ref FarPosition value1, ref FarPosition value2, float amount, out FarPosition result) { FarValue.SmoothStep(ref value1.X, ref value2.X, amount, out result.X); FarValue.SmoothStep(ref value1.Y, ref value2.Y, amount, out result.Y); }
/// <summary> /// Initializes a new instance of the <see cref="FarTransform"/> struct. /// </summary> /// <param name="translation">The initial translation.</param> /// <param name="matrix">The initial matrix.</param> public FarTransform(FarPosition translation, Matrix matrix) { Translation = translation; Matrix = matrix; }
/// <summary> /// Changes the position of the <see cref="FarRectangle"/>. /// </summary> /// <param name="amount"> /// The value to adjust the position of the <see cref="FarRectangle"/> by. /// </param> public void Offset(FarPosition amount) { X += amount.X; Y += amount.Y; }
/// <summary>Writes the specified rectangle value.</summary> /// <param name="packet">The packet to write to.</param> /// <param name="data">The value to write.</param> /// <returns>This packet, for call chaining.</returns> public static IWritablePacket Write(this IWritablePacket packet, FarPosition data) { return(packet.Write(data.X).Write(data.Y)); }
/// <summary> /// Computes the dot product of the specified <see cref="FarPosition"/> and <see cref="Vector2"/>. /// </summary> /// <param name="value1">The first value.</param> /// <param name="value2">The second value.</param> /// <returns>The dot product.</returns> public static FarValue Dot(FarPosition value1, Vector2 value2) { return(Dot(value2, value1)); }
/// <summary>Returns the component-wise maximum of the two specified values.</summary> /// <param name="value1">The first value.</param> /// <param name="value2">The second value.</param> /// <param name="result">The component-wise maximum.</param> public static void Max(ref FarPosition value1, ref FarPosition value2, out FarPosition result) { result.X = (value1.X > value2.X) ? value1.X : value2.X; result.Y = (value1.Y > value2.Y) ? value1.Y : value2.Y; }
/// <summary> /// Compares two <see cref="FarPosition"/>s for equality. /// </summary> /// <param name="other"> /// The other <see cref="FarPosition"/>. /// </param> /// <returns> /// <c>true</c> if the <see cref="FarPosition"/>s are equal; otherwise, <c>false</c>. /// </returns> public bool Equals(FarPosition other) { return(X == other.X && Y == other.Y); }
/// <summary>Calculates the squared distance between two points.</summary> /// <param name="value1">The first point.</param> /// <param name="value2">The second point.</param> /// <returns>The squared distance between the two points.</returns> public static float DistanceSquared(FarPosition value1, FarPosition value2) { return(((Vector2)(value1 - value2)).LengthSquared()); }
/// <summary>Reads a far position value.</summary> /// <param name="packet">The packet to read from.</param> /// <param name="data">The read value.</param> /// <returns>This packet, for call chaining.</returns> /// <exception cref="PacketException">The packet has not enough available data for the read operation.</exception> public static IReadablePacket Read(this IReadablePacket packet, out FarPosition data) { data = packet.ReadFarPosition(); return(packet); }
/// <summary>Clamps the specified value between the specified minimum and maximum.</summary> /// <param name="value">The value to clamp.</param> /// <param name="min">The minimum of the interval to clamp to.</param> /// <param name="max">The maximum of the interval to clamp to.</param> /// <param name="result">The clamped value.</param> public static void Clamp( ref FarPosition value, ref FarPosition min, ref FarPosition max, out FarPosition result) { FarValue.Clamp(ref value.X, ref min.X, ref max.X, out result.X); FarValue.Clamp(ref value.Y, ref min.Y, ref max.Y, out result.Y); }