structure du projet, ajout de la lib hexagonal
This commit is contained in:
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
*.swp
|
||||||
|
*.*~
|
||||||
|
project.lock.json
|
||||||
|
.DS_Store
|
||||||
|
*.pyc
|
||||||
|
nupkg/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
|
||||||
|
# Rider
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Fleet
|
||||||
|
.fleet/
|
||||||
|
|
||||||
|
# Code Rush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo].bj/
|
||||||
|
[Oo]ut/
|
||||||
|
msbuild.log
|
||||||
|
msbuild.err
|
||||||
|
msbuild.wrn
|
||||||
50
Giants.sln
Normal file
50
Giants.sln
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{824D17BD-3CFE-498A-967D-3F42DF5EE92D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Core", "Src\Giants.Core\Giants.Core.csproj", "{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F34871C1-07BB-4012-A310-3FFDD6DC7DBA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Core.Tests", "Tests\Giants.Core.Tests\Giants.Core.Tests.csproj", "{30032CBC-0B7B-4BF3-9682-C506460F0FE6}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Infrastructure", "Src\Giants.Infrastructure\Giants.Infrastructure.csproj", "{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Application", "Src\Giants.Application\Giants.Application.csproj", "{1EF04517-2D31-4130-A687-7954A5431312}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{30032CBC-0B7B-4BF3-9682-C506460F0FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{30032CBC-0B7B-4BF3-9682-C506460F0FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{30032CBC-0B7B-4BF3-9682-C506460F0FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{30032CBC-0B7B-4BF3-9682-C506460F0FE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1EF04517-2D31-4130-A687-7954A5431312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1EF04517-2D31-4130-A687-7954A5431312}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
|
||||||
|
{30032CBC-0B7B-4BF3-9682-C506460F0FE6} = {F34871C1-07BB-4012-A310-3FFDD6DC7DBA}
|
||||||
|
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
|
||||||
|
{1EF04517-2D31-4130-A687-7954A5431312} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
6
README.adoc
Normal file
6
README.adoc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Giants
|
||||||
|
|
||||||
|
Projet d'adaptation du jeux de société Giants par matagot
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- Lib de map hexagonal : HexagonalLib implementation for .NET(https://github.com/imurashka/HexagonalLib?tab=readme-ov-file)
|
||||||
14
Src/Giants.Application/Giants.Application.csproj
Normal file
14
Src/Giants.Application/Giants.Application.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Giants.Infrastructure\Giants.Infrastructure.csproj" />
|
||||||
|
<ProjectReference Include="..\Giants.Core\Giants.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
18
Src/Giants.Application/Src/GiantApplication.cs
Normal file
18
Src/Giants.Application/Src/GiantApplication.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Giants.Application;
|
||||||
|
|
||||||
|
using Giants.Core.Interfaces;
|
||||||
|
using Giants.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Une application Giants permettant l'instanciations des services, utilisé pour une console
|
||||||
|
/// ou autre archi sans injections de dependances
|
||||||
|
/// /// </summary>
|
||||||
|
public class GiantApplication
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary> Constructeur de base </summary>
|
||||||
|
public GiantApplication()
|
||||||
|
{
|
||||||
|
IHexagonalGrid grid = new HexagonalGridImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Src/Giants.Core/Giants.Core.csproj
Normal file
9
Src/Giants.Core/Giants.Core.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
23
Src/Giants.Core/Src/Entities/Match.cs
Normal file
23
Src/Giants.Core/Src/Entities/Match.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Giants.Core.Interfaces;
|
||||||
|
|
||||||
|
namespace Giants.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Il s'agit d'une instance d'une partie de Giants, c'est la racine de toutes les entitées de l'instance
|
||||||
|
/// /// </summary>
|
||||||
|
public class Match
|
||||||
|
{
|
||||||
|
#region données statiques
|
||||||
|
IHexagonalGrid _grid;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region données dynamiques
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary> Construction de base </summary>
|
||||||
|
/// <param name="grid"> La grid du jeu</param>
|
||||||
|
public Match(IHexagonalGrid grid)
|
||||||
|
{
|
||||||
|
_grid = grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs
Normal file
9
Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Giants.Core.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// represente un outils qui permet de gérer une grille hexagonal
|
||||||
|
/// </summary>
|
||||||
|
public interface IHexagonalGrid
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
9
Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs
Normal file
9
Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Giants.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represente l'organisation d'un plateau, il ne contient aucune informations liées a une partie mais il permet
|
||||||
|
/// d'effectuer des recherches de chemins ou de type de tuiles
|
||||||
|
/// </summary>
|
||||||
|
public class BoardLayout
|
||||||
|
{
|
||||||
|
}
|
||||||
8
Src/Giants.Core/Src/ValuesObjects/TileInfos.cs
Normal file
8
Src/Giants.Core/Src/ValuesObjects/TileInfos.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Giants.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represente les information statiques d'une case. Ses voisins, son type, aucune informations qui peut changer pendant une partie
|
||||||
|
/// </summary>
|
||||||
|
public class TileInfos
|
||||||
|
{
|
||||||
|
}
|
||||||
5
Src/Giants.Core/Src/ValuesObjects/TilePosition.cs
Normal file
5
Src/Giants.Core/Src/ValuesObjects/TilePosition.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Giants.Core;
|
||||||
|
|
||||||
|
public class TilePosition
|
||||||
|
{
|
||||||
|
}
|
||||||
14
Src/Giants.Infrastructure/Giants.Infrastructure.csproj
Normal file
14
Src/Giants.Infrastructure/Giants.Infrastructure.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Giants.Core\Giants.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\HexagonalLib\src\HexagonalLib.Net\HexagonalLib.Net\HexagonalLib.Net.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
16
Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs
Normal file
16
Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
namespace Giants.Infrastructure;
|
||||||
|
|
||||||
|
using Giants.Core.Interfaces;
|
||||||
|
|
||||||
|
using HexagonalLib;
|
||||||
|
|
||||||
|
public class HexagonalGridImpl : IHexagonalGrid
|
||||||
|
{
|
||||||
|
private readonly HexagonalGrid _grid;
|
||||||
|
|
||||||
|
public HexagonalGridImpl()
|
||||||
|
{
|
||||||
|
_grid = new HexagonalGrid(HexagonalGridType.PointyEven, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
127
Src/HexagonalLib/README.md
Normal file
127
Src/HexagonalLib/README.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# HexagonalLib implementation for .NET
|
||||||
|
|
||||||
|
_I was highly inspired by this article: [https://www.redblobgames.com/grids/hexagons/](https://www.redblobgames.com/grids/hexagons/) and this repo is mostly just C# implementation of it. Recommended for reading. Here I will describe some technical details regarding implementation._
|
||||||
|
|
||||||
|
## Hexagonal grid
|
||||||
|
|
||||||
|
To use hexagonal grids you need to create [HexagonalGrid](src/HexagonalLib/HexagonalGrid.cs) and initialize it with grid type and inscribed radius of hex.
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var grid = new HexagonalGrid(HexagonalGridType.PointyEven, 1.0f);
|
||||||
|
```
|
||||||
|
|
||||||
|
Grids layouts and orientations are merged to one enum [HexagonalGridType](src/HexagonalLib/HexagonalGridType.cs).
|
||||||
|
|
||||||
|
* PointyOdd - Horizontal layout shoves odd rows right [odd-r]
|
||||||
|
* PointyEven - Horizontal layout shoves even rows right [even-r]
|
||||||
|
* FlatOdd - Vertical layout shoves odd columns down [odd-q]
|
||||||
|
* FlatEven - Vertical layout shoves even columns down [even-q]
|
||||||
|
|
||||||
|
|
||||||
|
## Coordinates systems
|
||||||
|
|
||||||
|
There is three coordinates systems represented in lib:
|
||||||
|
|
||||||
|
* [Offset](src/HexagonalLib/Coordinates/Offset.cs) - offset coordinates ([link](https://www.redblobgames.com/grids/hexagons/#coordinates-offset))
|
||||||
|
* [Cubic](src/HexagonalLib/Coordinates/Cubic.cs) - cube coordinates ([link](https://www.redblobgames.com/grids/hexagons/#coordinates-cube))
|
||||||
|
* [Axial](src/HexagonalLib/Coordinates/Axial.cs) - axial coordinates ([link](https://www.redblobgames.com/grids/hexagons/#coordinates-axial))
|
||||||
|
|
||||||
|
_Note: there is no [Doubled](https://www.redblobgames.com/grids/hexagons/#coordinates-doubled) coordinates yet. I will add them in later versions._
|
||||||
|
|
||||||
|
|
||||||
|
Struct [HexagonalGrid](src/HexagonalLib/HexagonalGrid.cs) contains a bunch of methods for coordinates conversion (all details are [described](https://www.redblobgames.com/grids/hexagons/#conversions) in original article):
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var offsetFromCubic = grid.ToOffset(cubic);
|
||||||
|
var offsetFromAxial = grid.ToOffset(axial);
|
||||||
|
|
||||||
|
var cubicFromOffset = grid.ToCubic(offset);
|
||||||
|
var cubicFromAxial = grid.ToCubic(axial);
|
||||||
|
|
||||||
|
var axialFromOffset = grid.ToAxial(offset);
|
||||||
|
var axialFromCubic = grid.ToAxial(cubic);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Neighbors
|
||||||
|
|
||||||
|
There is the order of neighbors of hex:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can take a neighbor of any hex by providing a coordinate of hex and required neighbor index.
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var oNeighbor = grid.GetNeighbor(offset, neighborIndex);
|
||||||
|
var cNeighbor = grid.GetNeighbor(cubic, neighborIndex);
|
||||||
|
var aNeighbor = grid.GetNeighbor(axial, neighborIndex);
|
||||||
|
```
|
||||||
|
_The neighbor index can be negative or greater than 5 (it will be normalized)_
|
||||||
|
|
||||||
|
Or you can take all neighbors of particular hex
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var oNeighbors = grid.GetNeighbors(offset);
|
||||||
|
var cNeighbors = grid.GetNeighbors(cubic);
|
||||||
|
var aNeighbors = grid.GetNeighbors(axial);
|
||||||
|
```
|
||||||
|
|
||||||
|
There is also option to check are two hexes neighbors or not:
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var isNeighbors1 = grid.IsNeighbors(offset, oNeighbor);
|
||||||
|
var isNeighbors2 = grid.IsNeighbors(cubic, cNeighbor);
|
||||||
|
var isNeighbors3 = grid.IsNeighbors(axial, aNeighbor);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ring of neighbors
|
||||||
|
You also can get ring of neighbor for particular hex
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```C#
|
||||||
|
var oNeighbors = grid.GetNeighborsRing(offset, radius);
|
||||||
|
var cNeighbors = grid.GetNeighborsRing(cubic, radius);
|
||||||
|
var aNeighbors = grid.GetNeighborsRing(axial, radius);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Circle of neighbors
|
||||||
|
Same as ring but you will receive hexes from all rings
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```C#
|
||||||
|
var oNeighbors = grid.GetNeighborsAround(offset, radius);
|
||||||
|
var cNeighbors = grid.GetNeighborsAround(cubic, radius);
|
||||||
|
var aNeighbors = grid.GetNeighborsAround(axial, radius);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2D space
|
||||||
|
|
||||||
|
There is also list of methods to convert hex coordinate to its center (point represented as tuple):
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var pointFromOffset = grid.ToPoint2(offset);
|
||||||
|
var pointFromCubic = grid.ToPoint2(cubic);
|
||||||
|
var pointFromAxial = grid.ToPoint2(axial);
|
||||||
|
```
|
||||||
|
|
||||||
|
To convert point into a hex coordinate which contains this point you can use:
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var offsetFromPoint = grid.ToOffset(x, y);
|
||||||
|
var cubicFromPoint = grid.ToCubic(x, y);
|
||||||
|
var axialFromPoint = grid.ToAxial(x, y);
|
||||||
|
```
|
||||||
|
|
||||||
|
Hexagons have 6 sides and 6 corners. There is corners order of the hexes:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To take them in code simly use:
|
||||||
|
|
||||||
|
```C#
|
||||||
|
var cornerFromOffset = grid.GetCorner(offset, cornerIndex);
|
||||||
|
var cornerFromCubic = grid.GetCorner(cubic, cornerIndex);
|
||||||
|
var cornerFromAxial = grid.GetCorner(axial, cornerIndex);
|
||||||
|
```
|
||||||
|
_The corner index can be negative or greater than 5 (it will be normalized)_
|
||||||
BIN
Src/HexagonalLib/img/hex-around.png
Normal file
BIN
Src/HexagonalLib/img/hex-around.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
Src/HexagonalLib/img/hex-corners-order.png
Normal file
BIN
Src/HexagonalLib/img/hex-corners-order.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
Src/HexagonalLib/img/hex-neighbors-order.png
Normal file
BIN
Src/HexagonalLib/img/hex-neighbors-order.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
Src/HexagonalLib/img/hex-rings.png
Normal file
BIN
Src/HexagonalLib/img/hex-rings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
70
Src/HexagonalLib/src/.editorconfig
Normal file
70
Src/HexagonalLib/src/.editorconfig
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
[*]
|
||||||
|
charset=utf-8
|
||||||
|
end_of_line=crlf
|
||||||
|
trim_trailing_whitespace=false
|
||||||
|
insert_final_newline=false
|
||||||
|
indent_style=space
|
||||||
|
indent_size=4
|
||||||
|
|
||||||
|
# Microsoft .NET properties
|
||||||
|
csharp_new_line_before_members_in_object_initializers=false
|
||||||
|
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||||
|
csharp_style_var_elsewhere=true:suggestion
|
||||||
|
csharp_style_var_for_built_in_types=true:suggestion
|
||||||
|
csharp_style_var_when_type_is_apparent=true:suggestion
|
||||||
|
dotnet_naming_rule.private_constants_rule.severity=warning
|
||||||
|
dotnet_naming_rule.private_constants_rule.style=upper_camel_case_style
|
||||||
|
dotnet_naming_rule.private_constants_rule.symbols=private_constants_symbols
|
||||||
|
dotnet_naming_rule.private_static_readonly_rule.severity=warning
|
||||||
|
dotnet_naming_rule.private_static_readonly_rule.style=lower_camel_case_style
|
||||||
|
dotnet_naming_rule.private_static_readonly_rule.symbols=private_static_readonly_symbols
|
||||||
|
dotnet_naming_style.lower_camel_case_style.capitalization=camel_case
|
||||||
|
dotnet_naming_style.lower_camel_case_style.required_prefix=_
|
||||||
|
dotnet_naming_style.upper_camel_case_style.capitalization=pascal_case
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities=private
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.applicable_kinds=field
|
||||||
|
dotnet_naming_symbols.private_constants_symbols.required_modifiers=const
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities=private
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds=field
|
||||||
|
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers=static,readonly
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
|
||||||
|
dotnet_style_predefined_type_for_member_access=true:suggestion
|
||||||
|
dotnet_style_qualification_for_event=false:suggestion
|
||||||
|
dotnet_style_qualification_for_field=false:suggestion
|
||||||
|
dotnet_style_qualification_for_method=false:suggestion
|
||||||
|
dotnet_style_qualification_for_property=false:suggestion
|
||||||
|
dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion
|
||||||
|
|
||||||
|
# ReSharper properties
|
||||||
|
resharper_autodetect_indent_settings=true
|
||||||
|
resharper_csharp_max_attribute_length_for_same_line=80
|
||||||
|
resharper_csharp_max_line_length=170
|
||||||
|
resharper_keep_existing_attribute_arrangement=true
|
||||||
|
resharper_max_attribute_length_for_same_line=20
|
||||||
|
resharper_place_field_attribute_on_same_line=false
|
||||||
|
resharper_use_indent_from_vs=false
|
||||||
|
|
||||||
|
# ReSharper inspection severities
|
||||||
|
resharper_arrange_redundant_parentheses_highlighting=hint
|
||||||
|
resharper_arrange_this_qualifier_highlighting=hint
|
||||||
|
resharper_arrange_type_member_modifiers_highlighting=hint
|
||||||
|
resharper_arrange_type_modifiers_highlighting=hint
|
||||||
|
resharper_built_in_type_reference_style_for_member_access_highlighting=hint
|
||||||
|
resharper_built_in_type_reference_style_highlighting=hint
|
||||||
|
resharper_member_can_be_private_global_highlighting=none
|
||||||
|
resharper_partial_type_with_single_part_highlighting=none
|
||||||
|
resharper_redundant_base_qualifier_highlighting=warning
|
||||||
|
resharper_suggest_var_or_type_built_in_types_highlighting=hint
|
||||||
|
resharper_suggest_var_or_type_elsewhere_highlighting=hint
|
||||||
|
resharper_suggest_var_or_type_simple_types_highlighting=hint
|
||||||
|
resharper_web_config_module_not_resolved_highlighting=warning
|
||||||
|
resharper_web_config_type_not_resolved_highlighting=warning
|
||||||
|
resharper_web_config_wrong_module_highlighting=warning
|
||||||
|
|
||||||
|
[*.{appxmanifest,asax,ascx,aspx,build,cs,cshtml,dtd,fs,fsi,fsscript,fsx,master,ml,mli,nuspec,razor,resw,resx,skin,vb,xaml,xamlx,xoml,xsd}]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=4
|
||||||
|
tab_width=4
|
||||||
4
Src/HexagonalLib/src/.gitignore
vendored
Normal file
4
Src/HexagonalLib/src/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.bin/*
|
||||||
|
.obj/*
|
||||||
|
.idea/*
|
||||||
|
.packages/*
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
using HexagonalLib.Coordinates;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using static System.Math;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Tests
|
||||||
|
{
|
||||||
|
[TestFixture(TestOf = typeof(HexagonalGrid))]
|
||||||
|
public class HexagonalGridTests
|
||||||
|
{
|
||||||
|
private float InscribedRadius => 0.5f;
|
||||||
|
private float DescribedRadius => (float) (InscribedRadius / Cos(PI / HexagonalGrid.EdgesCount));
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check initial properties values for flat grids after creation")]
|
||||||
|
[TestCase(HexagonalGridType.FlatEven)]
|
||||||
|
[TestCase(HexagonalGridType.FlatOdd)]
|
||||||
|
public void FlatPropertiesTest(HexagonalGridType type)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
Assert.AreEqual(grid.InscribedRadius, InscribedRadius);
|
||||||
|
Assert.AreEqual(grid.DescribedRadius, DescribedRadius);
|
||||||
|
Assert.AreEqual(grid.InscribedDiameter, InscribedRadius * 2);
|
||||||
|
Assert.AreEqual(grid.DescribedDiameter, DescribedRadius * 2);
|
||||||
|
Assert.AreEqual(grid.HorizontalOffset, DescribedRadius * 1.5f);
|
||||||
|
Assert.AreEqual(grid.VerticalOffset, InscribedRadius * 2.0f);
|
||||||
|
Assert.AreEqual(grid.Side, DescribedRadius);
|
||||||
|
Assert.AreEqual(grid.AngleToFirstNeighbor, 30.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check initial properties values for pointy grids after creation")]
|
||||||
|
[TestCase(HexagonalGridType.PointyEven)]
|
||||||
|
[TestCase(HexagonalGridType.PointyOdd)]
|
||||||
|
public void PointyPropertiesTest(HexagonalGridType type)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
Assert.AreEqual(grid.InscribedRadius, InscribedRadius);
|
||||||
|
Assert.AreEqual(grid.DescribedRadius, DescribedRadius);
|
||||||
|
Assert.AreEqual(grid.InscribedDiameter, InscribedRadius * 2);
|
||||||
|
Assert.AreEqual(grid.DescribedDiameter, DescribedRadius * 2);
|
||||||
|
Assert.AreEqual(grid.HorizontalOffset, InscribedRadius * 2.0f);
|
||||||
|
Assert.AreEqual(grid.VerticalOffset, DescribedRadius * 1.5f);
|
||||||
|
Assert.AreEqual(grid.Side, DescribedRadius);
|
||||||
|
Assert.AreEqual(grid.AngleToFirstNeighbor, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check coordinate conversion from Offset")]
|
||||||
|
public void CoordinateConversionTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
Assert.IsTrue(cubic.IsValid(), $"Invalid cubic coordinate: {cubic.X}-{cubic.Y}-{cubic.Z}");
|
||||||
|
Assert.AreEqual(offset, grid.ToOffset(axial));
|
||||||
|
Assert.AreEqual(offset, grid.ToOffset(cubic));
|
||||||
|
Assert.AreEqual(axial, grid.ToAxial(offset));
|
||||||
|
Assert.AreEqual(axial, grid.ToAxial(cubic));
|
||||||
|
Assert.AreEqual(cubic, grid.ToCubic(offset));
|
||||||
|
Assert.AreEqual(cubic, grid.ToCubic(axial));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check conversion to Point2 from Offset")]
|
||||||
|
public void PointConversionTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
|
||||||
|
var fromOffset = grid.ToPoint2(offset);
|
||||||
|
var fromAxial = grid.ToPoint2(axial);
|
||||||
|
var fromCubic = grid.ToPoint2(cubic);
|
||||||
|
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromAxial), $"Expected: {fromAxial.X}:{fromAxial.Y}; Actual: {fromOffset.X}:{fromOffset.Y}");
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromCubic), $"Expected: {fromCubic.X}:{fromCubic.Y}; Actual: {fromOffset.X}:{fromOffset.Y}");
|
||||||
|
|
||||||
|
Assert.AreEqual(offset, grid.ToOffset(fromOffset));
|
||||||
|
Assert.AreEqual(axial, grid.ToAxial(fromAxial));
|
||||||
|
Assert.AreEqual(cubic, grid.ToCubic(fromCubic));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check IsNeighbor methods for all coordinates types")]
|
||||||
|
public void IsNeighborTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY,
|
||||||
|
[Values(-1, 0, 1, 2, 3, 4, 5, 6)] int neighborIndex)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
Assert.IsTrue(cubic.IsValid(), $"Invalid cubic coordinate: {cubic.X}-{cubic.Y}-{cubic.Z}");
|
||||||
|
|
||||||
|
var oNeighbor = grid.GetNeighbor(offset, neighborIndex);
|
||||||
|
var aNeighbor = grid.GetNeighbor(axial, neighborIndex);
|
||||||
|
var cNeighbor = grid.GetNeighbor(cubic, neighborIndex);
|
||||||
|
|
||||||
|
Assert.IsTrue(cNeighbor.IsValid(), $"Invalid cubic coordinate: {cNeighbor.X}-{cNeighbor.Y}-{cNeighbor.Z}");
|
||||||
|
Assert.IsTrue(grid.IsNeighbors(offset, oNeighbor), $"Neighbor1={offset}; Neighbor2={oNeighbor}; Index={neighborIndex};");
|
||||||
|
Assert.IsTrue(grid.IsNeighbors(axial, aNeighbor), $"Neighbor1={axial}; Neighbor2={aNeighbor}; Index={neighborIndex};");
|
||||||
|
Assert.IsTrue(grid.IsNeighbors(cubic, cNeighbor), $"Neighbor1={cubic}; Neighbor2={cNeighbor}; Index={neighborIndex};");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check neighbors order for all coordinates types")]
|
||||||
|
public void NeighborsOrderTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY,
|
||||||
|
[Values(-1, 0, 1, 2, 3, 4, 5, 6)] int neighborIndex)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
|
||||||
|
var oNeighbor = grid.GetNeighbor(offset, neighborIndex);
|
||||||
|
var aNeighbor = grid.GetNeighbor(axial, neighborIndex);
|
||||||
|
var cNeighbor = grid.GetNeighbor(cubic, neighborIndex);
|
||||||
|
|
||||||
|
Assert.IsTrue(cNeighbor.IsValid(), $"Invalid cubic coordinate: {cNeighbor.X}-{cNeighbor.Y}-{cNeighbor.Z}");
|
||||||
|
|
||||||
|
var fromAxial = grid.ToOffset(aNeighbor);
|
||||||
|
var fromCubic = grid.ToOffset(cNeighbor);
|
||||||
|
|
||||||
|
Assert.AreEqual(oNeighbor, fromAxial, $"Center=({offset} - {axial}); Current=({oNeighbor} - {aNeighbor}); Index={neighborIndex};");
|
||||||
|
Assert.AreEqual(oNeighbor, fromCubic, $"Center=({offset} - {cubic}); Current=({oNeighbor} - {cNeighbor}); Index={neighborIndex};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>HexagonalLib.Tests</RootNamespace>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Net.Tests\Debug\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Net.Tests\Release\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="nunit" Version="3.12.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HexagonalLib.Net\HexagonalLib.Net.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Tests
|
||||||
|
{
|
||||||
|
[TestFixture(TestOf = typeof(HexagonalMath))]
|
||||||
|
public class HexagonalMathTests
|
||||||
|
{
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check HexagonalMath.Rotate method")]
|
||||||
|
[TestCase(0, 1, 0, 0, 1)]
|
||||||
|
[TestCase(0, 1, 45, 0.5f, 0.5f)]
|
||||||
|
[TestCase(0, 1, 90, 1, 0)]
|
||||||
|
[TestCase(0, 1, 135, 0.5f, -0.5f)]
|
||||||
|
[TestCase(0, 1, 180, 0, -1)]
|
||||||
|
[TestCase(0, 1, 225, -0.5f, -0.5f)]
|
||||||
|
[TestCase(0, 1, 270, -1, 0)]
|
||||||
|
[TestCase(0, 1, 315, -0.5f, 0.5f)]
|
||||||
|
[TestCase(0, 1, 360, 0, 1)]
|
||||||
|
public void RotateTest(float x, float y, float degrees, float resultX, float resultY)
|
||||||
|
{
|
||||||
|
var vector = (x, y).Rotate(degrees);
|
||||||
|
var result = (resultX, resultY).Normalize();
|
||||||
|
Assert.IsTrue(vector.SimilarTo(result), $"Expected: {result.X}:{result.Y}; Actual: {vector.X}:{vector.Y}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>HexagonalLib</RootNamespace>
|
||||||
|
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<Title>HexagonalLib</Title>
|
||||||
|
<Authors>Ivan Murashka</Authors>
|
||||||
|
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||||
|
<PackageProjectUrl>https://github.com/imurashka/HexagonalLib</PackageProjectUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Net\Debug\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Net\Release\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="..\..\HexagonalLib\HexagonalLib.projitems" Label="Shared" />
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using HexagonalLib.Coordinates;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class HexagonalGridTests
|
||||||
|
{
|
||||||
|
private float InscribedRadius => 0.5f;
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check coordinate conversion from Offset to Unity vectors")]
|
||||||
|
public void Vector2ConversionTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
|
||||||
|
var fromOffset = grid.ToVector2(offset);
|
||||||
|
var fromAxial = grid.ToVector2(axial);
|
||||||
|
var fromCubic = grid.ToVector2(cubic);
|
||||||
|
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromAxial), $"Expected: {fromAxial}; Actual: {fromOffset}");
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromCubic), $"Expected: {fromCubic}; Actual: {fromOffset}");
|
||||||
|
|
||||||
|
Assert.AreEqual(offset, grid.ToOffset(fromOffset));
|
||||||
|
Assert.AreEqual(axial, grid.ToAxial(fromAxial));
|
||||||
|
Assert.AreEqual(cubic, grid.ToCubic(fromCubic));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test(Author = "Ivan Murashka", Description = "Check coordinate conversion from Offset to Unity vectors")]
|
||||||
|
public void Vector3ConversionTest(
|
||||||
|
[Values] HexagonalGridType type,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetX,
|
||||||
|
[Values(-13, -8, 0, 15, 22)] int offsetY)
|
||||||
|
{
|
||||||
|
var grid = new HexagonalGrid(type, InscribedRadius);
|
||||||
|
var offset = new Offset(offsetX, offsetY);
|
||||||
|
var axial = grid.ToAxial(offset);
|
||||||
|
var cubic = grid.ToCubic(offset);
|
||||||
|
|
||||||
|
var fromOffset = grid.ToVector3(offset);
|
||||||
|
var fromAxial = grid.ToVector3(axial);
|
||||||
|
var fromCubic = grid.ToVector3(cubic);
|
||||||
|
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromAxial), $"Expected: {fromAxial}; Actual: {fromOffset}");
|
||||||
|
Assert.IsTrue(fromOffset.SimilarTo(fromCubic), $"Expected: {fromCubic}; Actual: {fromOffset}");
|
||||||
|
|
||||||
|
Assert.AreEqual(offset, grid.ToOffset(fromOffset));
|
||||||
|
Assert.AreEqual(axial, grid.ToAxial(fromAxial));
|
||||||
|
Assert.AreEqual(cubic, grid.ToCubic(fromCubic));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\..\.packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\.packages\NUnit.3.12.0\build\NUnit.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{1E807875-014C-4745-86AB-E1E35916F8B3}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>HexagonalLib.Tests</RootNamespace>
|
||||||
|
<AssemblyName>HexagonalLib.Unity.Tests</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Unity.Tests\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Unity.Tests\Debug\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb">
|
||||||
|
<HintPath>..\..\.packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
|
<HintPath>..\..\.packages\Unity3D.UnityEngine.2018.3.5.1\lib\UnityEngine.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="HexagonalGridTests.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HexagonalLib.Unity\HexagonalLib.Unity.csproj">
|
||||||
|
<Project>{ee497232-ac7a-48d0-9059-53b152c6bf01}</Project>
|
||||||
|
<Name>HexagonalLib.Unity</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\.packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\.packages\NUnit.3.12.0\build\NUnit.props'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("HexagonalLib.Unity.Tests")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("HexagonalLib.Unity.Tests")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("1E807875-014C-4745-86AB-E1E35916F8B3")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="NUnit" version="3.12.0" targetFramework="net472" />
|
||||||
|
<package id="Unity3D.UnityEngine" version="2018.3.5.1" targetFramework="net472" />
|
||||||
|
</packages>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
public partial struct Axial
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
public readonly partial struct Cubic
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
public readonly partial struct Offset
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HexagonalLib.Coordinates;
|
||||||
|
using HexagonalLib.Utility;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
public partial struct HexagonalGrid
|
||||||
|
{
|
||||||
|
#region ToOffset
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to offset coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset(Vector2 vector)
|
||||||
|
{
|
||||||
|
return ToOffset(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to offset coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset(Vector3 vector)
|
||||||
|
{
|
||||||
|
return ToOffset(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToAxial
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to axial coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial(Vector2 vector)
|
||||||
|
{
|
||||||
|
return ToAxial(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to axial coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial(Vector3 vector)
|
||||||
|
{
|
||||||
|
return ToAxial(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToCubic
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to cubic coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic(Vector2 vector)
|
||||||
|
{
|
||||||
|
return ToCubic(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert point to cubic coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic(Vector3 vector)
|
||||||
|
{
|
||||||
|
return ToCubic(vector.AsTuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToVector
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its offset coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 ToVector2(Offset coord)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector2();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its axial coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 ToVector2(Axial coord)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector2();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its cubic coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 ToVector2(Cubic coord)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector2();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its offset coordinate to it center position in 3d space OZ
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 ToVector3(Offset coord, float y = 0)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector3(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its axial coordinate to it center position in 3d space OZ
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 ToVector3(Axial coord, float y = 0)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector3(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its cubic coordinate to it center position in 3d space OZ
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 ToVector3(Cubic coord, float y = 0)
|
||||||
|
{
|
||||||
|
return ToPoint2(coord).AsVector3(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region CreateMesh
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public Mesh CreateMesh(IReadOnlyList<Offset> hexes, int subdivide)
|
||||||
|
{
|
||||||
|
return CreateMesh(hexes, subdivide, CreateMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public Mesh CreateMesh(IReadOnlyList<Axial> hexes, int subdivide)
|
||||||
|
{
|
||||||
|
return CreateMesh(hexes, subdivide, CreateMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public Mesh CreateMesh(IReadOnlyList<Cubic> hexes, int subdivide)
|
||||||
|
{
|
||||||
|
return CreateMesh(hexes, subdivide, CreateMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mesh CreateMesh<T>(IReadOnlyList<T> hexes, int subdivide, Action<IEnumerable<T>, int, Action<int, (float X, float Y)>, Action<int, int>> createMesh)
|
||||||
|
{
|
||||||
|
var meshData = GetMeshData(hexes.Count, subdivide);
|
||||||
|
var vertices = new Vector3[meshData.VerticesCount];
|
||||||
|
var triangles = new int[meshData.IndicesCount];
|
||||||
|
|
||||||
|
createMesh(hexes, subdivide,
|
||||||
|
(i, point) => vertices[i] = new Vector3(point.X, 0, point.Y),
|
||||||
|
(i, index) => triangles[i] = index);
|
||||||
|
|
||||||
|
var mesh = new Mesh
|
||||||
|
{
|
||||||
|
vertices = vertices,
|
||||||
|
triangles = triangles
|
||||||
|
};
|
||||||
|
|
||||||
|
mesh.RecalculateNormals();
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{EE497232-AC7A-48D0-9059-53B152C6BF01}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>HexagonalLib</RootNamespace>
|
||||||
|
<AssemblyName>HexagonalLib.Unity</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Unity\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>..\..\.bin\HexagonalLib.Unity\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
|
<HintPath>..\..\.packages\Unity3D.UnityEngine.2018.3.5.1\lib\UnityEngine.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Coordinates\Axial.cs" />
|
||||||
|
<Compile Include="Coordinates\Cubic.cs" />
|
||||||
|
<Compile Include="Coordinates\Offset.cs" />
|
||||||
|
<Compile Include="HexagonalGrid.cs" />
|
||||||
|
<Compile Include="HexagonalMath.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Utility\VectorUtility.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="..\..\HexagonalLib\HexagonalLib.projitems" Label="Shared" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
public static partial class HexagonalMath
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two vectors and returns true if they are similar.
|
||||||
|
/// </summary>
|
||||||
|
public static bool SimilarTo(this in Vector2 a, in Vector2 b)
|
||||||
|
{
|
||||||
|
return a.x.SimilarTo(b.x) && a.y.SimilarTo(b.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two vectors and returns true if they are similar.
|
||||||
|
/// </summary>
|
||||||
|
public static bool SimilarTo(this in Vector3 a, in Vector3 b)
|
||||||
|
{
|
||||||
|
return a.x.SimilarTo(b.x) && a.y.SimilarTo(b.y) && a.z.SimilarTo(b.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("HexagonalLib.Unity")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("HexagonalLib.Unity")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("EE497232-AC7A-48D0-9059-53B152C6BF01")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Utility
|
||||||
|
{
|
||||||
|
internal static class VectorUtility
|
||||||
|
{
|
||||||
|
internal static (float x, float y) AsTuple(this Vector2 vector)
|
||||||
|
{
|
||||||
|
return (vector.x, vector.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (float x, float y) AsTuple(this Vector3 vector)
|
||||||
|
{
|
||||||
|
return (vector.x, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Vector2 AsVector2(this (float x, float y) tuple)
|
||||||
|
{
|
||||||
|
return new Vector2(tuple.x, tuple.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Vector3 AsVector3(this (float x, float y) tuple, float y = 0.0f)
|
||||||
|
{
|
||||||
|
return new Vector3(tuple.x, y, tuple.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Unity3D.UnityEngine" version="2018.3.5.1" targetFramework="net472" />
|
||||||
|
</packages>
|
||||||
50
Src/HexagonalLib/src/HexagonalLib.sln
Normal file
50
Src/HexagonalLib/src/HexagonalLib.sln
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "HexagonalLib", "HexagonalLib\HexagonalLib.shproj", "{30905D5D-8D2E-4A25-ABEB-B4B4B0C440E6}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HexagonalLib.Unity", "HexagonalLib.Unity", "{C02A807F-4B02-4900-895F-67E25F8CF774}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexagonalLib.Unity.Tests", "HexagonalLib.Unity\HexagonalLib.Unity.Tests\HexagonalLib.Unity.Tests.csproj", "{1E807875-014C-4745-86AB-E1E35916F8B3}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexagonalLib.Unity", "HexagonalLib.Unity\HexagonalLib.Unity\HexagonalLib.Unity.csproj", "{EE497232-AC7A-48D0-9059-53B152C6BF01}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HexagonalLib.Net", "HexagonalLib.Net", "{1F507917-8D29-4061-BC98-7B64DABADED3}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexagonalLib.Net.Tests", "HexagonalLib.Net\HexagonalLib.Net.Tests\HexagonalLib.Net.Tests.csproj", "{2608E591-E33C-446A-9E95-AFED738B2512}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexagonalLib.Net", "HexagonalLib.Net\HexagonalLib.Net\HexagonalLib.Net.csproj", "{CF391253-3550-40CF-810B-A6F8FCA2EBF2}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{30905D5D-8D2E-4A25-ABEB-B4B4B0C440E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{30905D5D-8D2E-4A25-ABEB-B4B4B0C440E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EE497232-AC7A-48D0-9059-53B152C6BF01}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EE497232-AC7A-48D0-9059-53B152C6BF01}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EE497232-AC7A-48D0-9059-53B152C6BF01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EE497232-AC7A-48D0-9059-53B152C6BF01}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1E807875-014C-4745-86AB-E1E35916F8B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1E807875-014C-4745-86AB-E1E35916F8B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1E807875-014C-4745-86AB-E1E35916F8B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1E807875-014C-4745-86AB-E1E35916F8B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CF391253-3550-40CF-810B-A6F8FCA2EBF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CF391253-3550-40CF-810B-A6F8FCA2EBF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CF391253-3550-40CF-810B-A6F8FCA2EBF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CF391253-3550-40CF-810B-A6F8FCA2EBF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2608E591-E33C-446A-9E95-AFED738B2512}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2608E591-E33C-446A-9E95-AFED738B2512}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2608E591-E33C-446A-9E95-AFED738B2512}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2608E591-E33C-446A-9E95-AFED738B2512}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{1E807875-014C-4745-86AB-E1E35916F8B3} = {C02A807F-4B02-4900-895F-67E25F8CF774}
|
||||||
|
{EE497232-AC7A-48D0-9059-53B152C6BF01} = {C02A807F-4B02-4900-895F-67E25F8CF774}
|
||||||
|
{CF391253-3550-40CF-810B-A6F8FCA2EBF2} = {1F507917-8D29-4061-BC98-7B64DABADED3}
|
||||||
|
{2608E591-E33C-446A-9E95-AFED738B2512} = {1F507917-8D29-4061-BC98-7B64DABADED3}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
86
Src/HexagonalLib/src/HexagonalLib/Coordinates/Axial.cs
Normal file
86
Src/HexagonalLib/src/HexagonalLib/Coordinates/Axial.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public readonly partial struct Axial : IEquatable<Axial>, IEqualityComparer<Axial>
|
||||||
|
{
|
||||||
|
public static Axial Zero => new Axial(0, 0);
|
||||||
|
|
||||||
|
public readonly int Q;
|
||||||
|
public readonly int R;
|
||||||
|
|
||||||
|
public Axial(int q, int r)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
Q = q;
|
||||||
|
R = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return (coord1.Q, coord1.R) == (coord2.Q, coord2.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return (coord1.Q, coord1.R) != (coord2.Q, coord2.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Axial operator +(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return new Axial(coord1.Q + coord2.Q, coord1.R + coord2.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Axial operator +(Axial coord, int offset)
|
||||||
|
{
|
||||||
|
return new Axial(coord.Q + offset, coord.R + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Axial operator -(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return new Axial(coord1.Q - coord2.Q, coord1.R - coord2.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Axial operator -(Axial coord, int offset)
|
||||||
|
{
|
||||||
|
return new Axial(coord.Q - offset, coord.R - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Axial operator *(Axial coord, int offset)
|
||||||
|
{
|
||||||
|
return new Axial(coord.Q * offset, coord.R * offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
return other is Axial axial && Equals(axial);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Axial other)
|
||||||
|
{
|
||||||
|
return (Q, R) == (other.Q, other.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return coord1.Equals(coord2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (Q, R).GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(Axial axial)
|
||||||
|
{
|
||||||
|
return axial.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"A-[{Q}:{R}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
148
Src/HexagonalLib/src/HexagonalLib/Coordinates/Cubic.cs
Normal file
148
Src/HexagonalLib/src/HexagonalLib/Coordinates/Cubic.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public readonly partial struct Cubic : IEquatable<Cubic>, IEqualityComparer<Cubic>
|
||||||
|
{
|
||||||
|
public static Cubic Zero => new Cubic(0, 0, 0);
|
||||||
|
|
||||||
|
public readonly int X;
|
||||||
|
public readonly int Y;
|
||||||
|
public readonly int Z;
|
||||||
|
|
||||||
|
public Cubic(int x, int y, int z)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Round float coordinates to nearest valid coordinate
|
||||||
|
/// </summary>
|
||||||
|
public Cubic(float x, float y, float z)
|
||||||
|
{
|
||||||
|
var rx = (int) Math.Round(x);
|
||||||
|
var ry = (int) Math.Round(y);
|
||||||
|
var rz = (int) Math.Round(z);
|
||||||
|
|
||||||
|
var xDiff = Math.Abs(rx - x);
|
||||||
|
var yDiff = Math.Abs(ry - y);
|
||||||
|
var zDiff = Math.Abs(rz - z);
|
||||||
|
|
||||||
|
if (xDiff > yDiff && xDiff > zDiff)
|
||||||
|
{
|
||||||
|
rx = -ry - rz;
|
||||||
|
}
|
||||||
|
else if (yDiff > zDiff)
|
||||||
|
{
|
||||||
|
ry = -rx - rz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rz = -rx - ry;
|
||||||
|
}
|
||||||
|
|
||||||
|
X = rx;
|
||||||
|
Y = ry;
|
||||||
|
Z = rz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return (coord1.X, coord1.Y, coord1.Z) == (coord2.X, coord2.Y, coord2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return (coord1.X, coord1.Y, coord1.Z) != (coord2.X, coord2.Y, coord2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator +(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return new Cubic(coord1.X + coord2.X, coord1.Y + coord2.Y, coord1.Z + coord2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator +(Cubic coord, int offset)
|
||||||
|
{
|
||||||
|
return new Cubic(coord.X + offset, coord.Y + offset, coord.Z + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator -(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return new Cubic(coord1.X - coord2.X, coord1.Y - coord2.Y, coord1.Z - coord2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator -(Cubic coord, int offset)
|
||||||
|
{
|
||||||
|
return new Cubic(coord.X - offset, coord.Y - offset, coord.Z - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator *(Cubic coord, int offset)
|
||||||
|
{
|
||||||
|
return new Cubic(coord.X * offset, coord.Y * offset, coord.Z * offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cubic operator *(Cubic coord, float delta)
|
||||||
|
{
|
||||||
|
return new Cubic(coord.X * delta, coord.Y * delta, coord.Z * delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid()
|
||||||
|
{
|
||||||
|
return X + Y + Z == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cubic RotateToRight()
|
||||||
|
{
|
||||||
|
var x = -Y;
|
||||||
|
var y = -Z;
|
||||||
|
var z = -X;
|
||||||
|
return new Cubic(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cubic RotateToRight(int times)
|
||||||
|
{
|
||||||
|
var cur = this;
|
||||||
|
for (var i = 0; i < times; i++)
|
||||||
|
{
|
||||||
|
cur = cur.RotateToRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Cubic other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Cubic other)
|
||||||
|
{
|
||||||
|
return (X, Y, Z) == (other.X, other.Y, other.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return coord1.Equals(coord2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (X, Y, Z).GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(Cubic coord)
|
||||||
|
{
|
||||||
|
return coord.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return !IsValid() ? "C-[Invalid]" : $"C-[{X}:{Y}:{Z}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
113
Src/HexagonalLib/src/HexagonalLib/Coordinates/Offset.cs
Normal file
113
Src/HexagonalLib/src/HexagonalLib/Coordinates/Offset.cs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace HexagonalLib.Coordinates
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public readonly partial struct Offset : IEquatable<Offset>, IEqualityComparer<Offset>
|
||||||
|
{
|
||||||
|
public static Offset Zero => new Offset(0, 0);
|
||||||
|
|
||||||
|
public readonly int X;
|
||||||
|
public readonly int Y;
|
||||||
|
|
||||||
|
public Offset(int x, int y)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Offset Add(int xOffset, int yOffset)
|
||||||
|
{
|
||||||
|
return new Offset(X + xOffset, Y + yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset Clamp(Offset coord, Offset min, Offset max)
|
||||||
|
{
|
||||||
|
var x = Clamp(coord.X, min.X, max.X);
|
||||||
|
var y = Clamp(coord.Y, min.Y, max.Y);
|
||||||
|
|
||||||
|
return new Offset(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Clamp(int value, int min, int max)
|
||||||
|
{
|
||||||
|
if (value < min)
|
||||||
|
{
|
||||||
|
value = min;
|
||||||
|
}
|
||||||
|
else if (value > max)
|
||||||
|
{
|
||||||
|
value = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return (coord1.X, coord1.Y) == (coord2.X, coord2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return (coord1.X, coord1.Y) != (coord2.X, coord2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset operator +(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return new Offset(coord1.X + coord2.X, coord1.Y + coord2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset operator +(Offset coord, int offset)
|
||||||
|
{
|
||||||
|
return new Offset(coord.X + offset, coord.Y + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset operator -(Offset coord, Offset index2)
|
||||||
|
{
|
||||||
|
return new Offset(coord.X - index2.X, coord.Y - index2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset operator /(Offset coord, int value)
|
||||||
|
{
|
||||||
|
return new Offset(coord.X / value, coord.Y / value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Offset operator *(Offset coord, int offset)
|
||||||
|
{
|
||||||
|
return new Offset(coord.X * offset, coord.Y * offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Offset other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Offset other)
|
||||||
|
{
|
||||||
|
return (X, Y) == (other.X, other.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return coord1.Equals(coord2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (X, Y).GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(Offset coord)
|
||||||
|
{
|
||||||
|
return coord.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"O-[{X}:{Y}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
Src/HexagonalLib/src/HexagonalLib/HexagonalException.cs
Normal file
72
Src/HexagonalLib/src/HexagonalLib/HexagonalException.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
public class HexagonalException : Exception
|
||||||
|
{
|
||||||
|
private class MessageBuilder
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _message = new StringBuilder();
|
||||||
|
|
||||||
|
public MessageBuilder Append(string message)
|
||||||
|
{
|
||||||
|
_message.AppendLine(message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder Append(HexagonalGrid grid)
|
||||||
|
{
|
||||||
|
Append(nameof(grid.Type), grid.Type);
|
||||||
|
Append(nameof(grid.InscribedRadius), grid.InscribedRadius);
|
||||||
|
Append(nameof(grid.DescribedRadius), grid.DescribedRadius);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder Append(params (string, object)[] fields)
|
||||||
|
{
|
||||||
|
foreach (var (paramName, paramValue) in fields)
|
||||||
|
{
|
||||||
|
Append(paramName, paramValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Append(string paramName, object paramValue)
|
||||||
|
{
|
||||||
|
_message.Append($"{paramName}={paramValue}; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _message.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HexagonalException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HexagonalException(string message, params (string, object)[] fields)
|
||||||
|
: base(CreateBuilder(message).Append(fields).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HexagonalException(string message, HexagonalGrid grid)
|
||||||
|
: base(CreateBuilder(message).Append(grid).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HexagonalException(string message, HexagonalGrid grid, params (string, object)[] fields)
|
||||||
|
: base(CreateBuilder(message).Append(grid).Append(fields).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MessageBuilder CreateBuilder(string message)
|
||||||
|
{
|
||||||
|
return new MessageBuilder().Append(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
812
Src/HexagonalLib/src/HexagonalLib/HexagonalGrid.cs
Normal file
812
Src/HexagonalLib/src/HexagonalLib/HexagonalGrid.cs
Normal file
@@ -0,0 +1,812 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HexagonalLib.Coordinates;
|
||||||
|
using static System.Math;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represent geometry logic for infinity hexagonal grid
|
||||||
|
/// </summary>
|
||||||
|
public readonly partial struct HexagonalGrid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Total count of edges in one Hex
|
||||||
|
/// </summary>
|
||||||
|
public const int EdgesCount = 6;
|
||||||
|
|
||||||
|
public static readonly float Sqrt3 = (float) Sqrt(3);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inscribed radius of the hex
|
||||||
|
/// </summary>
|
||||||
|
public readonly float InscribedRadius;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Described radius of hex
|
||||||
|
/// </summary>
|
||||||
|
public readonly float DescribedRadius;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hexagon side length
|
||||||
|
/// </summary>
|
||||||
|
public float Side => DescribedRadius;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inscribed diameter of hex
|
||||||
|
/// </summary>
|
||||||
|
public float InscribedDiameter => InscribedRadius * 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Described diameter of hex
|
||||||
|
/// </summary>
|
||||||
|
public float DescribedDiameter => DescribedRadius * 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Orientation and layout of this grid
|
||||||
|
/// </summary>
|
||||||
|
public readonly HexagonalGridType Type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset between hex and its right-side neighbour on X axis
|
||||||
|
/// </summary>
|
||||||
|
public float HorizontalOffset
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
return InscribedRadius * 2.0f;
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
return DescribedRadius * 1.5f;
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"Can't get {nameof(HorizontalOffset)} with unexpected {nameof(Type)}", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset between hex and its up-side neighbour on Y axis
|
||||||
|
/// </summary>
|
||||||
|
public float VerticalOffset
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
return DescribedRadius * 1.5f;
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
return InscribedRadius * 2.0f;
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"Can't get {nameof(VerticalOffset)} with unexpected {nameof(Type)}", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The angle between the centers of any hex and its first neighbor relative to the vector (0, 1) clockwise
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="HexagonalException"></exception>
|
||||||
|
public float AngleToFirstNeighbor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
return 0.0f;
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
return 30.0f;
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"Can't get {nameof(AngleToFirstNeighbor)} with unexpected {nameof(Type)}", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base constructor for hexagonal grid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Orientation and layout of the grid</param>
|
||||||
|
/// <param name="radius">Inscribed radius</param>
|
||||||
|
public HexagonalGrid(HexagonalGridType type, float radius)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
InscribedRadius = radius;
|
||||||
|
DescribedRadius = (float) (radius / Cos(PI / EdgesCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region ToOffset
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert cubic coordinate to offset
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset(Cubic coord)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
{
|
||||||
|
var col = coord.X + (coord.Z - (coord.Z & 1)) / 2;
|
||||||
|
var row = coord.Z;
|
||||||
|
return new Offset(col, row);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
{
|
||||||
|
var col = coord.X + (coord.Z + (coord.Z & 1)) / 2;
|
||||||
|
var row = coord.Z;
|
||||||
|
return new Offset(col, row);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
{
|
||||||
|
var col = coord.X;
|
||||||
|
var row = coord.Z + (coord.X - (coord.X & 1)) / 2;
|
||||||
|
return new Offset(col, row);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
{
|
||||||
|
var col = coord.X;
|
||||||
|
var row = coord.Z + (coord.X + (coord.X & 1)) / 2;
|
||||||
|
return new Offset(col, row);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"{nameof(ToOffset)} failed with unexpected {nameof(Type)}", this, (nameof(coord), coord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert axial coordinate to offset
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset(Axial axial)
|
||||||
|
{
|
||||||
|
return ToOffset(ToCubic(axial));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the offset coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset(float x, float y)
|
||||||
|
{
|
||||||
|
return ToOffset(ToCubic(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the offset coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Offset ToOffset((float X, float Y) point)
|
||||||
|
{
|
||||||
|
return ToOffset(ToCubic(point.X, point.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToAxial
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert cubic coordinate to axial
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial(Cubic cubic)
|
||||||
|
{
|
||||||
|
return new Axial(cubic.X, cubic.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert offset coordinate to axial
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial(Offset offset)
|
||||||
|
{
|
||||||
|
return ToAxial(ToCubic(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the axial coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial(float x, float y)
|
||||||
|
{
|
||||||
|
return ToAxial(ToCubic(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the axial coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Axial ToAxial((float X, float Y) point)
|
||||||
|
{
|
||||||
|
return ToAxial(ToCubic(point.X, point.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToCubic
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert offset coordinate to cubic
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic(Offset coord)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
{
|
||||||
|
var x = coord.X - (coord.Y - (coord.Y & 1)) / 2;
|
||||||
|
var z = coord.Y;
|
||||||
|
var y = -x - z;
|
||||||
|
return new Cubic(x, y, z);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
{
|
||||||
|
var x = coord.X - (coord.Y + (coord.Y & 1)) / 2;
|
||||||
|
var z = coord.Y;
|
||||||
|
var y = -x - z;
|
||||||
|
return new Cubic(x, y, z);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
{
|
||||||
|
var x = coord.X;
|
||||||
|
var z = coord.Y - (coord.X - (coord.X & 1)) / 2;
|
||||||
|
var y = -x - z;
|
||||||
|
return new Cubic(x, y, z);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
{
|
||||||
|
var x = coord.X;
|
||||||
|
var z = coord.Y - (coord.X + (coord.X & 1)) / 2;
|
||||||
|
var y = -x - z;
|
||||||
|
return new Cubic(x, y, z);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"{nameof(ToCubic)} failed with unexpected {nameof(Type)}", this, (nameof(coord), coord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert axial coordinate to cubic
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic(Axial axial)
|
||||||
|
{
|
||||||
|
return new Cubic(axial.Q, -axial.Q - axial.R, axial.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cubic coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic(float x, float y)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
{
|
||||||
|
var q = (x * Sqrt3 / 3.0f - y / 3.0f) / Side;
|
||||||
|
var r = y * 2.0f / 3.0f / Side;
|
||||||
|
return new Cubic(q, -q - r, r);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
{
|
||||||
|
var q = x * 2.0f / 3.0f / Side;
|
||||||
|
var r = (-x / 3.0f + Sqrt3 / 3.0f * y) / Side;
|
||||||
|
return new Cubic(q, -q - r, r);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"{nameof(ToCubic)} failed with unexpected {nameof(Type)}", this, (nameof(x), x), (nameof(y), y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cubic coordinate of the hex which contains a point
|
||||||
|
/// </summary>
|
||||||
|
public Cubic ToCubic((float X, float Y) point)
|
||||||
|
{
|
||||||
|
return ToCubic(point.X, point.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ToPoint2
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its offset coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) ToPoint2(Offset coord)
|
||||||
|
{
|
||||||
|
return ToPoint2(ToAxial(coord));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its axial coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) ToPoint2(Axial coord)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
{
|
||||||
|
var x = Side * (Sqrt3 * coord.Q + Sqrt3 / 2 * coord.R);
|
||||||
|
var y = Side * (3.0f / 2.0f * coord.R);
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
{
|
||||||
|
var x = Side * (3.0f / 2.0f * coord.Q);
|
||||||
|
var y = Side * (Sqrt3 / 2 * coord.Q + Sqrt3 * coord.R);
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"{nameof(ToPoint2)} failed with unexpected {nameof(Type)}", this, (nameof(coord), coord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert hex based on its cubic coordinate to it center position in 2d space
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) ToPoint2(Cubic coord)
|
||||||
|
{
|
||||||
|
return ToPoint2(ToAxial(coord));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetCornerPoint
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns corner point in 2d space of given coordinate
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) GetCornerPoint(Offset coord, int edge)
|
||||||
|
{
|
||||||
|
return GetCornerPoint(coord, edge, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns corner point in 2d space of given coordinate
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) GetCornerPoint(Axial coord, int edge)
|
||||||
|
{
|
||||||
|
return GetCornerPoint(coord, edge, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns corner point in 2d space of given coordinate
|
||||||
|
/// </summary>
|
||||||
|
public (float X, float Y) GetCornerPoint(Cubic coord, int edge)
|
||||||
|
{
|
||||||
|
return GetCornerPoint(coord, edge, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns corner point in 2d space of given coordinate
|
||||||
|
/// </summary>
|
||||||
|
private (float X, float Y) GetCornerPoint<T>(T coord, int edge, Func<T, (float X, float Y)> toPoint)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
edge = NormalizeIndex(edge);
|
||||||
|
var angleDeg = 60 * edge;
|
||||||
|
if (Type == HexagonalGridType.PointyEven || Type == HexagonalGridType.PointyOdd)
|
||||||
|
{
|
||||||
|
angleDeg -= 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
var center = toPoint(coord);
|
||||||
|
var angleRad = PI / 180 * angleDeg;
|
||||||
|
var x = (float) (center.X + DescribedRadius * Cos(angleRad));
|
||||||
|
var y = (float) (center.Y + DescribedRadius * Sin(angleRad));
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetNeighbor
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the neighbor at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
public Offset GetNeighbor(Offset coord, int neighborIndex)
|
||||||
|
{
|
||||||
|
return coord + GetNeighborsOffsets(coord)[NormalizeIndex(neighborIndex)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the neighbor at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
public Axial GetNeighbor(Axial coord, int neighborIndex)
|
||||||
|
{
|
||||||
|
return coord + _axialNeighbors[NormalizeIndex(neighborIndex)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the neighbor at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
public Cubic GetNeighbor(Cubic coord, int neighborIndex)
|
||||||
|
{
|
||||||
|
return coord + _cubicNeighbors[NormalizeIndex(neighborIndex)];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetNeighbors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return all neighbors of the hex
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Offset> GetNeighbors(Offset hex)
|
||||||
|
{
|
||||||
|
foreach (var offset in GetNeighborsOffsets(hex))
|
||||||
|
{
|
||||||
|
yield return offset + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return all neighbors of the hex
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Axial> GetNeighbors(Axial hex)
|
||||||
|
{
|
||||||
|
foreach (var offset in _axialNeighbors)
|
||||||
|
{
|
||||||
|
yield return offset + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return all neighbors of the hex
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Cubic> GetNeighbors(Cubic hex)
|
||||||
|
{
|
||||||
|
foreach (var offset in _cubicNeighbors)
|
||||||
|
{
|
||||||
|
yield return offset + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IsNeighbors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two hexes are neighbors or no
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNeighbors(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return IsNeighbors(coord1, coord2, GetNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two hexes are neighbors or no
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNeighbors(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
Func<Axial, int, Axial> getNeighbor = GetNeighbor;
|
||||||
|
return IsNeighbors(coord1, coord2, getNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two hexes are neighbors or no
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNeighbors(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return IsNeighbors(coord1, coord2, GetNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two hexes are neighbors or no
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNeighbors<T>(T coord1, T coord2, in Func<T, int, T> getNeighbor)
|
||||||
|
where T : struct, IEqualityComparer<T>
|
||||||
|
{
|
||||||
|
for (var neighborIndex = 0; neighborIndex < EdgesCount; neighborIndex++)
|
||||||
|
{
|
||||||
|
var neighbor = getNeighbor(coord1, neighborIndex);
|
||||||
|
if (neighbor.Equals(coord2))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetNeighborsRing
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Offset> GetNeighborsRing(Offset center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsRing(center, radius, GetNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Axial> GetNeighborsRing(Axial center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsRing(center, radius, GetNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Cubic> GetNeighborsRing(Cubic center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsRing(center, radius, GetNeighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
private static IEnumerable<T> GetNeighborsRing<T>(T center, int radius, Func<T, int, T> getNeighbor)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (radius == 0)
|
||||||
|
{
|
||||||
|
yield return center;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < radius; i++)
|
||||||
|
{
|
||||||
|
center = getNeighbor(center, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < radius; j++)
|
||||||
|
{
|
||||||
|
yield return center;
|
||||||
|
center = getNeighbor(center, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetNeighborsAround
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a all hexes in the ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Offset> GetNeighborsAround(Offset center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsAround(center, radius, GetNeighborsRing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a all hexes in the ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Axial> GetNeighborsAround(Axial center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsAround(center, radius, GetNeighborsRing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a all hexes in the ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Cubic> GetNeighborsAround(Cubic center, int radius)
|
||||||
|
{
|
||||||
|
return GetNeighborsAround(center, radius, GetNeighborsRing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a all hexes in the ring with a radius of <see cref="radius"/> hexes around the given <see cref="center"/>.
|
||||||
|
/// </summary>
|
||||||
|
private static IEnumerable<T> GetNeighborsAround<T>(T center, int radius, Func<T, int, IEnumerable<T>> getNeighborRing)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
for (var i = 0; i < radius; i++)
|
||||||
|
{
|
||||||
|
foreach (var hex in getNeighborRing(center, i))
|
||||||
|
{
|
||||||
|
yield return hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetNeighborIndex
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the bypass index to the specified neighbor
|
||||||
|
/// </summary>
|
||||||
|
public byte GetNeighborIndex(Offset center, Offset neighbor)
|
||||||
|
{
|
||||||
|
return GetNeighborIndex(center, neighbor, GetNeighbors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the bypass index to the specified neighbor
|
||||||
|
/// </summary>
|
||||||
|
public byte GetNeighborIndex(Axial center, Axial neighbor)
|
||||||
|
{
|
||||||
|
return GetNeighborIndex(center, neighbor, GetNeighbors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the bypass index to the specified neighbor
|
||||||
|
/// </summary>
|
||||||
|
public byte GetNeighborIndex(Cubic center, Cubic neighbor)
|
||||||
|
{
|
||||||
|
return GetNeighborIndex(center, neighbor, GetNeighbors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the bypass index to the specified neighbor
|
||||||
|
/// </summary>
|
||||||
|
private byte GetNeighborIndex<T>(T center, T neighbor, Func<T, IEnumerable<T>> getNeighbors)
|
||||||
|
where T : struct, IEqualityComparer<T>
|
||||||
|
{
|
||||||
|
byte neighborIndex = 0;
|
||||||
|
foreach (var current in getNeighbors(center))
|
||||||
|
{
|
||||||
|
if (current.Equals(neighbor))
|
||||||
|
{
|
||||||
|
return neighborIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
neighborIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HexagonalException($"Can't find bypass index", this, (nameof(center), center), (nameof(neighbor), neighbor));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetPointBetweenTwoNeighbours
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the midpoint of the boundary segment of two neighbors
|
||||||
|
/// </summary>
|
||||||
|
public (float x, float y) GetPointBetweenTwoNeighbours(Offset coord1, Offset coord2)
|
||||||
|
{
|
||||||
|
return GetPointBetweenTwoNeighbours(coord1, coord2, IsNeighbors, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the midpoint of the boundary segment of two neighbors
|
||||||
|
/// </summary>
|
||||||
|
public (float x, float y) GetPointBetweenTwoNeighbours(Axial coord1, Axial coord2)
|
||||||
|
{
|
||||||
|
return GetPointBetweenTwoNeighbours(coord1, coord2, IsNeighbors, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the midpoint of the boundary segment of two neighbors
|
||||||
|
/// </summary>
|
||||||
|
public (float x, float y) GetPointBetweenTwoNeighbours(Cubic coord1, Cubic coord2)
|
||||||
|
{
|
||||||
|
return GetPointBetweenTwoNeighbours(coord1, coord2, IsNeighbors, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the midpoint of the boundary segment of two neighbors
|
||||||
|
/// </summary>
|
||||||
|
private (float x, float y) GetPointBetweenTwoNeighbours<T>(T coord1, T coord2, Func<T, T, bool> isNeighbor, Func<T, (float X, float Y)> toPoint)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (!isNeighbor(coord1, coord2))
|
||||||
|
{
|
||||||
|
throw new HexagonalException($"Can't calculate point between not neighbors", this, (nameof(coord1), coord1), (nameof(coord2), coord2));
|
||||||
|
}
|
||||||
|
|
||||||
|
var c1 = toPoint(coord1);
|
||||||
|
var c2 = toPoint(coord2);
|
||||||
|
|
||||||
|
return ((c1.X + c2.X) / 2, (c1.Y + c2.Y) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region CubeDistance
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manhattan distance between two hexes
|
||||||
|
/// </summary>
|
||||||
|
public int CubeDistance(Offset h1, Offset h2)
|
||||||
|
{
|
||||||
|
var cubicFrom = ToCubic(h1);
|
||||||
|
var cubicTo = ToCubic(h2);
|
||||||
|
return CubeDistance(cubicFrom, cubicTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manhattan distance between two hexes
|
||||||
|
/// </summary>
|
||||||
|
public int CubeDistance(Axial h1, Axial h2)
|
||||||
|
{
|
||||||
|
var cubicFrom = ToCubic(h1);
|
||||||
|
var cubicTo = ToCubic(h2);
|
||||||
|
return CubeDistance(cubicFrom, cubicTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manhattan distance between two hexes
|
||||||
|
/// </summary>
|
||||||
|
public static int CubeDistance(Cubic h1, Cubic h2)
|
||||||
|
{
|
||||||
|
return (Abs(h1.X - h2.X) + Abs(h1.Y - h2.Y) + Abs(h1.Z - h2.Z)) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Neighbors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return all neighbors offsets of the hex
|
||||||
|
/// </summary>
|
||||||
|
private IReadOnlyList<Offset> GetNeighborsOffsets(Offset coord)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case HexagonalGridType.PointyOdd:
|
||||||
|
return Abs(coord.Y % 2) == 0 ? _pointyEvenNeighbors : _pointyOddNeighbors;
|
||||||
|
case HexagonalGridType.PointyEven:
|
||||||
|
return Abs(coord.Y % 2) == 1 ? _pointyEvenNeighbors : _pointyOddNeighbors;
|
||||||
|
case HexagonalGridType.FlatOdd:
|
||||||
|
return Abs(coord.X % 2) == 0 ? _flatEvenNeighbors : _flatOddNeighbors;
|
||||||
|
case HexagonalGridType.FlatEven:
|
||||||
|
return Abs(coord.X % 2) == 1 ? _flatEvenNeighbors : _flatOddNeighbors;
|
||||||
|
default:
|
||||||
|
throw new HexagonalException($"{nameof(GetNeighborsOffsets)} failed with unexpected {nameof(Type)}", this, (nameof(coord), coord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly List<Offset> _pointyOddNeighbors = new List<Offset>
|
||||||
|
{
|
||||||
|
new Offset(+1, 0), new Offset(+1, -1), new Offset(0, -1),
|
||||||
|
new Offset(-1, 0), new Offset(0, +1), new Offset(+1, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly List<Offset> _pointyEvenNeighbors = new List<Offset>
|
||||||
|
{
|
||||||
|
new Offset(+1, 0), new Offset(0, -1), new Offset(-1, -1),
|
||||||
|
new Offset(-1, 0), new Offset(-1, +1), new Offset(0, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly List<Offset> _flatOddNeighbors = new List<Offset>
|
||||||
|
{
|
||||||
|
new Offset(+1, +1), new Offset(+1, 0), new Offset(0, -1),
|
||||||
|
new Offset(-1, 0), new Offset(-1, +1), new Offset(0, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly List<Offset> _flatEvenNeighbors = new List<Offset>
|
||||||
|
{
|
||||||
|
new Offset(+1, 0), new Offset(+1, -1), new Offset(0, -1),
|
||||||
|
new Offset(-1, -1), new Offset(-1, 0), new Offset(0, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly List<Axial> _axialNeighbors = new List<Axial>
|
||||||
|
{
|
||||||
|
new Axial(+1, 0), new Axial(+1, -1), new Axial(0, -1),
|
||||||
|
new Axial(-1, 0), new Axial(-1, +1), new Axial(0, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly List<Cubic> _cubicNeighbors = new List<Cubic>
|
||||||
|
{
|
||||||
|
new Cubic(+1, -1, 0), new Cubic(+1, 0, -1), new Cubic(0, +1, -1),
|
||||||
|
new Cubic(-1, +1, 0), new Cubic(-1, 0, +1), new Cubic(0, -1, +1),
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static int NormalizeIndex(int index)
|
||||||
|
{
|
||||||
|
index = index % EdgesCount;
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
index += EdgesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
189
Src/HexagonalLib/src/HexagonalLib/HexagonalGridMesh.cs
Normal file
189
Src/HexagonalLib/src/HexagonalLib/HexagonalGridMesh.cs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HexagonalLib.Coordinates;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
public readonly partial struct HexagonalGrid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate count of vertices and indices needed for build mesh.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hexesCount">Count on hexes in mesh</param>
|
||||||
|
/// <param name="subdivide">Count of triangles splits for each hex</param>
|
||||||
|
public (int VerticesCount, int IndicesCount) GetMeshData(int hexesCount, int subdivide)
|
||||||
|
{
|
||||||
|
// Calculate number of vertices we need to generate
|
||||||
|
// numVertices = 1 + Σ {S, i = 1} (i * 6)
|
||||||
|
var numVertices = 1;
|
||||||
|
|
||||||
|
// Calculate number of indices we need to generate
|
||||||
|
// numIndices = Σ {S, i = 1} (36 * i - 18)
|
||||||
|
var numIndices = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i <= subdivide; i++)
|
||||||
|
{
|
||||||
|
numVertices += i * 6;
|
||||||
|
numIndices += 36 * i - 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (numVertices * hexesCount, numIndices * hexesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public void CreateMesh(IEnumerable<Offset> hexes, int subdivide, Action<int, (float X, float Y)> setVertex, Action<int, int> setIndex)
|
||||||
|
{
|
||||||
|
CreateMesh(hexes, subdivide, setVertex, setIndex, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public void CreateMesh(IEnumerable<Axial> hexes, int subdivide, Action<int, (float X, float Y)> setVertex, Action<int, int> setIndex)
|
||||||
|
{
|
||||||
|
CreateMesh(hexes, subdivide, setVertex, setIndex, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// </summary>
|
||||||
|
public void CreateMesh(IEnumerable<Cubic> hexes, int subdivide, Action<int, (float X, float Y)> setVertex, Action<int, int> setIndex)
|
||||||
|
{
|
||||||
|
CreateMesh(hexes, subdivide, setVertex, setIndex, ToPoint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for list of hex. The generation algorithm is taken from the site:
|
||||||
|
/// http://www.voidinspace.com/2014/07/project-twa-part-1-generating-a-hexagonal-tile-and-its-triangular-grid/
|
||||||
|
/// </summary>
|
||||||
|
private void CreateMesh<T>(IEnumerable<T> hexes, int subdivide, Action<int, (float X, float Y)> setVertex, Action<int, int> setIndex, Func<T, (float X, float Y)> toPoint)
|
||||||
|
{
|
||||||
|
var vertex = 0;
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
var data = GetMeshData(1, subdivide);
|
||||||
|
|
||||||
|
foreach (var hex in hexes)
|
||||||
|
{
|
||||||
|
var localVertex = vertex;
|
||||||
|
var localIndex = index;
|
||||||
|
var center = toPoint(hex);
|
||||||
|
|
||||||
|
void setVertexLocal(int i, (float X, float Y) currentVertex)
|
||||||
|
{
|
||||||
|
var (x, y) = currentVertex;
|
||||||
|
var shifted = (x + center.X, y + center.Y);
|
||||||
|
setVertex(localVertex + i, shifted);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIndexLocal(int i, int currentIndex) => setIndex(localIndex + i, localVertex + currentIndex);
|
||||||
|
|
||||||
|
CreateMesh(subdivide, setVertexLocal, setIndexLocal);
|
||||||
|
|
||||||
|
vertex += data.VerticesCount;
|
||||||
|
index += data.IndicesCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mesh for one hex. The generation algorithm is taken from the site:
|
||||||
|
/// http://www.voidinspace.com/2014/07/project-twa-part-1-generating-a-hexagonal-tile-and-its-triangular-grid/
|
||||||
|
/// </summary>
|
||||||
|
public void CreateMesh(int subdivide, Action<int, (float X, float Y)> setVertex, Action<int, int> setIndex)
|
||||||
|
{
|
||||||
|
// We'll need those later to generate our x, z coordinates
|
||||||
|
var radius = InscribedRadius / (float) Math.Cos(Math.PI / 6);
|
||||||
|
var sin60 = (float) Math.Sin(Math.PI / 3);
|
||||||
|
var invTan60 = 1.0f / (float) Math.Tan(Math.PI / 3.0f);
|
||||||
|
var rdq = radius / subdivide;
|
||||||
|
|
||||||
|
var verticesIndex = 0;
|
||||||
|
var indicesIndex = 0;
|
||||||
|
|
||||||
|
// We'll need those to calculate our indices
|
||||||
|
var currentNumPoints = 0;
|
||||||
|
var prevRowNumPoints = 0;
|
||||||
|
|
||||||
|
// [colMin, colMax]
|
||||||
|
var npCol0 = 2 * subdivide + 1;
|
||||||
|
var colMin = -subdivide;
|
||||||
|
var colMax = subdivide;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now let's generate the grid
|
||||||
|
// First we'll iterate through the Columns, starting from the bottom (fA)
|
||||||
|
for (var itC = colMin; itC <= colMax; itC++)
|
||||||
|
{
|
||||||
|
// Calculate z for this row
|
||||||
|
// That's the same for each point in this column
|
||||||
|
var x = sin60 * rdq * itC;
|
||||||
|
|
||||||
|
// Calculate how many points (z values) we need to generate on for this column
|
||||||
|
var npColI = npCol0 - Math.Abs(itC);
|
||||||
|
|
||||||
|
// [rowMin, rowMax]
|
||||||
|
var rowMin = -subdivide;
|
||||||
|
if (itC < 0)
|
||||||
|
{
|
||||||
|
rowMin += Math.Abs(itC);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowMax = rowMin + npColI - 1;
|
||||||
|
|
||||||
|
// We need this for the indices
|
||||||
|
currentNumPoints += npColI;
|
||||||
|
|
||||||
|
// Iterate through the Rows (fB)
|
||||||
|
for (var itR = rowMin; itR <= rowMax; itR++)
|
||||||
|
{
|
||||||
|
// Calculate z
|
||||||
|
var z = invTan60 * x + rdq * itR;
|
||||||
|
setVertex(verticesIndex, (x, z).Rotate(AngleToFirstNeighbor));
|
||||||
|
|
||||||
|
// Indices
|
||||||
|
// From each point we'll try to create triangles left and right
|
||||||
|
if (verticesIndex < (currentNumPoints - 1))
|
||||||
|
{
|
||||||
|
// Triangles left from this column
|
||||||
|
if (itC >= colMin && itC < colMax)
|
||||||
|
{
|
||||||
|
// To get the point above
|
||||||
|
var padLeft = 0;
|
||||||
|
if (itC < 0)
|
||||||
|
{
|
||||||
|
padLeft = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIndex(indicesIndex++, verticesIndex + npColI + padLeft);
|
||||||
|
setIndex(indicesIndex++, verticesIndex + 1);
|
||||||
|
setIndex(indicesIndex++, verticesIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangles right from this column
|
||||||
|
if (itC > colMin && itC <= colMax)
|
||||||
|
{
|
||||||
|
// To get point bellow
|
||||||
|
var padRight = 0;
|
||||||
|
if (itC > 0)
|
||||||
|
{
|
||||||
|
padRight = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIndex(indicesIndex++, verticesIndex - prevRowNumPoints + padRight);
|
||||||
|
setIndex(indicesIndex++, verticesIndex);
|
||||||
|
setIndex(indicesIndex++, verticesIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next vertex...
|
||||||
|
verticesIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the previous row number of points, used to calculate the index buffer
|
||||||
|
prevRowNumPoints = npColI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Src/HexagonalLib/src/HexagonalLib/HexagonalGridType.cs
Normal file
28
Src/HexagonalLib/src/HexagonalLib/HexagonalGridType.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The typical layouts and orientations for hex grids
|
||||||
|
/// </summary>
|
||||||
|
public enum HexagonalGridType : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Horizontal layout shoves odd rows right [odd-r]
|
||||||
|
/// </summary>
|
||||||
|
PointyOdd,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Horizontal layout shoves even rows right [even-r]
|
||||||
|
/// </summary>
|
||||||
|
PointyEven,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertical layout shoves odd columns down [odd-q]
|
||||||
|
/// </summary>
|
||||||
|
FlatOdd,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertical layout shoves even columns down [even-q]
|
||||||
|
/// </summary>
|
||||||
|
FlatEven,
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Src/HexagonalLib/src/HexagonalLib/HexagonalLib.projitems
Normal file
21
Src/HexagonalLib/src/HexagonalLib/HexagonalLib.projitems
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||||
|
<HasSharedItems>true</HasSharedItems>
|
||||||
|
<SharedGUID>1FDA753A-7694-41B7-8C00-AA39FD0780CA</SharedGUID>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<Import_RootNamespace>HexagonalLib</Import_RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Coordinates\Axial.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Coordinates\Cubic.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Coordinates\Offset.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)HexagonalException.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)HexagonalGrid.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)HexagonalGridMesh.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)HexagonalGridType.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)HexagonalMath.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
18
Src/HexagonalLib/src/HexagonalLib/HexagonalLib.shproj
Normal file
18
Src/HexagonalLib/src/HexagonalLib/HexagonalLib.shproj
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{30905D5D-8D2E-4A25-ABEB-B4B4B0C440E6}</ProjectGuid>
|
||||||
|
<AssemblyName>HexagonalLib</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
|
||||||
|
<Import Project="HexagonalLib.projitems" Label="Shared" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
47
Src/HexagonalLib/src/HexagonalLib/HexagonalMath.cs
Normal file
47
Src/HexagonalLib/src/HexagonalLib/HexagonalMath.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace HexagonalLib
|
||||||
|
{
|
||||||
|
public static partial class HexagonalMath
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Rotate 2d vector around z Axis clockwise
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vector">Vector to rotate</param>
|
||||||
|
/// <param name="degrees">Angle of rotation</param>
|
||||||
|
public static (float X, float Y) Rotate(this in (float X, float Y) vector, float degrees)
|
||||||
|
{
|
||||||
|
var radians = Math.PI / 180.0 * degrees;
|
||||||
|
var sin = Math.Sin(radians);
|
||||||
|
var cos = Math.Cos(radians);
|
||||||
|
var x = (float) Math.Round(cos * vector.X - sin * vector.Y, 6);
|
||||||
|
var y = (float) Math.Round(sin * vector.X + cos * vector.Y, 6);
|
||||||
|
return (-x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this vector with a magnitude of 1
|
||||||
|
/// </summary>
|
||||||
|
public static (float X, float Y) Normalize(this in (float X, float Y) vector)
|
||||||
|
{
|
||||||
|
var distance = Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y);
|
||||||
|
return ((float) (vector.X / distance), (float) (vector.Y / distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two floating point values and returns true if they are similar.
|
||||||
|
/// </summary>
|
||||||
|
public static bool SimilarTo(this in float a, in float b)
|
||||||
|
{
|
||||||
|
return Math.Abs(b - a) < (double) Math.Max(1E-06f * Math.Max(Math.Abs(a), Math.Abs(b)), float.Epsilon * 8f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two vectors and returns true if they are similar.
|
||||||
|
/// </summary>
|
||||||
|
public static bool SimilarTo(this in (float X, float Y) a, in (float X, float Y) b)
|
||||||
|
{
|
||||||
|
return a.X.SimilarTo(b.X) && a.Y.SimilarTo(b.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Src/HexagonalLib/src/nuget.config
Normal file
5
Src/HexagonalLib/src/nuget.config
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<configuration>
|
||||||
|
<config>
|
||||||
|
<add key="repositoryPath" value=".packages" />
|
||||||
|
</config>
|
||||||
|
</configuration>
|
||||||
12
Tests/Giants.Core.Tests/ApplicationTests.cs
Normal file
12
Tests/Giants.Core.Tests/ApplicationTests.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Giants.Core.Tests;
|
||||||
|
|
||||||
|
using Giants.Application;
|
||||||
|
|
||||||
|
public class ApplicationTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ApplicationCreationExample()
|
||||||
|
{
|
||||||
|
GiantApplication app = new GiantApplication();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Tests/Giants.Core.Tests/Giants.Core.Tests.csproj
Normal file
26
Tests/Giants.Core.Tests/Giants.Core.Tests.csproj
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Src\Giants.Core\Giants.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Src\Giants.Application\Giants.Application.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user