Create coordinate system conversion wrapper around Mirror
The Symmetry.Mirror enum was previously documented as defined in terms of the WPos system, which happens to align with CPos for Rectangular grid types. However, the existing code gets confused when attempting to support RectangularIsometric, due to a lack of appropriate conversion logic. This change makes Mirror agnostic to specific coordinate systems and introduces a WMirror wrapper that provides getters for the correct Mirror configuration given the coordinate system being used.
This commit is contained in:
committed by
Gustas Kažukauskas
parent
91ddfd6fc1
commit
00cd438190
@@ -189,7 +189,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
MersenneTwister random,
|
||||
CellLayer<int> cellLayer,
|
||||
int rotations,
|
||||
Symmetry.Mirror mirror,
|
||||
Symmetry.WMirror wmirror,
|
||||
int featureSize,
|
||||
Func<int, int> ampFunc)
|
||||
{
|
||||
@@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
size,
|
||||
rotations,
|
||||
mirror,
|
||||
wmirror.ForCPos(),
|
||||
featureSize,
|
||||
ampFunc);
|
||||
CellLayerUtils.FromMatrix(cellLayer, noise);
|
||||
|
||||
@@ -18,25 +18,66 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
{
|
||||
public static class Symmetry
|
||||
{
|
||||
/// <summary>Trivial mirroring configurations defined in world space.</summary>
|
||||
/// <summary>
|
||||
/// Trivial mirroring configurations. These are not tied to a specific coordinate system.
|
||||
/// </summary>
|
||||
public enum Mirror
|
||||
{
|
||||
/// <summary>No mirror.</summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>Match low X with high X in WPos space.</summary>
|
||||
/// <summary>Match low X with high X.</summary>
|
||||
LeftMatchesRight = 1,
|
||||
|
||||
/// <summary>Match low X, low Y with high X, high Y in WPos space.</summary>
|
||||
/// <summary>Match low X, low Y with high X, high Y.</summary>
|
||||
TopLeftMatchesBottomRight = 2,
|
||||
|
||||
/// <summary>Match low Y with high Y in WPos space.</summary>
|
||||
/// <summary>Match low Y with high Y.</summary>
|
||||
TopMatchesBottom = 3,
|
||||
|
||||
/// <summary>Match low X, high Y with high X, low Y in WPos space.</summary>
|
||||
/// <summary>Match low X, high Y with high X, low Y.</summary>
|
||||
TopRightMatchesBottomLeft = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a mirror defined in terms of WPos space and provides conversions to appropriate
|
||||
/// coordinate systems.
|
||||
/// </summary>
|
||||
public readonly struct WMirror
|
||||
{
|
||||
readonly Mirror mirror;
|
||||
readonly MapGridType gridType;
|
||||
|
||||
/// <summary>Create a WMirror.</summary>
|
||||
/// <param name="mirror">Mirror relative to WPos space.</param>
|
||||
/// <param name="gridType">Map grid type used for conversions.</param>
|
||||
public WMirror(Mirror mirror, MapGridType gridType)
|
||||
{
|
||||
this.mirror = mirror;
|
||||
this.gridType = gridType;
|
||||
}
|
||||
|
||||
public bool HasMirror => mirror != Mirror.None;
|
||||
|
||||
/// <summary>Return a Mirror relative to the WPos coordinate system.</summary>
|
||||
public Mirror ForWPos()
|
||||
{
|
||||
return mirror;
|
||||
}
|
||||
|
||||
/// <summary>Return a Mirror relative to the CPos coordinate system.</summary>
|
||||
public Mirror ForCPos()
|
||||
{
|
||||
if (mirror == Mirror.None)
|
||||
return Mirror.None;
|
||||
|
||||
if (gridType == MapGridType.RectangularIsometric)
|
||||
return (Mirror)((((int)mirror + 2) & 0b11) + 1);
|
||||
|
||||
return mirror;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParseMirror(string s, out Mirror mirror) => Enum.TryParse(s, out mirror);
|
||||
|
||||
/// <summary>
|
||||
@@ -71,10 +112,10 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
}
|
||||
}
|
||||
|
||||
public static WPos MirrorWPosAround(Mirror mirror, WPos original, WPos center)
|
||||
public static WPos MirrorWPosAround(WMirror wmirror, WPos original, WPos center)
|
||||
{
|
||||
var result = MirrorPointAround(
|
||||
mirror,
|
||||
wmirror.ForWPos(),
|
||||
new int2(original.X, original.Y),
|
||||
new int2(center.X, center.Y));
|
||||
return new WPos(result.X, result.Y, original.Z);
|
||||
@@ -91,9 +132,9 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
WPos original,
|
||||
WPos center,
|
||||
int rotations,
|
||||
Mirror mirror)
|
||||
WMirror wmirror)
|
||||
{
|
||||
var projections = new WPos[RotateAndMirrorProjectionCount(rotations, mirror)];
|
||||
var projections = new WPos[RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())];
|
||||
var projectionIndex = 0;
|
||||
|
||||
for (var rotation = 0; rotation < rotations; rotation++)
|
||||
@@ -109,8 +150,8 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
var projection = new WPos(projX, projY, original.Z);
|
||||
projections[projectionIndex++] = projection;
|
||||
|
||||
if (mirror != Mirror.None)
|
||||
projections[projectionIndex++] = MirrorWPosAround(mirror, projection, center);
|
||||
if (wmirror.HasMirror)
|
||||
projections[projectionIndex++] = MirrorWPosAround(wmirror, projection, center);
|
||||
}
|
||||
|
||||
return projections;
|
||||
@@ -120,24 +161,24 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
WPos original,
|
||||
CellLayer<T> cellLayer,
|
||||
int rotations,
|
||||
Mirror mirror)
|
||||
WMirror wmirror)
|
||||
{
|
||||
return RotateAndMirrorWPosAround(
|
||||
original,
|
||||
CellLayerUtils.Center(cellLayer),
|
||||
rotations,
|
||||
mirror);
|
||||
wmirror);
|
||||
}
|
||||
|
||||
public static CPos[] RotateAndMirrorCPos<T>(
|
||||
CPos original,
|
||||
CellLayer<T> cellLayer,
|
||||
int rotations,
|
||||
Mirror mirror)
|
||||
WMirror wmirror)
|
||||
{
|
||||
var cposProjections = new CPos[RotateAndMirrorProjectionCount(rotations, mirror)];
|
||||
var cposProjections = new CPos[RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos())];
|
||||
var wpos = CellLayerUtils.CPosToWPos(original, cellLayer.GridType);
|
||||
var wposProjections = RotateAndMirrorWPos(wpos, cellLayer, rotations, mirror);
|
||||
var wposProjections = RotateAndMirrorWPos(wpos, cellLayer, rotations, wmirror);
|
||||
for (var i = 0; i < wposProjections.Length; i++)
|
||||
cposProjections[i] = CellLayerUtils.WPosToCPos(wposProjections[i], cellLayer.GridType);
|
||||
return cposProjections;
|
||||
@@ -222,12 +263,12 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
public static ImmutableArray<ActorPlan> RotateAndMirrorActorPlans(
|
||||
IReadOnlyList<ActorPlan> originals,
|
||||
int rotations,
|
||||
Mirror mirror)
|
||||
WMirror wmirror)
|
||||
{
|
||||
var projections = new List<ActorPlan>(
|
||||
originals.Count * RotateAndMirrorProjectionCount(rotations, mirror));
|
||||
originals.Count * RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos()));
|
||||
foreach (var original in originals)
|
||||
projections.AddRange(RotateAndMirrorActorPlan(original, rotations, mirror));
|
||||
projections.AddRange(RotateAndMirrorActorPlan(original, rotations, wmirror));
|
||||
|
||||
return projections.ToImmutableArray();
|
||||
}
|
||||
@@ -239,14 +280,14 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
public static ImmutableArray<ActorPlan> RotateAndMirrorActorPlan(
|
||||
ActorPlan original,
|
||||
int rotations,
|
||||
Mirror mirror)
|
||||
WMirror wmirror)
|
||||
{
|
||||
var projections = new List<ActorPlan>(RotateAndMirrorProjectionCount(rotations, mirror));
|
||||
var projections = new List<ActorPlan>(RotateAndMirrorProjectionCount(rotations, wmirror.ForWPos()));
|
||||
var points = RotateAndMirrorWPos(
|
||||
original.WPosCenterLocation,
|
||||
original.Map.Tiles,
|
||||
rotations,
|
||||
mirror);
|
||||
wmirror);
|
||||
foreach (var point in points)
|
||||
{
|
||||
var plan = original.Clone();
|
||||
@@ -266,7 +307,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
public static void RotateAndMirrorOverCPos<T>(
|
||||
CellLayer<T> cellLayer,
|
||||
int rotations,
|
||||
Mirror mirror,
|
||||
WMirror wmirror,
|
||||
Action<CPos[], CPos> action)
|
||||
{
|
||||
var size = cellLayer.Size;
|
||||
@@ -274,7 +315,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
for (var u = 0; u < size.Width; u++)
|
||||
{
|
||||
var original = new MPos(u, v).ToCPos(cellLayer.GridType);
|
||||
var projections = RotateAndMirrorCPos(original, cellLayer, rotations, mirror);
|
||||
var projections = RotateAndMirrorCPos(original, cellLayer, rotations, wmirror);
|
||||
action(projections, original);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
public readonly Map Map;
|
||||
public readonly ModData ModData;
|
||||
public readonly List<ActorPlan> ActorPlans;
|
||||
public readonly Symmetry.Mirror Mirror;
|
||||
public readonly Symmetry.WMirror WMirror;
|
||||
public readonly int Rotations;
|
||||
|
||||
readonly ITerrainInfo terrainInfo;
|
||||
@@ -128,7 +128,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
Map = map;
|
||||
ModData = modData;
|
||||
ActorPlans = actorPlans;
|
||||
Mirror = mirror;
|
||||
WMirror = new Symmetry.WMirror(mirror, map.Grid.Type);
|
||||
Rotations = rotations;
|
||||
|
||||
terrainInfo = modData.DefaultTerrainInfo[map.Tileset];
|
||||
@@ -222,7 +222,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
Symmetry.RotateAndMirrorOverCPos(
|
||||
layer,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
(sources, destination)
|
||||
=> newLayer[destination] = sources
|
||||
.Select(source => layer.TryGetValue(source, out var value) ? value : outsideValue)
|
||||
@@ -371,7 +371,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
if (mask != null)
|
||||
zoneable = CellLayerUtils.Intersect([zoneable, mask]);
|
||||
|
||||
if (Rotations > 1 || Mirror != Symmetry.Mirror.None)
|
||||
if (Rotations > 1 || WMirror.HasMirror)
|
||||
{
|
||||
// Reserve the center of the map - otherwise it will mess with symmetries
|
||||
CellLayerUtils.OverCircle(
|
||||
@@ -411,7 +411,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
Symmetry.RotateAndMirrorOverCPos(
|
||||
projectionSpacing,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
(projections, cpos) =>
|
||||
projectionSpacing[cpos] = Symmetry.ProjectionProximity(projections) / 2);
|
||||
return projectionSpacing;
|
||||
@@ -443,7 +443,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
Symmetry.RotateAndMirrorOverCPos(
|
||||
incompatibilities,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
(sources, destination) =>
|
||||
{
|
||||
if (!dominant[destination])
|
||||
@@ -545,7 +545,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
Symmetry.RotateAndMirrorOverCPos(
|
||||
regionMask,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
TestSymmetry);
|
||||
|
||||
for (var id = 0; id < symmetryScore.Length; id++)
|
||||
@@ -726,7 +726,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
{
|
||||
CheckHasMapShapeOrNull(zoneable);
|
||||
var projections = Symmetry.RotateAndMirrorActorPlan(
|
||||
actorPlan, Rotations, Mirror);
|
||||
actorPlan, Rotations, WMirror);
|
||||
ActorPlans.AddRange(projections);
|
||||
if (zoneable != null)
|
||||
foreach (var projection in projections)
|
||||
@@ -998,7 +998,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
noise,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
noiseFeatureSize,
|
||||
wavelength => NoiseUtils.ClumpinessAmplitude(wavelength, clumpiness));
|
||||
|
||||
@@ -1021,7 +1021,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
CellLayerUtils.CellBounds(Map).Size.ToInt2(),
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror.ForCPos(),
|
||||
noiseFeatureSize,
|
||||
NoiseUtils.PinkAmplitude);
|
||||
MatrixUtils.NormalizeRangeInPlace(elevation, 1024);
|
||||
@@ -1050,7 +1050,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
pattern,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
noiseFeatureSize,
|
||||
wavelength => NoiseUtils.ClumpinessAmplitude(wavelength, clumpiness));
|
||||
{
|
||||
@@ -1764,7 +1764,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
chosenMPos.ToCPos(Map),
|
||||
space,
|
||||
Rotations,
|
||||
Mirror);
|
||||
WMirror);
|
||||
foreach (var projection in projections)
|
||||
{
|
||||
if (space.Contains(projection))
|
||||
@@ -1811,7 +1811,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
// For awkward symmetries, we try harder to make sure roads are fairer.
|
||||
// This can degrade the quantity of roads, though.
|
||||
var imperfectSymmetry =
|
||||
Mirror != Symmetry.Mirror.None ||
|
||||
WMirror.HasMirror ||
|
||||
Rotations == 3 ||
|
||||
Rotations >= 5;
|
||||
var gridType = Map.Grid.Type;
|
||||
@@ -1890,7 +1890,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
{
|
||||
var cposPath = CellLayerUtils.FromMatrixPoints([path], space)[0];
|
||||
var projectedPoints = cposPath
|
||||
.SelectMany(p => Symmetry.RotateAndMirrorCPos(p, space, Rotations, Mirror))
|
||||
.SelectMany(p => Symmetry.RotateAndMirrorCPos(p, space, Rotations, WMirror))
|
||||
.ToArray();
|
||||
var matrixPoints = CellLayerUtils.ToMatrixPoints([projectedPoints], space)[0];
|
||||
if (!matrixPoints.All(p => !nearPath.ContainsXY(p) || nearPath[p]))
|
||||
@@ -2140,7 +2140,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
|
||||
var chosenMPos = PriorityMPos(n);
|
||||
var chosenCPos = chosenMPos.ToCPos(gridType);
|
||||
foreach (var cpos in Symmetry.RotateAndMirrorCPos(chosenCPos, plan, Rotations, Mirror))
|
||||
foreach (var cpos in Symmetry.RotateAndMirrorCPos(chosenCPos, plan, Rotations, WMirror))
|
||||
if (Map.Resources.Contains(cpos))
|
||||
remaining -= AddResource(cpos);
|
||||
}
|
||||
@@ -2186,7 +2186,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
decorationNoise,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
featureSize,
|
||||
NoiseUtils.WhiteAmplitude);
|
||||
|
||||
@@ -2195,7 +2195,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
random,
|
||||
densityNoise,
|
||||
Rotations,
|
||||
Mirror,
|
||||
WMirror,
|
||||
1024,
|
||||
NoiseUtils.PinkAmplitude);
|
||||
var densityMask = CellLayerUtils.CalibratedBooleanThreshold(
|
||||
|
||||
Reference in New Issue
Block a user