Skip to content

Commit

Permalink
Merge with HexgridUtilitiesExamples - Checkpoint #5 - FOV complete
Browse files Browse the repository at this point in the history
  • Loading branch information
pgeerkens committed Apr 8, 2019
1 parent acec616 commit 180ddab
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 125 deletions.
21 changes: 8 additions & 13 deletions HexUtilities/FieldOfView/FovFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,51 @@
// 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;

namespace PGNapoleonics.HexUtilities.FieldOfView {
/// <summary>Extension methods for interface IFovBoard {IHex}.</summary>
public static class FovFactory {
/// <summary>Returns the field-of-view on <c>board</c> from the hex specified by coordinates <c>coords</c>.</summary>
[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);

/// <summary>Gets a Field-of-View for this board asynchronously, assuming a flat earth.</summary>
public static Task<IShadingMask> 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));

/// <summary>Gets a Field-of-View for this board asynchronously, assuming a flat earth.</summary>
public static Task<IShadingMask> 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));

/// <summary>Gets a Field-of-View for this board asynchronously, assuming a flat earth.</summary>
public static Task<IShadingMask> 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));

/// <summary>Gets a Field-of-View for this board asynchronously, assuming a flat earth.</summary>
public static Task<IShadingMask> 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));

/// <summary>Gets a Field-of-View for this board asynchronously.</summary>
public static Task<IShadingMask> 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));

/// <summary>Gets a Field-of-View for this board synchronously, assuming a flat earth.</summary>
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);

/// <summary>Gets a Field-of-View for this board synchronously.</summary>
public static IShadingMask GetFieldOfView(this IFovBoard @this, HexCoords origin,
int fovRadius, FovTargetMode targetMode, int heightOfMan, int hexesPerMile) {
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;
}
Expand Down
2 changes: 1 addition & 1 deletion HexUtilities/FieldOfView/IFovBoard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace PGNapoleonics.HexUtilities.FieldOfView {
/// <summary>Enumeration of line-of-sight modes</summary>
public enum FovTargetMode {
/// <summary>Target height and observer height both set to the same constant value
/// (ShadowCasting.DefaultHeight) above ground eleevation</summary>
/// (ShadowCasting.DefaultHeight) above ground elevation</summary>
EqualHeights,
/// <summary>Use actual observer height and ground level as target height.</summary>
TargetHeightEqualZero,
Expand Down
44 changes: 20 additions & 24 deletions HexUtilities/FieldOfView/RiseRun.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,36 @@ namespace PGNapoleonics.HexUtilities.FieldOfView {
/// <summary>TODO</summary>
[DebuggerDisplay("RiseRun: ({Rise} over {Run})")]
public struct RiseRun : IEquatable<RiseRun>, IComparable<RiseRun> {
#region Constructors
/// <summary>Creates a new instance of the RiseRUn struct.</summary>
/// <param name="rise"></param>
/// <param name="run"></param>
internal RiseRun(int rise, int run) : this() {
Rise = rise;
Run = run;
}
#endregion

#region Properties
/// <summary>Delta-height in units of elevation: meters.</summary>
/// <summary>Delta-height in units of elevation: feet.</summary>
public int Rise { get; }
/// <summary>Delta-width in units of distance: hexes.</summary>
public int Run { get; }
#endregion

/// <inheritdoc/>
public override string ToString() => $"Rise={Rise}; Run={Run}";
#region Operators and IComparable<RiseRun> implementations:
/// <summary>Less Than operator</summary>
public static bool operator < (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) < 0;

/// <summary>Less Than or Equals operator</summary>
public static bool operator <= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) <= 0;

/// <summary>Greater Thanoperator</summary>
public static bool operator > (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) > 0;

/// <summary>Greater Than or Equals operator</summary>
public static bool operator >= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) >= 0;

/// <summary>Less-Than comparaator.</summary>
public int CompareTo(RiseRun other) => (Rise * other.Run).CompareTo(other.Rise * Run);

#endregion

#region Value Equality with IEquatable<T>
/// <inheritdoc/>
Expand All @@ -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<RiseRun> implementations:
/// <summary>Less Than operator</summary>
public static bool operator < (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) < 0;

/// <summary>Less Than or Equals operator</summary>
public static bool operator <= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) <= 0;

/// <summary>Greater Thanoperator</summary>
public static bool operator > (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) > 0;

/// <summary>Greater Than or Equals operator</summary>
public static bool operator >= (RiseRun lhs, RiseRun rhs) => lhs.CompareTo(rhs) >= 0;

/// <summary>Less-Than comparaator.</summary>
public int CompareTo(RiseRun other) => (Rise * other.Run).CompareTo(other.Rise * Run);

#endregion
/// <inheritdoc/>
public override string ToString() => $"Rise={Rise}; Run={Run}";
}
}
31 changes: 17 additions & 14 deletions HexUtilities/FieldOfView/ShadowCastingFov.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@

namespace PGNapoleonics.HexUtilities.FieldOfView {
/// <summary>Credit: Eric Lippert</summary>
/// <a href="http://blogs.msdn.com/b/ericlippert/archive/2011/12/29/shadowcasting-in-c-part-six.aspx">Shadow Casting in C# Part Six</a>
/// <remarks>
/// It is important for realiism that observerHeight > board[observerCoords].ElevationASL,
/// or no parallax over the current ground elevation will be observed. TerrainHeight is the
/// ElevationASL of the hex, plus the height of any blocking in the hex, usually due to terrain
/// 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: <a href="http://blogs.msdn.com/b/ericlippert/archive/2011/12/29/shadowcasting-in-c-part-six.aspx">
/// Shadow Casting in C# Part Six</a>
/// </remarks>
public static partial class ShadowCasting {
/// <summary>Get or set whether to force serial execution of FOV calculation.</summary>
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -154,14 +156,14 @@ int calculationHeightUnits
Func<HexCoords,Hexside,int> heightTerrain,
Action<HexCoords> 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<Dodecant> dodecantFov = d => {
void dodecantFov(Dodecant d) {
var dodecant = new Dodecant(d,matrixOrigin);
_mapCoordsDodecant = hex => dodecant.TranslateDodecant<HexCoords>(v=>v)(hex);
_mapCoordsDodecant = hex => dodecant.TranslateDodecant<HexCoords>(v => v)(hex);

ComputeFieldOfViewInDodecantZero(
radius,
Expand All @@ -171,7 +173,7 @@ Action<HexCoords> setFieldOfView
dodecant.TranslateDodecant(heightTerrain),
dodecant.TranslateDodecant(setFieldOfView)
);
};
}
#if DEBUG
InSerial = true;
#endif
Expand Down Expand Up @@ -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)) {
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -343,15 +345,16 @@ FovCone cone
static Func<HexCoords, HexCoords> _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);

[Conditional("TRACE")]
static partial void FieldOfViewTrace(bool newline, string format, params object[] paramArgs)
=> Tracing.FieldOfView.Trace(newline, format, paramArgs);

#endregion
}
}

0 comments on commit 180ddab

Please sign in to comment.