diff --git a/HexUtilities/FieldOfView/FovFactory.cs b/HexUtilities/FieldOfView/FovFactory.cs
index c7483db..9d878fe 100644
--- a/HexUtilities/FieldOfView/FovFactory.cs
+++ b/HexUtilities/FieldOfView/FovFactory.cs
@@ -3,7 +3,6 @@
// THis software may be used under the terms of attached file License.md (The MIT License).
///////////////////////////////////////////////////////////////////////////////////////////
#endregion
-using System;
using System.Threading.Tasks;
using PGNapoleonics.HexUtilities.Common;
@@ -11,40 +10,35 @@
namespace PGNapoleonics.HexUtilities.FieldOfView {
/// Extension methods for interface IFovBoard {IHex}.
public static class FovFactory {
- /// Returns the field-of-view on board from the hex specified by coordinates coords.
- [Obsolete("Use GetFieldOfView(HexCoords origin, int fovRadius) instead.")]
- public static IShadingMask GetFov(this IFovBoard @this, HexCoords origin, int fovRadius)
- => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0);
-
/// Gets a Field-of-View for this board asynchronously, assuming a flat earth.
public static Task GetFieldOfViewAsync(this IFovBoard @this, HexCoords origin,
int fovRadius)
- => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0));
+ => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0));
/// Gets a Field-of-View for this board asynchronously, assuming a flat earth.
public static Task GetFieldOfViewAsync(this IFovBoard @this, HexCoords origin,
int fovRadius, int height)
- => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0));
+ => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0));
/// Gets a Field-of-View for this board asynchronously, assuming a flat earth.
public static Task GetFieldOfViewAsync(this IFovBoard @this, HexCoords origin,
int fovRadius, FovTargetMode targetMode)
- => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, 1, 0));
+ => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, 1, 0));
/// Gets a Field-of-View for this board asynchronously, assuming a flat earth.
public static Task GetFieldOfViewAsync(this IFovBoard @this, HexCoords origin,
int fovRadius, FovTargetMode targetMode, int height)
- => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, height, 0));
+ => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, height, 0));
/// Gets a Field-of-View for this board asynchronously.
public static Task GetFieldOfViewAsync(this IFovBoard @this, HexCoords origin,
int fovRadius, FovTargetMode targetMode, int height, int hexesPerMile)
- => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, height, hexesPerMile));
+ => Task.Run(() => @this.GetFieldOfView(origin, fovRadius, targetMode, height, hexesPerMile));
/// Gets a Field-of-View for this board synchronously, assuming a flat earth.
public static IShadingMask GetFieldOfView(this IFovBoard @this, HexCoords origin,
int fovRadius)
- => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0);
+ => @this.GetFieldOfView(origin, fovRadius, FovTargetMode.EqualHeights, 1, 0);
/// Gets a Field-of-View for this board synchronously.
public static IShadingMask GetFieldOfView(this IFovBoard @this, HexCoords origin,
@@ -52,7 +46,8 @@ public static IShadingMask GetFieldOfView(this IFovBoard @this, HexCoords origin
Tracing.FieldOfView.Trace("GetFieldOfView");
var fov = new ArrayFieldOfView(@this);
if (@this.IsOverseeable(origin))
- ShadowCasting.ComputeFieldOfView(@this, origin, fovRadius, targetMode, coords => fov[coords] = true, heightOfMan, hexesPerMile);
+ ShadowCasting.ComputeFieldOfView(@this, origin, fovRadius, targetMode,
+ coords => fov[coords] = true, heightOfMan, hexesPerMile);
return fov;
}
diff --git a/HexUtilities/FieldOfView/IFovBoard.cs b/HexUtilities/FieldOfView/IFovBoard.cs
index ac69292..0820314 100644
--- a/HexUtilities/FieldOfView/IFovBoard.cs
+++ b/HexUtilities/FieldOfView/IFovBoard.cs
@@ -12,7 +12,7 @@ namespace PGNapoleonics.HexUtilities.FieldOfView {
/// Enumeration of line-of-sight modes
public enum FovTargetMode {
/// Target height and observer height both set to the same constant value
- /// (ShadowCasting.DefaultHeight) above ground eleevation
+ /// (ShadowCasting.DefaultHeight) above ground elevation
EqualHeights,
/// Use actual observer height and ground level as target height.
TargetHeightEqualZero,
diff --git a/HexUtilities/FieldOfView/RiseRun.cs b/HexUtilities/FieldOfView/RiseRun.cs
index 63a0485..9496744 100644
--- a/HexUtilities/FieldOfView/RiseRun.cs
+++ b/HexUtilities/FieldOfView/RiseRun.cs
@@ -33,7 +33,6 @@ namespace PGNapoleonics.HexUtilities.FieldOfView {
/// TODO
[DebuggerDisplay("RiseRun: ({Rise} over {Run})")]
public struct RiseRun : IEquatable, IComparable {
- #region Constructors
/// Creates a new instance of the RiseRUn struct.
///
///
@@ -41,17 +40,29 @@ internal RiseRun(int rise, int run) : this() {
Rise = rise;
Run = run;
}
- #endregion
- #region Properties
- /// Delta-height in units of elevation: meters.
+ /// Delta-height in units of elevation: feet.
public int Rise { get; }
/// Delta-width in units of distance: hexes.
public int Run { get; }
- #endregion
- ///
- public override string ToString() => $"Rise={Rise}; Run={Run}";
+ #region Operators and IComparable implementations:
+ /// Less Than operator
+ public static bool operator < (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) < 0;
+
+ /// Less Than or Equals operator
+ public static bool operator <= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) <= 0;
+
+ /// Greater Thanoperator
+ public static bool operator > (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) > 0;
+
+ /// Greater Than or Equals operator
+ public static bool operator >= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) >= 0;
+
+ /// Less-Than comparaator.
+ public int CompareTo(RiseRun other) => (Rise * other.Run).CompareTo(other.Rise * Run);
+
+ #endregion
#region Value Equality with IEquatable
///
@@ -71,22 +82,7 @@ public override int GetHashCode() => Run != 0 ? (Rise / Run).GetHashCode()
public static bool operator == (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) == 0;
#endregion
- #region Operators and IComparable implementations:
- /// Less Than operator
- public static bool operator < (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) < 0;
-
- /// Less Than or Equals operator
- public static bool operator <= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) <= 0;
-
- /// Greater Thanoperator
- public static bool operator > (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) > 0;
-
- /// Greater Than or Equals operator
- public static bool operator >= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) >= 0;
-
- /// Less-Than comparaator.
- public int CompareTo(RiseRun other) => (Rise * other.Run).CompareTo(other.Rise * Run);
-
- #endregion
+ ///
+ public override string ToString() => $"Rise={Rise}; Run={Run}";
}
}
diff --git a/HexUtilities/FieldOfView/ShadowCastingFov.cs b/HexUtilities/FieldOfView/ShadowCastingFov.cs
index e0d8493..c4f80d5 100644
--- a/HexUtilities/FieldOfView/ShadowCastingFov.cs
+++ b/HexUtilities/FieldOfView/ShadowCastingFov.cs
@@ -12,7 +12,6 @@
namespace PGNapoleonics.HexUtilities.FieldOfView {
/// Credit: Eric Lippert
- /// Shadow Casting in C# Part Six
///
/// It is important for realiism that observerHeight > board[observerCoords].ElevationASL,
/// or no parallax over the current ground elevation will be observed. TerrainHeight is the
@@ -20,6 +19,9 @@ namespace PGNapoleonics.HexUtilities.FieldOfView {
/// but sometimes occuppying units will block vision as well. Control this in the implementation
/// of IFovBoard {IHex} with the definition of the observerHeight, targetHeight, and
/// terrainHeight delegates.
+ ///
+ /// See:
+ /// Shadow Casting in C# Part Six
///
public static partial class ShadowCasting {
/// Get or set whether to force serial execution of FOV calculation.
@@ -129,11 +131,11 @@ int calculationHeightUnits
if (hexesPerMile == 0) {
return coords => 0;
} else if(UseMetric) {
- return ( coords => (coordsObserver.Range(coords) * coordsObserver.Range(coords))
- * calculationHeightUnits * 2 / (9 * hexesPerMile * hexesPerMile) );
+ return coords => coordsObserver.Range(coords) * coordsObserver.Range(coords)
+ * calculationHeightUnits * 2 / (9 * hexesPerMile * hexesPerMile);
} else {
- return ( coords => (coordsObserver.Range(coords) * coordsObserver.Range(coords))
- * calculationHeightUnits * 2 / (3 * hexesPerMile * hexesPerMile) );
+ return coords => coordsObserver.Range(coords) * coordsObserver.Range(coords)
+ * calculationHeightUnits * 2 / (3 * hexesPerMile * hexesPerMile);
}
}
@@ -154,14 +156,14 @@ private static void ComputeFieldOfView(
Func heightTerrain,
Action setFieldOfView
) {
- FieldOfViewTrace(true, " - Coords = " + coordsObserver.User.ToString());
+ FieldOfViewTrace(true, $" - Coords = {coordsObserver.User.ToString()}");
var matrixOrigin = new IntMatrix2D(coordsObserver.Canon);
if (radius >= 0) setFieldOfView(coordsObserver); // Always visible to self!
- Action dodecantFov = d => {
+ void dodecantFov(Dodecant d) {
var dodecant = new Dodecant(d,matrixOrigin);
- _mapCoordsDodecant = hex => dodecant.TranslateDodecant(v=>v)(hex);
+ _mapCoordsDodecant = hex => dodecant.TranslateDodecant(v => v)(hex);
ComputeFieldOfViewInDodecantZero(
radius,
@@ -171,7 +173,7 @@ Action setFieldOfView
dodecant.TranslateDodecant(heightTerrain),
dodecant.TranslateDodecant(setFieldOfView)
);
- };
+ }
#if DEBUG
InSerial = true;
#endif
@@ -258,7 +260,7 @@ FovCone cone
// track the overlap-cone between adjacent hexes as we move down.
var overlapVector = cone.VectorTop;
var hexX = XFromVector(range, topVector);
- FieldOfViewTrace(false, "DQ: ({0}) from {1}", cone, hexX);
+ FieldOfViewTrace(false, $"DQ: ({cone}) from {hexX}");
do {
while (overlapVector.GT(bottomVector)) {
@@ -278,8 +280,8 @@ FovCone cone
&& bottomVector.LE(coordsCurrent.Canon) && coordsCurrent.Canon.LE(topVector)
) {
setFieldOfView(coordsCurrent);
- FieldOfViewTrace(false," Set visible: {0} / {1}; {2} >= {3}",
- _mapCoordsDodecant(coordsCurrent), coordsCurrent.ToString(), riseRun, cone.RiseRun);
+ FieldOfViewTrace(false,
+ $" Set visible: {_mapCoordsDodecant(coordsCurrent)} / {coordsCurrent.ToString()}; {riseRun} >= {cone.RiseRun}");
}
#endregion
@@ -312,7 +314,7 @@ FovCone cone
topVector = LogAndEnqueue(enqueue, range, topVector, bottomVector, topRiseRun, 4);
break;
}
- FieldOfViewTrace(false, "DQ: ({0}) from {1}", cone, hexX);
+ FieldOfViewTrace(false, $"DQ: ({cone}) from {hexX}");
}
#endregion
@@ -343,7 +345,9 @@ FovCone cone
static Func _mapCoordsDodecant;
static partial void FieldOfViewTrace(string format, params object[] paramArgs);
+
static partial void FieldOfViewTrace(bool newline, string format, params object[] paramArgs);
+
[Conditional("TRACE")]
static partial void FieldOfViewTrace(string format, params object[] paramArgs)
=> Tracing.FieldOfView.Trace(format, paramArgs);
@@ -351,7 +355,6 @@ static partial void FieldOfViewTrace(string format, params object[] paramArgs)
[Conditional("TRACE")]
static partial void FieldOfViewTrace(bool newline, string format, params object[] paramArgs)
=> Tracing.FieldOfView.Trace(newline, format, paramArgs);
-
#endregion
}
}
diff --git a/HexUtilities/FieldOfView/ShadowCastingFov_Utilities.cs b/HexUtilities/FieldOfView/ShadowCastingFov_Utilities.cs
index d6492af..29d2a30 100644
--- a/HexUtilities/FieldOfView/ShadowCastingFov_Utilities.cs
+++ b/HexUtilities/FieldOfView/ShadowCastingFov_Utilities.cs
@@ -1,83 +1,61 @@
-#region The MIT License - Copyright (C) 2012-2019 Pieter Geerkens
-/////////////////////////////////////////////////////////////////////////////////////////
-// PG Software Solutions - Hex-Grid Utilities
-/////////////////////////////////////////////////////////////////////////////////////////
-// The MIT License:
-// ----------------
-//
-// Copyright (c) 2012-2019 Pieter Geerkens (email: pgeerkens@users.noreply.github.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this
-// software and associated documentation files (the "Software"), to deal in the Software
-// without restriction, including without limitation the rights to use, copy, modify,
-// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to the following
-// conditions:
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-/////////////////////////////////////////////////////////////////////////////////////////
+#region Copyright (c) 2012-2019 Pieter Geerkens (email: pgeerkens@users.noreply.github.com)
+///////////////////////////////////////////////////////////////////////////////////////////
+// THis software may be used under the terms of attached file License.md (The MIT License).
+///////////////////////////////////////////////////////////////////////////////////////////
#endregion
using System;
using System.Diagnostics.CodeAnalysis;
namespace PGNapoleonics.HexUtilities.FieldOfView {
- public static partial class ShadowCasting {
- [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "code")]
- static IntVector2D LogAndEnqueue(Action enqueue, int range, IntVector2D top,
- IntVector2D bottom, RiseRun riseRun, int code
- ) {
- if( top.GT(bottom)) {
- var cone = new FovCone(range+1, top, bottom, riseRun);
- FieldOfViewTrace(false, " EQ: ({0}) code: {1}", cone, code);
- enqueue(cone);
- return bottom;
- } else {
- return top;
- }
- }
+ public static partial class ShadowCasting {
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "code")]
+ static IntVector2D LogAndEnqueue(Action enqueue, int range, IntVector2D top,
+ IntVector2D bottom, RiseRun riseRun, int code
+ ) {
+ if( top.GT(bottom)) {
+ var cone = new FovCone(range+1, top, bottom, riseRun);
+ FieldOfViewTrace(false, " EQ: ({0}) code: {1}", cone, code);
+ enqueue(cone);
+ return bottom;
+ } else {
+ return top;
+ }
+ }
- static int XFromVector(int y, IntVector2D v) {
- return (-2 * v.Y + v.X * (3 * y + 1) + (3 * v.Y) - 1) / (3 * v.Y);
- }
- /// Helper IntMatrix2D for VectorHexTop.
- static IntMatrix2D matrixHexTop = new IntMatrix2D(3,0, 0,3, 2, 1);
- /// Helper IntMatrix2D for VectorHexBottom.
- static IntMatrix2D matrixHexBottom = new IntMatrix2D(3,0, 0,3, -2,-1);
+ static int XFromVector(int y,IntVector2D v) => (-2 * v.Y + v.X * (3 * y + 1) + (3 * v.Y) - 1) / (3 * v.Y);
+
+ /// Helper IntMatrix2D for VectorHexTop.
+ static IntMatrix2D matrixHexTop = new IntMatrix2D(3,0, 0,3, 2, 1);
+
+ /// Helper IntMatrix2D for VectorHexBottom.
+ static IntMatrix2D matrixHexBottom = new IntMatrix2D(3,0, 0,3, -2,-1);
+
+ /// IntVector2D for top corner of cell Canon(i,j).
+ ///
+ /// In first dodecant; The top corner for hex (i,j) is determined
+ /// (from close visual inspection) as:
+ /// (i,j) + 1/3 * (2,1)
+ /// which reduces to:
+ /// (i + 2/3, j + 1/3) == 1/3 * (3x + 2, 3y + 1)
+ ///
+ static IntVector2D VectorHexTop(HexCoords hex) => hex.Canon * matrixHexTop;
+
+ /// IntVector2D for bottom corner of cell Canon(i,j).
+ ///
+ /// In first dodecant; The bottom corner for hex (i,j) is determined
+ /// (from close visual inspection) as:
+ /// (i,j) + 1/3 * (-2,-1)
+ /// which reduces to:
+ /// (i - 2/3, j - 1/3) == 1/3 * (3x - 2, 3y - 1)
+ ///
+ static IntVector2D VectorHexBottom(HexCoords hex) => hex.Canon * matrixHexBottom;
+
+ #region These are here (instead of IntVector2D.cs) because they are "upside-down" for regular use.
+ static IntVector2D VectorMax(IntVector2D lhs,IntVector2D rhs) => lhs.GT(rhs) ? lhs : rhs;
- /// IntVector2D for top corner of cell Canon(i,j).
- ///
- /// In first dodecant; The top corner for hex (i,j) is determined
- /// (from close visual inspection) as:
- /// (i,j) + 1/3 * (2,1)
- /// which reduces to:
- /// (i + 2/3, j + 1/3) == 1/3 * (3x + 2, 3y + 1)
- ///
- static IntVector2D VectorHexTop(HexCoords hex) { return hex.Canon * matrixHexTop; }
- /// IntVector2D for bottom corner of cell Canon(i,j).
- ///
- /// In first dodecant; The bottom corner for hex (i,j) is determined
- /// (from close visual inspection) as:
- /// (i,j) + 1/3 * (-2,-1)
- /// which reduces to:
- /// (i - 2/3, j - 1/3) == 1/3 * (3x - 2, 3y - 1)
- ///
- static IntVector2D VectorHexBottom(HexCoords hex) { return hex.Canon * matrixHexBottom; }
+ static bool GT(this IntVector2D lhs,IntVector2D rhs) => lhs.X*rhs.Y > lhs.Y*rhs.X;
- #region These are here (instead of IntVector2D.cs) because they are "upside-down" for regular use.
- static IntVector2D VectorMax(IntVector2D lhs, IntVector2D rhs) {
- return lhs.GT(rhs) ? lhs : rhs;
+ static bool LE(this IntVector2D lhs,IntVector2D rhs) => !lhs.GT(rhs);
+ #endregion
}
- static bool GT(this IntVector2D lhs, IntVector2D rhs) { return lhs.X*rhs.Y > lhs.Y*rhs.X; }
- static bool LE(this IntVector2D lhs, IntVector2D rhs) { return ! lhs.GT(rhs); }
- #endregion
- }
}