internal static FaceDir RotateBy(this FaceDir faceDir, Rotation r) { var f = faceDir.Forward(); var x1 = (int)f.x; var z1 = (int)f.z; var(x2, z2) = TopoArrayUtils.SquareRotateVector(x1, z1, r); if (x1 == x2 && z1 == z2) { return(faceDir); } if (x2 == 1) { return(FaceDir.Right); } if (x2 == -1) { return(FaceDir.Left); } if (z2 == 1) { return(FaceDir.Forward); } if (z2 == -1) { return(FaceDir.Back); } throw new System.Exception(); }
public static IEnumerable <ITopoArray <Tile> > GetRotatedSamples( ITopoArray <Tile> sample, int rotationalSymmetry, bool reflectionalSymmetry, TileRotation tileRotation = null) { if (sample.Topology.Directions.Type == DirectionsType.Hexagonal2d) { var reflections = reflectionalSymmetry ? 2 : 1; for (var r = 0; r < reflections; r++) { for (var i = 0; i < 6; i += (6 / rotationalSymmetry)) { yield return(TopoArrayUtils.HexRotate(sample, i, r > 0, tileRotation)); } } } else { var reflections = reflectionalSymmetry ? 2 : 1; for (var r = 0; r < reflections; r++) { for (var i = 0; i < 4; i += (4 / rotationalSymmetry)) { yield return(TopoArrayUtils.Rotate(sample, i, r > 0, tileRotation)); } } } }
public void Init(TilePropagator propagator) { pathTileSet = propagator.CreateTileSet(Exits.Keys); endPointTileSet = EndPointTiles != null?propagator.CreateTileSet(EndPointTiles) : null; graph = CreateEdgedGraph(propagator.Topology); var tileRotation = TileRotation ?? new TileRotation(); actualExits = new Dictionary <Tile, ISet <Direction> >(); foreach (var kv in Exits) { foreach (var rot in tileRotation.RotationGroup) { if (tileRotation.Rotate(kv.Key, rot, out var rtile)) { Direction Rotate(Direction d) { return(TopoArrayUtils.RotateDirection(propagator.Topology.Directions, d, rot)); } var rexits = new HashSet <Direction>(kv.Value.Select(Rotate)); actualExits[rtile] = rexits; } } } tilesByExit = actualExits .SelectMany(kv => kv.Value.Select(e => Tuple.Create(kv.Key, e))) .GroupBy(x => x.Item2, x => x.Item1) .ToDictionary(g => g.Key, propagator.CreateTileSet); }
public static AdjacentModel.Adjacency Rotate(AdjacentModel.Adjacency adjacency, Rotation rotation, DirectionSet directions, TileRotation tileRotation) { return(new AdjacentModel.Adjacency { Src = tileRotation.Rotate(adjacency.Src, rotation).ToArray(), Dest = tileRotation.Rotate(adjacency.Dest, rotation).ToArray(), Direction = TopoArrayUtils.RotateDirection(directions, adjacency.Direction, rotation), }); }
public static IEnumerable<ITopoArray<Tile>> GetRotatedSamples( ITopoArray<Tile> sample, TileRotation tileRotation = null) { tileRotation = tileRotation ?? new TileRotation(); foreach (var rotation in tileRotation.RotationGroup) { yield return TopoArrayUtils.Rotate(sample, rotation, tileRotation); } }
public void Init(TilePropagator propagator) { ISet <Tile> actualEndPointTiles; if (TileRotation != null) { actualExits = new Dictionary <Tile, ISet <Direction> >(); foreach (var kv in Exits) { foreach (var rot in TileRotation.RotationGroup) { if (TileRotation.Rotate(kv.Key, rot, out var rtile)) { Direction Rotate(Direction d) { return(TopoArrayUtils.RotateDirection(propagator.Topology.AsGridTopology().Directions, d, rot)); } var rexits = new HashSet <Direction>(kv.Value.Select(Rotate)); actualExits[rtile] = rexits; } } } actualEndPointTiles = EndPointTiles == null ? null : new HashSet <Tile>(TileRotation.RotateAll(EndPointTiles)); } else { actualExits = Exits; actualEndPointTiles = EndPointTiles; } pathTileSet = propagator.CreateTileSet(Exits.Keys); pathSelectedTracker = propagator.CreateSelectedTracker(pathTileSet); endPointTileSet = EndPointTiles != null?propagator.CreateTileSet(actualEndPointTiles) : null; endPointSelectedTracker = EndPointTiles != null?propagator.CreateSelectedTracker(endPointTileSet) : null; graph = CreateEdgedGraph(propagator.Topology); tilesByExit = actualExits .SelectMany(kv => kv.Value.Select(e => Tuple.Create(kv.Key, e))) .GroupBy(x => x.Item2, x => x.Item1) .ToDictionary(g => g.Key, propagator.CreateTileSet); trackerByExit = tilesByExit .ToDictionary(kv => kv.Key, kv => propagator.CreateSelectedTracker(kv.Value)); Check(propagator, true); }
/// <summary> /// Declares that the tiles in dest can be placed adjacent to the tiles in src, in the direction specified by (x, y, z). /// Then it adds similar declarations for other rotations and reflections, as specified by rotations. /// </summary> public void AddAdjacency(IList <Tile> src, IList <Tile> dest, int x, int y, int z, TileRotation tileRotation = null) { RequireDirections(); tileRotation = tileRotation ?? new TileRotation(); foreach (var rotation in tileRotation.RotationGroup) { var(x2, y2) = TopoArrayUtils.RotateVector(directions.Type, x, y, rotation); AddAdjacency( tileRotation.Rotate(src, rotation).ToList(), tileRotation.Rotate(dest, rotation).ToList(), x2, y2, z); } }
public static IEnumerable <ITopoArray <Tile> > GetRotatedSamples( ITopoArray <Tile> sample, TileRotation tileRotation = null) { tileRotation = tileRotation ?? new TileRotation(); foreach (var rotation in tileRotation.RotationGroup) { if (sample.Topology.Directions.Type == DirectionsType.Hexagonal2d) { yield return(TopoArrayUtils.HexRotate(sample, rotation, tileRotation)); } else { yield return(TopoArrayUtils.Rotate(sample, rotation, tileRotation)); } } }
private static ITopoArray <V> GetSubTile <V>(Tile tile, IDictionary <Tile, ITopoArray <V> > subTiles) { if (subTiles.TryGetValue(tile, out var result)) { return(result); } if (tile.Value is RotatedTile rt) { if (!subTiles.TryGetValue(rt.Tile, out var subTile)) { return(null); } result = TopoArrayUtils.Rotate(subTile, rt.Rotation); return(subTiles[tile] = result); } return(null); }
/// <summary> /// Declares that the tiles in dest can be placed adjacent to the tiles in src, in the direction specified by (x, y, z). /// Then it adds similar declarations for other rotations and reflections, as specified by rotations. /// </summary> public void AddAdjacency(IList <Tile> src, IList <Tile> dest, int x, int y, int z, TileRotation tileRotation = null) { tileRotation = tileRotation ?? new TileRotation(); foreach (var rotation in tileRotation.RotationGroup) { int x2, y2; if (directions.Type == DirectionsType.Hexagonal2d) { (x2, y2) = TopoArrayUtils.HexRotateVector(x, y, rotation); } else { (x2, y2) = TopoArrayUtils.RotateVector(x, y, rotation); } AddAdjacency( tileRotation.Rotate(src, rotation).ToList(), tileRotation.Rotate(dest, rotation).ToList(), x2, y2, z); } }
/// <summary> /// Declares that the tiles in dest can be placed adjacent to the tiles in src, in the direction specified by (x, y, z). /// Then it adds similar declarations for other rotations and reflections, as specified by rotations. /// </summary> public void AddAdjacency(IList <Tile> src, IList <Tile> dest, int x, int y, int z, int rotationalSymmetry, bool reflectionalSymmetry, TileRotation rotations = null) { rotations = rotations ?? new TileRotation(); int totalRotationalSymmetry; if (directions.Type == DirectionsType.Hexagonal2d) { totalRotationalSymmetry = 6; } else { totalRotationalSymmetry = 4; } int reflections = reflectionalSymmetry ? 2 : 1; for (var r = 0; r < reflections; r++) { var reflectX = r > 0 ? true : false; for (var rotateCw = 0; rotateCw < totalRotationalSymmetry; rotateCw += (totalRotationalSymmetry / rotationalSymmetry)) { int x2, y2; if (directions.Type == DirectionsType.Hexagonal2d) { (x2, y2) = TopoArrayUtils.HexRotateVector(x, y, rotateCw, reflectX); } else { (x2, y2) = TopoArrayUtils.RotateVector(x, y, rotateCw, reflectX); } AddAdjacency( rotations.Rotate(src, rotateCw, reflectX).ToList(), rotations.Rotate(dest, rotateCw, reflectX).ToList(), x2, y2, z); } } }
public void TestHexRotate() { var a = new int[2, 2]; a[0, 0] = 1; a[1, 0] = 2; a[0, 1] = 3; a[1, 1] = 4; var ta = TopoArray.Create(a, new Topology(DirectionSet.Hexagonal2d, 2, 2, false, false)); var r5 = TopoArrayUtils.HexRotate(ta, new Rotation(5 * 60, false)); Assert.AreEqual(2, r5.Get(0, 0)); Assert.AreEqual(1, r5.Get(0, 1)); Assert.AreEqual(4, r5.Get(1, 1)); Assert.AreEqual(3, r5.Get(1, 2)); var r1 = TopoArrayUtils.HexRotate(ta, new Rotation(1 * 60, false)); Assert.AreEqual(3, r1.Get(0, 0)); Assert.AreEqual(1, r1.Get(1, 0)); Assert.AreEqual(4, r1.Get(1, 1)); Assert.AreEqual(2, r1.Get(2, 1)); var r2 = TopoArrayUtils.HexRotate(ta, new Rotation(2 * 60, false)); Assert.AreEqual(3, r2.Get(0, 0)); Assert.AreEqual(4, r2.Get(0, 1)); Assert.AreEqual(1, r2.Get(1, 1)); Assert.AreEqual(2, r2.Get(1, 2)); var r3 = TopoArrayUtils.HexRotate(ta, new Rotation(3 * 60, false)); Assert.AreEqual(4, r3.Get(0, 0)); Assert.AreEqual(3, r3.Get(1, 0)); Assert.AreEqual(2, r3.Get(0, 1)); Assert.AreEqual(1, r3.Get(1, 1)); var refl = TopoArrayUtils.HexRotate(ta, new Rotation(0 * 60, true)); Assert.AreEqual(2, refl.Get(0, 0)); Assert.AreEqual(1, refl.Get(1, 0)); Assert.AreEqual(4, refl.Get(1, 1)); Assert.AreEqual(3, refl.Get(2, 1)); }
public void TestRotate() { var a = new int[2, 2]; a[0, 0] = 1; a[1, 0] = 2; a[0, 1] = 3; a[1, 1] = 4; var ta = TopoArray.Create(a, new Topology(2, 2, false)); var r1 = TopoArrayUtils.Rotate(ta, new Rotation(3 * 90)); Assert.AreEqual(2, r1.Get(0, 0)); Assert.AreEqual(4, r1.Get(1, 0)); Assert.AreEqual(1, r1.Get(0, 1)); Assert.AreEqual(3, r1.Get(1, 1)); var r3 = TopoArrayUtils.Rotate(ta, new Rotation(1 * 90)); Assert.AreEqual(3, r3.Get(0, 0)); Assert.AreEqual(1, r3.Get(1, 0)); Assert.AreEqual(4, r3.Get(0, 1)); Assert.AreEqual(2, r3.Get(1, 1)); var refl = TopoArrayUtils.Rotate(ta, new Rotation(0 * 90, true)); Assert.AreEqual(2, refl.Get(0, 0)); Assert.AreEqual(1, refl.Get(1, 0)); Assert.AreEqual(4, refl.Get(0, 1)); Assert.AreEqual(3, refl.Get(1, 1)); }
private static IList <AdjacentModel.Adjacency> GetAutoAdjacencies <T>( IDictionary <Tile, ITopoArray <T> > subTiles, GridTopology subTileTopology, TileRotation tileRotations, Func <T, T, double> diff, double tolerance) { // Pre-process for rotations var allSubTiles = subTiles; if (subTileTopology.Width == subTileTopology.Height) { allSubTiles = new Dictionary <Tile, ITopoArray <T> >(); foreach (var kv in subTiles) { foreach (var rot in tileRotations.RotationGroup) { if (tileRotations.Rotate(kv.Key, rot, out var rt) && !allSubTiles.ContainsKey(rt)) { allSubTiles[rt] = TopoArrayUtils.Rotate(kv.Value, rot); } } } } var output = new List <AdjacentModel.Adjacency>(); // Left-right { var leftSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceX(x.Value, 0)); var rightSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceX(x.Value, subTileTopology.Width - 1)); foreach (var kv1 in leftSlices) { foreach (var kv2 in rightSlices) { if (DiffSlice(kv1.Value, kv2.Value, diff) <= tolerance) { output.Add(new AdjacentModel.Adjacency { Src = new[] { kv2.Key }, Dest = new[] { kv1.Key }, Direction = Direction.XPlus }); } } } } // { var upSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceY(x.Value, 0)); var downSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceY(x.Value, subTileTopology.Height - 1)); foreach (var kv1 in upSlices) { foreach (var kv2 in downSlices) { if (DiffSlice(kv1.Value, kv2.Value, diff) <= tolerance) { output.Add(new AdjacentModel.Adjacency { Src = new[] { kv2.Key }, Dest = new[] { kv1.Key }, Direction = Direction.YPlus }); } } } } // if (subTileTopology.Directions.Type == DirectionSetType.Cartesian3d) { var aboveSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceZ(x.Value, 0)); var belowSlices = allSubTiles.ToDictionary(x => x.Key, x => SliceZ(x.Value, subTileTopology.Depth - 1)); foreach (var kv1 in aboveSlices) { foreach (var kv2 in belowSlices) { if (DiffSlice(kv1.Value, kv2.Value, diff) <= tolerance) { output.Add(new AdjacentModel.Adjacency { Src = new[] { kv2.Key }, Dest = new[] { kv1.Key }, Direction = Direction.ZPlus }); } } } } return(output); }
public EdgedPathView(EdgedPathSpec spec, TilePropagator propagator) { if (spec.TileRotation != null) { exits = new Dictionary <Tile, ISet <Direction> >(); foreach (var kv in spec.Exits) { foreach (var rot in spec.TileRotation.RotationGroup) { if (spec.TileRotation.Rotate(kv.Key, rot, out var rtile)) { Direction Rotate(Direction d) { return(TopoArrayUtils.RotateDirection(propagator.Topology.AsGridTopology().Directions, d, rot)); } var rexits = new HashSet <Direction>(kv.Value.Select(Rotate)); exits[rtile] = rexits; } } } endPointTiles = spec.RelevantTiles == null ? null : new HashSet <Tile>(spec.TileRotation.RotateAll(spec.RelevantTiles)); } else { exits = spec.Exits; endPointTiles = spec.RelevantTiles; } pathTileSet = propagator.CreateTileSet(exits.Keys); pathSelectedTracker = propagator.CreateSelectedTracker(pathTileSet); Graph = CreateEdgedGraph(propagator.Topology); this.propagator = propagator; this.topology = propagator.Topology; var nodesPerIndex = GetNodesPerIndex(); CouldBePath = new bool[propagator.Topology.IndexCount * nodesPerIndex]; MustBePath = new bool[propagator.Topology.IndexCount * nodesPerIndex]; tileSetByExit = exits .SelectMany(kv => kv.Value.Select(e => Tuple.Create(kv.Key, e))) .GroupBy(x => x.Item2, x => x.Item1) .ToDictionary(g => g.Key, propagator.CreateTileSet); trackerByExit = tileSetByExit .ToDictionary(kv => kv.Key, kv => propagator.CreateSelectedTracker(kv.Value)); hasEndPoints = spec.RelevantCells != null || spec.RelevantTiles != null; if (hasEndPoints) { CouldBeRelevant = new bool[propagator.Topology.IndexCount * nodesPerIndex]; MustBeRelevant = new bool[propagator.Topology.IndexCount * nodesPerIndex]; endPointIndices = spec.RelevantCells == null ? null : spec.RelevantCells.Select(p => propagator.Topology.GetIndex(p.X, p.Y, p.Z)).ToList(); endPointTileSet = endPointTiles != null?propagator.CreateTileSet(endPointTiles) : null; endPointSelectedTracker = endPointTiles != null?propagator.CreateSelectedTracker(endPointTileSet) : null; } else { CouldBeRelevant = CouldBePath; MustBeRelevant = MustBePath; endPointTileSet = pathTileSet; } }
/// <summary> /// Rotates v about the y-axis by r. /// </summary> internal static Vector3Int Rotate(Rotation r, Vector3Int v) { (v.x, v.z) = TopoArrayUtils.SquareRotateVector(v.x, v.z, r); return(v); }