2015-11-27 17:16:33 +01:00
|
|
|
|
using System;
|
2022-10-04 11:53:07 +08:00
|
|
|
|
using System.Globalization;
|
2022-08-28 14:57:44 +08:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2015-11-27 17:16:33 +01:00
|
|
|
|
|
|
|
|
|
|
namespace MinecraftClient.Mapping
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represents a location into a Minecraft world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public struct Location
|
|
|
|
|
|
{
|
2022-10-02 13:49:36 +08:00
|
|
|
|
public static readonly Location Zero = new(0, 0, 0);
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The X Coordinate
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double X;
|
2022-08-18 20:58:49 +02:00
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Y Coordinate (vertical)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double Y;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Z coordinate
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double Z;
|
|
|
|
|
|
|
2022-12-06 15:50:17 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Identifies whether the coordinates are absolute or relative.
|
|
|
|
|
|
/// true for relative coordinates, false for absolute coordinates.
|
|
|
|
|
|
/// X-axis: ((Status & (1 << 0)) > 0)
|
|
|
|
|
|
/// Y-axis: ((Status & (1 << 1)) > 0)
|
|
|
|
|
|
/// Z-axis: ((Status & (1 << 2)) > 0)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public byte Status;
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create a new location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Location(double x, double y, double z)
|
|
|
|
|
|
{
|
|
|
|
|
|
X = x;
|
|
|
|
|
|
Y = y;
|
|
|
|
|
|
Z = z;
|
2022-12-06 15:50:17 +08:00
|
|
|
|
Status = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create a new location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Location(double x, double y, double z, byte status)
|
|
|
|
|
|
{
|
|
|
|
|
|
X = x;
|
|
|
|
|
|
Y = y;
|
|
|
|
|
|
Z = z;
|
|
|
|
|
|
Status = status;
|
2015-11-27 17:16:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-05 22:03:47 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create a new location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Location(Location loc)
|
|
|
|
|
|
{
|
|
|
|
|
|
X = loc.X;
|
|
|
|
|
|
Y = loc.Y;
|
|
|
|
|
|
Z = loc.Z;
|
2022-12-06 15:50:17 +08:00
|
|
|
|
Status = loc.Status;
|
2022-09-05 22:03:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-12-08 00:34:40 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create a new location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="chunkX">Location of the chunk into the world</param>
|
|
|
|
|
|
/// <param name="chunkZ">Location of the chunk into the world</param>
|
|
|
|
|
|
/// <param name="blockX">Location of the block into the chunk</param>
|
|
|
|
|
|
/// <param name="blockY">Location of the block into the world</param>
|
|
|
|
|
|
/// <param name="blockZ">Location of the block into the chunk</param>
|
2022-08-30 17:37:46 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2015-12-08 00:34:40 +01:00
|
|
|
|
public Location(int chunkX, int chunkZ, int blockX, int blockY, int blockZ)
|
|
|
|
|
|
{
|
|
|
|
|
|
X = chunkX * Chunk.SizeX + blockX;
|
|
|
|
|
|
Y = blockY;
|
|
|
|
|
|
Z = chunkZ * Chunk.SizeZ + blockZ;
|
2022-12-06 15:50:17 +08:00
|
|
|
|
Status = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Location ToAbsolute(Location based)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((Status & (1 << 0)) > 0)
|
|
|
|
|
|
X += based.X;
|
|
|
|
|
|
if ((Status & (1 << 1)) > 0)
|
|
|
|
|
|
Y += based.Y;
|
|
|
|
|
|
if ((Status & (1 << 2)) > 0)
|
|
|
|
|
|
Z += based.Z;
|
|
|
|
|
|
Status = 0;
|
|
|
|
|
|
return this;
|
2015-12-08 00:34:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-29 22:49:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse location from the string.
|
2022-10-17 20:00:33 +08:00
|
|
|
|
/// throw FormatException if the parsing fails.
|
2022-09-29 22:49:07 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="x">The string representation of the X-axis coordinate.</param>
|
|
|
|
|
|
/// <param name="y">The string representation of the Y-axis coordinate.</param>
|
|
|
|
|
|
/// <param name="z">The string representation of the Z-axis coordinate.</param>
|
|
|
|
|
|
/// <returns>The location represented by the string.</returns>
|
|
|
|
|
|
public static Location Parse(string x, string y, string z)
|
|
|
|
|
|
{
|
|
|
|
|
|
Location.TryParse(x, y, z, out Location? res);
|
|
|
|
|
|
if (res == null)
|
|
|
|
|
|
throw new FormatException();
|
|
|
|
|
|
else
|
|
|
|
|
|
return (Location)res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool TryParse(string x, string y, string z, out Location? location)
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] coord_str = new string[] { x.Trim(), y.Trim(), z.Trim() };
|
|
|
|
|
|
double[] coord_res = new double[3];
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
|
|
{
|
2022-10-04 11:53:07 +08:00
|
|
|
|
if (!double.TryParse(coord_str[i], NumberStyles.Any, CultureInfo.CurrentCulture, out coord_res[i]))
|
2022-09-29 22:49:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
location = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
location = new Location(coord_res[0], coord_res[1], coord_res[2]);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse location from the string (relative coordinate representation is supported).
|
2022-10-17 20:00:33 +08:00
|
|
|
|
/// throw FormatException if the parsing fails.
|
2022-09-29 22:49:07 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="current">Relative position base point.</param>
|
|
|
|
|
|
/// <param name="x">The string representation of the X-axis coordinate.</param>
|
|
|
|
|
|
/// <param name="y">The string representation of the Y-axis coordinate.</param>
|
|
|
|
|
|
/// <param name="z">The string representation of the Z-axis coordinate.</param>
|
|
|
|
|
|
/// <returns>The location represented by the string.</returns>
|
|
|
|
|
|
public static Location Parse(Location current, string x, string y, string z)
|
|
|
|
|
|
{
|
|
|
|
|
|
Location.TryParse(current, x, y, z, out Location? res);
|
|
|
|
|
|
if (res == null)
|
|
|
|
|
|
throw new FormatException();
|
|
|
|
|
|
else
|
|
|
|
|
|
return (Location)res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool TryParse(Location current, string x, string y, string z, out Location? location)
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] coord_str = new string[] { x.Trim(), y.Trim(), z.Trim() };
|
|
|
|
|
|
double[] coord_res = new double[3];
|
|
|
|
|
|
double[] coord_cur = new double[] { current.X, current.Y, current.Z };
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (coord_str[i].StartsWith('~'))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (coord_str[i].Length > 1)
|
|
|
|
|
|
{
|
2022-10-04 11:53:07 +08:00
|
|
|
|
if (!double.TryParse(coord_str[i][1..], NumberStyles.Any, CultureInfo.CurrentCulture, out coord_res[i]))
|
2022-09-29 22:49:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
location = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
coord_res[i] += coord_cur[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
coord_res[i] = coord_cur[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2022-10-04 11:53:07 +08:00
|
|
|
|
if (!double.TryParse(coord_str[i], NumberStyles.Any, CultureInfo.CurrentCulture, out coord_res[i]))
|
2022-09-29 22:49:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
location = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
location = new Location(coord_res[0], coord_res[1], coord_res[2]);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-25 14:36:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Round coordinates
|
|
|
|
|
|
/// </summary>
|
2022-09-09 16:13:25 +08:00
|
|
|
|
/// <returns>New location</returns>
|
|
|
|
|
|
public Location ToFloor()
|
2022-08-25 14:36:15 +08:00
|
|
|
|
{
|
2022-10-02 18:31:08 +08:00
|
|
|
|
return new Location(Math.Floor(X), Math.Floor(Y), Math.Floor(Z));
|
2022-08-25 14:36:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get the center coordinates
|
|
|
|
|
|
/// </summary>
|
2022-09-09 16:13:25 +08:00
|
|
|
|
/// <returns>New location</returns>
|
|
|
|
|
|
public Location ToCenter()
|
2022-08-25 14:36:15 +08:00
|
|
|
|
{
|
2022-10-02 18:31:08 +08:00
|
|
|
|
return new Location(Math.Floor(X) + 0.5, Y, Math.Floor(Z) + 0.5);
|
2022-08-25 14:36:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-30 15:30:49 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The X index of the corresponding chunk in the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkX
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2015-12-08 00:34:40 +01:00
|
|
|
|
return (int)Math.Floor(X / Chunk.SizeX);
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Y index of the corresponding chunk in the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkY
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2022-08-18 20:58:49 +02:00
|
|
|
|
return (int)Math.Floor((Y - World.GetDimension().minY) / Chunk.SizeY);
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Z index of the corresponding chunk in the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkZ
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2015-12-08 00:34:40 +01:00
|
|
|
|
return (int)Math.Floor(Z / Chunk.SizeZ);
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The X index of the corresponding block in the corresponding chunk of the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkBlockX
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2015-12-08 00:34:40 +01:00
|
|
|
|
return ((int)Math.Floor(X) % Chunk.SizeX + Chunk.SizeX) % Chunk.SizeX;
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Y index of the corresponding block in the corresponding chunk of the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkBlockY
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2015-12-08 00:34:40 +01:00
|
|
|
|
return ((int)Math.Floor(Y) % Chunk.SizeY + Chunk.SizeY) % Chunk.SizeY;
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The Z index of the corresponding block in the corresponding chunk of the world
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int ChunkBlockZ
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2015-12-08 00:34:40 +01:00
|
|
|
|
return ((int)Math.Floor(Z) % Chunk.SizeZ + Chunk.SizeZ) % Chunk.SizeZ;
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-12-12 16:48:29 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get a squared distance to the specified location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">Other location for computing distance</param>
|
|
|
|
|
|
/// <returns>Distance to the specified location, without using a square root</returns>
|
|
|
|
|
|
public double DistanceSquared(Location location)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((X - location.X) * (X - location.X))
|
|
|
|
|
|
+ ((Y - location.Y) * (Y - location.Y))
|
|
|
|
|
|
+ ((Z - location.Z) * (Z - location.Z));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get exact distance to the specified location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">Other location for computing distance</param>
|
|
|
|
|
|
/// <returns>Distance to the specified location, with square root so lower performances</returns>
|
|
|
|
|
|
public double Distance(Location location)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Math.Sqrt(DistanceSquared(location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-24 00:06:52 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Considering the current location as Feet location, calculate Eyes location
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>Player Eyes location</returns>
|
|
|
|
|
|
public Location EyesLocation()
|
|
|
|
|
|
{
|
|
|
|
|
|
return this + new Location(0, 1.62, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="obj">Object to compare to</param>
|
|
|
|
|
|
/// <returns>TRUE if the locations are equals</returns>
|
2022-10-02 18:31:08 +08:00
|
|
|
|
public override bool Equals(object? obj)
|
2015-11-27 17:16:33 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (obj == null)
|
|
|
|
|
|
return false;
|
2022-10-02 18:31:08 +08:00
|
|
|
|
if (obj is Location location)
|
2015-11-27 17:16:33 +01:00
|
|
|
|
{
|
2022-10-02 18:31:08 +08:00
|
|
|
|
return ((int)X) == ((int)location.X)
|
|
|
|
|
|
&& ((int)Y) == ((int)location.Y)
|
|
|
|
|
|
&& ((int)Z) == ((int)location.Z);
|
2015-11-27 17:16:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="loc1">First location to compare</param>
|
|
|
|
|
|
/// <param name="loc2">Second location to compare</param>
|
|
|
|
|
|
/// <returns>TRUE if the locations are equals</returns>
|
2015-12-12 16:48:29 +01:00
|
|
|
|
public static bool operator ==(Location loc1, Location loc2)
|
2022-10-02 18:31:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
return loc1.Equals(loc2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Compare two locations. Locations are not equals if the integer part of their coordinates are not equals.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="loc1">First location to compare</param>
|
|
|
|
|
|
/// <param name="loc2">Second location to compare</param>
|
|
|
|
|
|
/// <returns>TRUE if the locations are equals</returns>
|
2015-12-12 16:48:29 +01:00
|
|
|
|
public static bool operator !=(Location loc1, Location loc2)
|
2022-10-02 18:31:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
return !loc1.Equals(loc2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Sums two locations and returns the result.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <exception cref="NullReferenceException">
|
|
|
|
|
|
/// Thrown if one of the provided location is null
|
|
|
|
|
|
/// </exception>
|
|
|
|
|
|
/// <param name="loc1">First location to sum</param>
|
|
|
|
|
|
/// <param name="loc2">Second location to sum</param>
|
|
|
|
|
|
/// <returns>Sum of the two locations</returns>
|
2015-12-12 16:48:29 +01:00
|
|
|
|
public static Location operator +(Location loc1, Location loc2)
|
2015-11-27 17:16:33 +01:00
|
|
|
|
{
|
|
|
|
|
|
return new Location
|
|
|
|
|
|
(
|
|
|
|
|
|
loc1.X + loc2.X,
|
|
|
|
|
|
loc1.Y + loc2.Y,
|
|
|
|
|
|
loc1.Z + loc2.Z
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-12-12 16:48:29 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Substract a location to another
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <exception cref="NullReferenceException">
|
|
|
|
|
|
/// Thrown if one of the provided location is null
|
|
|
|
|
|
/// </exception>
|
|
|
|
|
|
/// <param name="loc1">First location</param>
|
|
|
|
|
|
/// <param name="loc2">Location to substract to the first one</param>
|
|
|
|
|
|
/// <returns>Sum of the two locations</returns>
|
|
|
|
|
|
public static Location operator -(Location loc1, Location loc2)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new Location
|
|
|
|
|
|
(
|
|
|
|
|
|
loc1.X - loc2.X,
|
|
|
|
|
|
loc1.Y - loc2.Y,
|
|
|
|
|
|
loc1.Z - loc2.Z
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Multiply a location by a scalar value
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="loc">Location to multiply</param>
|
|
|
|
|
|
/// <param name="val">Scalar value</param>
|
|
|
|
|
|
/// <returns>Product of the location and the scalar value</returns>
|
|
|
|
|
|
public static Location operator *(Location loc, double val)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new Location
|
|
|
|
|
|
(
|
|
|
|
|
|
loc.X * val,
|
|
|
|
|
|
loc.Y * val,
|
|
|
|
|
|
loc.Z * val
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Divide a location by a scalar value
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="loc">Location to divide</param>
|
|
|
|
|
|
/// <param name="val">Scalar value</param>
|
|
|
|
|
|
/// <returns>Result of the division</returns>
|
|
|
|
|
|
public static Location operator /(Location loc, double val)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new Location
|
|
|
|
|
|
(
|
|
|
|
|
|
loc.X / val,
|
|
|
|
|
|
loc.Y / val,
|
|
|
|
|
|
loc.Z / val
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-27 17:16:33 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// DO NOT USE. Defined to comply with C# requirements requiring a GetHashCode() when overriding Equals() or ==
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// A modulo will be applied if the location is outside the following ranges:
|
|
|
|
|
|
/// X: -4096 to +4095
|
|
|
|
|
|
/// Y: -32 to +31
|
|
|
|
|
|
/// Z: -4096 to +4095
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <returns>A simplified version of the location</returns>
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
|
{
|
|
|
|
|
|
return (((int)X) & ~((~0) << 13)) << 19
|
|
|
|
|
|
| (((int)Y) & ~((~0) << 13)) << 13
|
|
|
|
|
|
| (((int)Z) & ~((~0) << 06)) << 00;
|
|
|
|
|
|
}
|
2015-11-30 15:30:49 +01:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Convert the location into a string representation
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>String representation of the location</returns>
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
|
{
|
2022-07-25 18:11:10 +08:00
|
|
|
|
return String.Format("X:{0:0.00} Y:{1:0.00} Z:{2:0.00}", X, Y, Z);
|
2015-11-30 15:30:49 +01:00
|
|
|
|
}
|
2015-11-27 17:16:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|