Skip to content

Commit

Permalink
Extend room rotations with 4 more transformations. It is now possible…
Browse files Browse the repository at this point in the history
… to choose exactly which transformations can be applied to a given room shape.
  • Loading branch information
OndrejNepozitek committed Dec 30, 2018
1 parent 764a498 commit 8c9c5be
Show file tree
Hide file tree
Showing 20 changed files with 621 additions and 71 deletions.
24 changes: 24 additions & 0 deletions GeneralAlgorithms.Tests/DataStructures/Common/IntVector2Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace GeneralAlgorithms.Tests.DataStructures.Common
{
using GeneralAlgorithms.DataStructures.Common;
using NUnit.Framework;

[TestFixture]
public class IntVector2Tests
{
[Test]
public void Transform_CorrectlyTransforms()
{
var point = new IntVector2(1, 2);

Assert.That(point.Transform(Transformation.Identity), Is.EqualTo(new IntVector2(1, 2)));
Assert.That(point.Transform(Transformation.Rotate90), Is.EqualTo(new IntVector2(2, -1)));
Assert.That(point.Transform(Transformation.Rotate180), Is.EqualTo(new IntVector2(-1, -2)));
Assert.That(point.Transform(Transformation.Rotate270), Is.EqualTo(new IntVector2(-2, 1)));
Assert.That(point.Transform(Transformation.MirrorX), Is.EqualTo(new IntVector2(1, -2)));
Assert.That(point.Transform(Transformation.MirrorY), Is.EqualTo(new IntVector2(-1, 2)));
Assert.That(point.Transform(Transformation.Diagonal13), Is.EqualTo(new IntVector2(2, 1)));
Assert.That(point.Transform(Transformation.Diagonal24), Is.EqualTo(new IntVector2(-2, -1)));
}
}
}
107 changes: 107 additions & 0 deletions GeneralAlgorithms.Tests/DataStructures/Polygons/GridPolygonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,5 +253,112 @@ public void Constructor_CounterClockwise_Throws()
Assert.Throws<ArgumentException>(() => p.Build());
}
}

[Test]
public void Transform_ReturnsTransformed()
{
var polygon = GridPolygon.GetRectangle(2, 1);

{
var transformed = polygon.Transform(Transformation.Identity);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(0, 1),
new IntVector2(2, 1),
new IntVector2(2, 0)
}));
}

{
var transformed = polygon.Transform(Transformation.Rotate90);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(1, 0),
new IntVector2(1, -2),
new IntVector2(0, -2)
}));
}

{
var transformed = polygon.Transform(Transformation.Rotate180);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(0, -1),
new IntVector2(-2, -1),
new IntVector2(-2, 0)
}));
}

{
var transformed = polygon.Transform(Transformation.Rotate270);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(-1, 0),
new IntVector2(-1, 2),
new IntVector2(0, 2)
}));
}

{
var transformed = polygon.Transform(Transformation.MirrorX);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(2, 0),
new IntVector2(2, -1),
new IntVector2(0, -1)
}));
}

{
var transformed = polygon.Transform(Transformation.MirrorY);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(-2, 0),
new IntVector2(-2, 1),
new IntVector2(0, 1)
}));
}

{
var transformed = polygon.Transform(Transformation.Diagonal13);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(0, 2),
new IntVector2(1, 2),
new IntVector2(1, 0)
}));
}

{
var transformed = polygon.Transform(Transformation.Diagonal24);
Assert.That(transformed.GetPoints(), Is.EquivalentTo(new List<IntVector2>()
{
new IntVector2(0, 0),
new IntVector2(0, -2),
new IntVector2(-1, -2),
new IntVector2(-1, 0)
}));
}
}

[Test]
public void GetAllTransformations_ReturnsCorrectCount()
{
var square = GridPolygon.GetSquare(1);
var rectangle = GridPolygon.GetRectangle(1, 2);

var transformedSquares = square.GetAllTransformations();
var transformedRectangles = rectangle.GetAllTransformations();

Assert.That(transformedSquares.Count(), Is.EqualTo(8));
Assert.That(transformedRectangles.Count(), Is.EqualTo(8));
}
}
}
1 change: 1 addition & 0 deletions GeneralAlgorithms.Tests/GeneralAlgorithms.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
<Compile Include="Algorithms\Polygons\GridPolygonOverlapTests.cs" />
<Compile Include="Algorithms\Polygons\GridPolygonPartitioningTests.cs" />
<Compile Include="Algorithms\Polygons\GridPolygonUtilsTests.cs" />
<Compile Include="DataStructures\Common\IntVector2Tests.cs" />
<Compile Include="DataStructures\Common\OrthogonalLineTests.cs" />
<Compile Include="DataStructures\Common\SimpleBitVector32Tests.cs" />
<Compile Include="DataStructures\Graphs\GraphTests.cs" />
Expand Down
13 changes: 13 additions & 0 deletions GeneralAlgorithms/Algorithms/Common/TransformationHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace GeneralAlgorithms.Algorithms.Common
{
using System;
using DataStructures.Common;

public static class TransformationHelper
{
public static Transformation[] GetAllTransforamtion()
{
return (Transformation[]) Enum.GetValues(typeof(Transformation));
}
}
}
40 changes: 40 additions & 0 deletions GeneralAlgorithms/DataStructures/Common/IntVector2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Algorithms.Math;
using Polygons;

/// <summary>
/// Integer vector with 2 elements. Represents a point in a 2D discrete space.
Expand Down Expand Up @@ -131,6 +132,45 @@ public IntVector2 RotateAroundCenter(int degrees)
return new IntVector2(x, y);
}

/// <summary>
/// Transforms a given vector.
/// </summary>
/// <param name="transformation"></param>
/// <returns></returns>
[Pure]
public IntVector2 Transform(Transformation transformation)
{
switch (transformation)
{
case Transformation.Identity:
return this;

case Transformation.Rotate90:
return RotateAroundCenter(90);

case Transformation.Rotate180:
return RotateAroundCenter(180);

case Transformation.Rotate270:
return RotateAroundCenter(270);

case Transformation.MirrorX:
return new IntVector2(X, -Y);

case Transformation.MirrorY:
return new IntVector2(-X, Y);

case Transformation.Diagonal13:
return new IntVector2(Y, X);

case Transformation.Diagonal24:
return new IntVector2(-Y, -X);

default:
throw new ArgumentException("Given polygon transformation is not implemented");
}
}

/// <summary>
/// Computes a dot product of two vectors.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion GeneralAlgorithms/DataStructures/Common/OrthogonalLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public OrthogonalLine(IntVector2 from, IntVector2 to)
}

/// <summary>
/// Construct an orthogonal line from given endpoints an a direction.
/// Construct an orthogonal line from given endpoints and a direction.
/// </summary>
/// <remarks>
/// Direction is used only when the line is degenerated - that means
Expand Down
10 changes: 10 additions & 0 deletions GeneralAlgorithms/DataStructures/Common/Transformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace GeneralAlgorithms.DataStructures.Common
{
public enum Transformation
{
Identity,
Rotate90, Rotate180, Rotate270, // Rotations are clockwise
MirrorX, MirrorY,
Diagonal13, Diagonal24
}
}
55 changes: 53 additions & 2 deletions GeneralAlgorithms/DataStructures/Polygons/GridPolygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,16 @@ public override int GetHashCode()
return new GridPolygon(polygon.points.Select(x => x + position));
}

#region Transformations

/// <summary>
/// Scales the polygon.
/// </summary>
/// <param name="factor"></param>
/// <returns></returns>
public GridPolygon Scale(IntVector2 factor)
{
if (factor.X <= 0 || factor.Y <= 0)
if (factor.X <= 0 || factor.Y <= 0)
throw new ArgumentOutOfRangeException(nameof(factor), "Both components of factor must be positive");

return new GridPolygon(points.Select(x => x.ElementWiseProduct(factor)));
Expand Down Expand Up @@ -209,6 +211,53 @@ public IEnumerable<GridPolygon> GetAllRotations()
return PossibleRotations.Select(Rotate);
}

/// <summary>
/// Transforms a given polygon.
/// </summary>
/// <remarks>
/// Returns a new polygon rather than modifying the original one.
///
/// Some transformations would result in a counter-clockwise order of points, which is currently not allowed.
/// In that case, the order of points is reversed with the first point staying the same.
/// </remarks>
/// <param name="transformation"></param>
/// <returns></returns>
public GridPolygon Transform(Transformation transformation)
{
var newPoints = points.Select(x => x.Transform(transformation));

// Change order of points if needed
if (transformation == Transformation.MirrorX
|| transformation == Transformation.MirrorY
|| transformation == Transformation.Diagonal13
|| transformation == Transformation.Diagonal24)
{
var newPointsList = newPoints.ToList();
newPoints = new[] {newPointsList[0]}.Concat(newPointsList.Skip(1).Reverse());
}

return new GridPolygon(newPoints);
}

/// <summary>
/// Get all possible transformations of the polygon.
/// </summary>
/// <remarks>
/// Possibly includes duplicates as e.g. all rotations of a square ale equal.
/// </remarks>
/// <returns></returns>
public IEnumerable<GridPolygon> GetAllTransformations()
{
foreach (var transformation in (Transformation[])Enum.GetValues(typeof(Transformation)))
{
yield return Transform(transformation);
}
}

#endregion

#region Factories

/// <summary>
/// Helper method for creating a polygon with side a.
/// </summary>
Expand All @@ -227,7 +276,7 @@ public static GridPolygon GetSquare(int a)
/// <returns></returns>
public static GridPolygon GetRectangle(int width, int height)
{
if (width <= 0)
if (width <= 0)
throw new ArgumentOutOfRangeException(nameof(width), "Both a and b must be greater than 0");

if (height <= 0)
Expand All @@ -241,5 +290,7 @@ public static GridPolygon GetRectangle(int width, int height)

return polygon.Build();
}

#endregion
}
}
2 changes: 2 additions & 0 deletions GeneralAlgorithms/GeneralAlgorithms.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Compile Include="Algorithms\Common\Extensions.cs" />
<Compile Include="Algorithms\Common\ILineIntersection.cs" />
<Compile Include="Algorithms\Common\OrthogonalLineIntersection.cs" />
<Compile Include="Algorithms\Common\TransformationHelper.cs" />
<Compile Include="Algorithms\Graphs\BipartiteCheck.cs" />
<Compile Include="Algorithms\Graphs\GraphDecomposition\GraphDecomposer.cs" />
<Compile Include="Algorithms\Graphs\GraphDecomposition\IGraphDecomposer.cs" />
Expand Down Expand Up @@ -118,6 +119,7 @@
<Compile Include="DataStructures\Polygons\GridPolygon.cs" />
<Compile Include="DataStructures\Polygons\GridRectangle.cs" />
<Compile Include="DataStructures\Polygons\IPolygon.cs" />
<Compile Include="DataStructures\Common\Transformation.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
28 changes: 27 additions & 1 deletion MapGeneration.Interfaces/Core/MapLayouts/IRoom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,44 @@
/// <typeparam name="TNode"></typeparam>
public interface IRoom<TNode>
{
/// <summary>
/// Corresponding input graph node.
/// </summary>
TNode Node { get; }

/// <summary>
/// Shape of the room.
/// </summary>
GridPolygon Shape { get; }

/// <summary>
/// Position of the room.
/// </summary>
IntVector2 Position { get; }

/// <summary>
/// Whether it is a corridor room or not.
/// </summary>
bool IsCorridor { get; }

/// <summary>
/// Information about connections to neighbours.
/// </summary>
IList<IDoorInfo<TNode>> Doors { get; }

/// <summary>
/// Room description.
/// </summary>
IRoomDescription RoomDescription { get; }

int Rotation { get; }
/// <summary>
/// Chosen transformation of the room shape.
/// </summary>
Transformation Transformation { get; }

/// <summary>
/// All possible transformations of the room room description.
/// </summary>
IList<Transformation> Transformations { get; }
}
}

0 comments on commit 8c9c5be

Please sign in to comment.