Пример #1
0
        public void OperatorOverloadPlus()
        {
            Vec2D point = new Vec2D( 1f, 2f ) + new Vec2D( 3f, 4f );

            Assert.That( point.x, Is.InRange<float>( 4f - EPSILON, 4f + EPSILON ) );
            Assert.That( point.y, Is.InRange<float>( 6f - EPSILON, 6f + EPSILON ) );
        }
Пример #2
0
        public void ConstructorXZ()
        {
            Vec2D point = new Vec2D( 1f, 2f );

            Assert.That( point.x, Is.EqualTo( 1f ) );
            Assert.That( point.y, Is.EqualTo( 2f ) );
        }
Пример #3
0
        public void OperatorOverloadMinus()
        {
            Vec2D point = new Vec2D( 4f, 3f ) - new Vec2D( 1f, 2f );

            Assert.That( point.x, Is.InRange<float>( 3f - EPSILON, 3f + EPSILON ) );
            Assert.That( point.y, Is.InRange<float>( 1f - EPSILON, 1f + EPSILON ) );
        }
Пример #4
0
        public void ConstructorParameterless()
        {
            Vec2D point = new Vec2D();

            Assert.That( point.x, Is.EqualTo( 0f ) );
            Assert.That( point.y, Is.EqualTo( 0f ) );
        }
Пример #5
0
        public void Length()
        {
            Vec2D point = new Vec2D( 2, 2 );

            float length = point.Length();
            float expected = (float)( 2 * Math.Sqrt( 2 ) );

            Assert.That( length, Is.InRange<float>( expected - EPSILON, expected + EPSILON ) );
        }
Пример #6
0
        public void Distance()
        {
            Vec2D point1 = new Vec2D( 1, 1 );
            Vec2D point2 = new Vec2D( 3, 3 );

            float length = point1.Distance( point2 );
            float expected = (float)( 2 * Math.Sqrt( 2 ) );

            Assert.That( length, Is.InRange<float>( expected - EPSILON, expected + EPSILON ) );
        }
Пример #7
0
        /// <summary>
        /// Returns a TriangleEnum representing the triangle (within the current slice, either
        /// top or bottom, that the point belongs to).
        /// </summary>
        /// <param name="withinSlice">A point on the x-z cartesian plane, relative to the top-left
        /// of the current slice.</param>
        /// <param name="parity">The "parity" of the slice, indicating wither the border seaparting
        /// the two triangles within the slice goes from top-left to bottom-right (ODD) or
        /// bottom-left to top-right (EVEN).</param>
        /// <returns>A TriangleEnum representing the triangle (within the current slice, either
        /// top or bottom, that the point belongs to).</returns>
        private TriangleEnum WhichTriangle(Vec2D withinSlice, ParityEnum parity)
        {
            float xFraction = withinSlice.x / Slice.x;
            float yBorder   = 0f;

            if (parity == ParityEnum.Even)
            {
                // When parity is even, the border is bottom-left to top-right.
                yBorder = Slice.y * xFraction;
            }
            else
            {
                // When parity is odd, the border is top-left to bottom-right.
                yBorder = Slice.y * (1f - xFraction);
            }

            return((withinSlice.y < yBorder) ? TriangleEnum.Top : TriangleEnum.Bottom);
        }
Пример #8
0
        PointToCubic(Vec2D point)
        {
            // This function exhibited one of the nastiest bugs I've ever come across in my career
            // thanks to a subtle order or bracketing error resulting in bad order of operations.
            //
            // The offending line of code:
            // float q = ( point.x * ( SQRT_3 - point.y ) * ONE_THIRD ) / HexRadius;
            //
            // evaluates to:
            // float q = ( point.x * ONE_THIRD * SQRT_3 - point.x * point.y * ONE_THIRD ) / HexRadius;
            //
            // Resulting is a weird distortion on the coordinate space because the x and y
            // coordinates of the input point were getting multiplied together in the 2nd term!
            //
            // The correct version of the code is now implemented below -- after 2 solid days of
            // meticulous and demoralizing debugging!!!

            float q = (point.x * ONE_THIRD * SQRT_3 - point.y * ONE_THIRD) / HexRadius;
            float r = (point.y * TWO_THIRDS) / HexRadius;

            return(new FloatAxial(q, r).ToFloatCubic().Round());
        }
Пример #9
0
        PointToDirectionInHex(Vec2D point)
        {
            AxialHexCoord axial = PointToCubic(point).ToAxial();
            //AxialHexCoord axial = PointToAxial( point );

            Vec2D center      = AxialToPoint(axial);
            Vec2D topLeft     = center - new Vec2D(0.5f * SQRT_3 * HexRadius, HexRadius);
            Vec2D fromTopLeft = point - topLeft;

            int hSlice = (int)Math.Floor(fromTopLeft.x / Slice.x);
            int vSlice = (int)Math.Floor(fromTopLeft.y / Slice.y);

            Vec2D withinSlice = new Vec2D(
                fromTopLeft.x % Slice.x,
                fromTopLeft.y % Slice.y
                );

            ParityEnum parity = ParityEnum.Even;

            if (((hSlice & 1) + (vSlice & 1)) == 1)
            {
                // One of the two dimensions is odd, otherwise parity is even by default.
                parity = ParityEnum.Odd;
            }

            //
            // Debugging output associated with a horrible bug in PointToCubic()
            //
            //Console.WriteLine( "Point: x: " + point.x + ", y: " + point.y );
            //Console.WriteLine( "Axial: q: " + axial.q + ", r: " + axial.r );
            //Console.WriteLine( "Center: x: " + center.x + ", y: " + center.y );
            //Console.WriteLine( "Top Left: x: " + topLeft.x + ", y: " + topLeft.y );
            //Console.WriteLine( "From Top Left: x: " + fromTopLeft.x + ", y: " + fromTopLeft.y );
            //Console.WriteLine( "Slice: x: " + Slice.x + ", y: " + Slice.y );
            //Console.WriteLine( "Slice Index: x: " + hSlice + ", y: " + vSlice );
            //Console.WriteLine( "Within Slice: x: " + withinSlice.x + ", y: " + withinSlice.y );
            //Console.WriteLine( "Parity: " + parity );

            // Compute and return the triangle by which the point is contained.
            bool          isInvalid = false;
            DirectionEnum direction = DirectionEnum.E;
            TriangleEnum  triangle  = WhichTriangle(withinSlice, parity);


            if (hSlice == 0)
            {
                switch (vSlice)
                {
                case 0:
                    if (triangle == TriangleEnum.Bottom)
                    {
                        direction = DirectionEnum.NW;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                case 1:
                    direction = (triangle == TriangleEnum.Top) ? DirectionEnum.NW : DirectionEnum.W;
                    break;

                case 2:
                    direction = (triangle == TriangleEnum.Top) ? DirectionEnum.W  : DirectionEnum.SW;
                    break;

                case 3:
                    if (triangle == TriangleEnum.Top)
                    {
                        direction = DirectionEnum.SW;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                default:
                    isInvalid = true;
                    break;
                }
            }
            else             // hSlice == 1
            {
                switch (vSlice)
                {
                case 0:
                    if (triangle == TriangleEnum.Bottom)
                    {
                        direction = DirectionEnum.NE;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                case 1:
                    direction = (triangle == TriangleEnum.Top) ? DirectionEnum.NE : DirectionEnum.E;
                    break;

                case 2:
                    direction = (triangle == TriangleEnum.Top) ? DirectionEnum.E  : DirectionEnum.SE;
                    break;

                case 3:
                    if (triangle == TriangleEnum.Top)
                    {
                        direction = DirectionEnum.SE;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                default:
                    isInvalid = true;
                    break;
                }
            }

            //
            // Debugging output associated with a horrible bug in PointToCubic()
            //
            //Console.WriteLine( "Triangle: " + triangle );
            //Console.WriteLine( "Direction: " + direction );
            //Console.WriteLine( "" );
            //Console.WriteLine( "" );

            if (isInvalid)
            {
                throw new InvalidOperationException("This should never happen!");
            }
            else
            {
                return(direction);
            }
        }
Пример #10
0
 /// <summary>
 /// Returns the distance from this Vec2D to the given other.
 /// </summary>
 /// <param name="other">Any other Vec2D.</param>
 /// <returns>A float representing the distance from this Vec2D to the given other.
 /// </returns>
 public float Distance(Vec2D other)
 {
     return((other - this).Length());
 }
Пример #11
0
        /// <summary>
        /// Get the hex that contains the given point on the x-z cartesian plane.
        /// </summary>
        /// <param name="point">A point on the x-y cartesian plane.</param>
        /// <returns>A CubicHexCoord representation of the grid position of the hex that the point
        /// is contained by.</returns>
        public CubicHexCoord PointToCubic( Vec2D point )
        {
            // This function exhibited one of the nastiest bugs I've ever come across in my career
            // thanks to a subtle order or bracketing error resulting in bad order of operations.
            //
            // The offending line of code:
            // float q = ( point.x * ( SQRT_3 - point.y ) * ONE_THIRD ) / HexRadius;
            //
            // evaluates to:
            // float q = ( point.x * ONE_THIRD * SQRT_3 - point.x * point.y * ONE_THIRD ) / HexRadius;
            //
            // Resulting is a weird distortion on the coordinate space because the x and y
            // coordinates of the input point were getting multiplied together in the 2nd term!
            //
            // The correct version of the code is now implemented below -- after 2 solid days of
            // meticulous and demoralizing debugging!!!

            float q = ( point.x * ONE_THIRD * SQRT_3 - point.y * ONE_THIRD ) / HexRadius;
            float r = ( point.y * TWO_THIRDS ) / HexRadius;

            return new FloatAxial( q, r ).ToFloatCubic().Round();
        }
Пример #12
0
        public void PointToDirectionInHex()
        {
            HexGrid grid = new HexGrid( 2f );
            Vec2D hexPos = grid.AxialToPoint( new AxialHexCoord( 10, 10 ) );
            float offset = 0.5f * grid.HexRadius;

            Vec2D[] points = new Vec2D[ 12 ] {
                new Vec2D(	hexPos.x + offset,	hexPos.y + 0f * offset - 0.01f	), // 0a
                new Vec2D(	hexPos.x + offset,	hexPos.y + 0f * offset + 0.01f	), // 0b
                new Vec2D(	hexPos.x + offset,	hexPos.y + 1f * offset - 0.01f	), // 1a
                new Vec2D(	hexPos.x + offset,	hexPos.y + 1f * offset + 0.01f	), // 1b
                new Vec2D(	hexPos.x - offset,	hexPos.y + 1f * offset + 0.01f	), // 2a
                new Vec2D(	hexPos.x - offset,	hexPos.y + 1f * offset - 0.01f	), // 2b
                new Vec2D(	hexPos.x - offset,	hexPos.y + 0f * offset + 0.01f	), // 3a
                new Vec2D(	hexPos.x - offset,	hexPos.y + 0f * offset - 0.01f	), // 3b
                new Vec2D(	hexPos.x - offset,	hexPos.y - 1f * offset + 0.01f	), // 4a
                new Vec2D(	hexPos.x - offset,	hexPos.y - 1f * offset - 0.01f	), // 4b
                new Vec2D(	hexPos.x + offset,	hexPos.y - 1f * offset - 0.01f	), // 5a
                new Vec2D(	hexPos.x + offset,	hexPos.y  -1f * offset + 0.01f	)  // 5b
            };

            DirectionEnum[] results = new DirectionEnum[ 12 ];
            for ( int i = 0; i < points.Length; i++ )
            {
                results[ i ] = grid.PointToDirectionInHex( points[ i ] );
            }

            Assert.That( results, Is.EquivalentTo( new DirectionEnum[ 12 ] {
                DirectionEnum.E,  // 0a
                DirectionEnum.E,  // 0b
                DirectionEnum.SE, // 1a
                DirectionEnum.SE, // 1b
                DirectionEnum.SW, // 2a
                DirectionEnum.SW, // 2b
                DirectionEnum.W,  // 3a
                DirectionEnum.W,  // 3b
                DirectionEnum.NW, // 4a
                DirectionEnum.NW, // 4b
                DirectionEnum.NE, // 5a
                DirectionEnum.NE  // 5b
            } ) );
        }
Пример #13
0
 /// <summary>
 /// Create a new HexGrid given the radius of all hexes within the grid.
 /// </summary>
 /// <param name="hexRadius">The distance from the center of any given hex to one of its
 /// vertices.</param>
 public HexGrid( float hexRadius )
 {
     __hexRadius = hexRadius;
     __slice = new Vec2D( 0.5f * SQRT_3 * HexRadius, 0.5f * HexRadius );
 }
Пример #14
0
        /// <summary>
        /// Returns a TriangleEnum representing the triangle (within the current slice, either 
        /// top or bottom, that the point belongs to).
        /// </summary>
        /// <param name="withinSlice">A point on the x-z cartesian plane, relative to the top-left 
        /// of the current slice.</param>
        /// <param name="parity">The "parity" of the slice, indicating wither the border seaparting 
        /// the two triangles within the slice goes from top-left to bottom-right (ODD) or 
        /// bottom-left to top-right (EVEN).</param>
        /// <returns>A TriangleEnum representing the triangle (within the current slice, either 
        /// top or bottom, that the point belongs to).</returns>
        private TriangleEnum WhichTriangle( Vec2D withinSlice, ParityEnum parity )
        {
            float xFraction = withinSlice.x / Slice.x;
            float yBorder = 0f;

            if ( parity == ParityEnum.Even )
            {
                // When parity is even, the border is bottom-left to top-right.
                yBorder = Slice.y * xFraction;
            }
            else
            {
                // When parity is odd, the border is top-left to bottom-right.
                yBorder = Slice.y * ( 1f - xFraction );
            }

            return ( withinSlice.y < yBorder ) ? TriangleEnum.Top : TriangleEnum.Bottom;
        }
Пример #15
0
        /// <summary>
        /// Returns a DirectionEnum identifying the triangle by which the given point is contained.
        /// </summary>
        /// <param name="point">A point on the x-y cartesian plane.</param>
        /// <returns>A DirectionEnum representing the direction of the triangle that the point is 
        /// contained by within the hex (relative to the center of the hex).</returns>
        public DirectionEnum PointToDirectionInHex( Vec2D point )
        {
            AxialHexCoord axial = PointToCubic( point ).ToAxial();
            //AxialHexCoord axial = PointToAxial( point );

            Vec2D center = AxialToPoint( axial );
            Vec2D topLeft = center - new Vec2D( 0.5f * SQRT_3 * HexRadius, HexRadius );
            Vec2D fromTopLeft = point - topLeft;

            int hSlice = (int)Math.Floor( fromTopLeft.x / Slice.x );
            int vSlice = (int)Math.Floor( fromTopLeft.y / Slice.y );

            Vec2D withinSlice = new Vec2D(
                fromTopLeft.x % Slice.x,
                fromTopLeft.y % Slice.y
            );

            ParityEnum parity = ParityEnum.Even;
            if ( ( ( hSlice & 1 ) + ( vSlice & 1 ) ) == 1 )
            {
                // One of the two dimensions is odd, otherwise parity is even by default.
                parity = ParityEnum.Odd;
            }

            //
            // Debugging output associated with a horrible bug in PointToCubic()
            //
            //Console.WriteLine( "Point: x: " + point.x + ", y: " + point.y );
            //Console.WriteLine( "Axial: q: " + axial.q + ", r: " + axial.r );
            //Console.WriteLine( "Center: x: " + center.x + ", y: " + center.y );
            //Console.WriteLine( "Top Left: x: " + topLeft.x + ", y: " + topLeft.y );
            //Console.WriteLine( "From Top Left: x: " + fromTopLeft.x + ", y: " + fromTopLeft.y );
            //Console.WriteLine( "Slice: x: " + Slice.x + ", y: " + Slice.y );
            //Console.WriteLine( "Slice Index: x: " + hSlice + ", y: " + vSlice );
            //Console.WriteLine( "Within Slice: x: " + withinSlice.x + ", y: " + withinSlice.y );
            //Console.WriteLine( "Parity: " + parity );

            // Compute and return the triangle by which the point is contained.
            bool isInvalid = false;
            DirectionEnum direction = DirectionEnum.E;
            TriangleEnum triangle = WhichTriangle( withinSlice, parity );

            if ( hSlice == 0 )
            {
                switch ( vSlice )
                {
                    case 0:
                    if ( triangle == TriangleEnum.Bottom )
                    {
                        direction = DirectionEnum.NW;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                    case 1:
                    direction = ( triangle == TriangleEnum.Top ) ? DirectionEnum.NW : DirectionEnum.W;
                    break;

                    case 2:
                    direction = ( triangle == TriangleEnum.Top ) ? DirectionEnum.W  : DirectionEnum.SW;
                    break;

                    case 3:
                    if ( triangle == TriangleEnum.Top )
                    {
                        direction = DirectionEnum.SW;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                    default:
                    isInvalid = true;
                    break;
                }
            }
            else // hSlice == 1
            {
                switch ( vSlice )
                {
                    case 0:
                    if ( triangle == TriangleEnum.Bottom )
                    {
                        direction = DirectionEnum.NE;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                    case 1:
                    direction = ( triangle == TriangleEnum.Top ) ? DirectionEnum.NE : DirectionEnum.E;
                    break;

                    case 2:
                    direction = ( triangle == TriangleEnum.Top ) ? DirectionEnum.E  : DirectionEnum.SE;
                    break;

                    case 3:
                    if ( triangle == TriangleEnum.Top )
                    {
                        direction = DirectionEnum.SE;
                    }
                    else
                    {
                        isInvalid = true;
                    }
                    break;

                    default:
                    isInvalid = true;
                    break;
                }
            }

            //
            // Debugging output associated with a horrible bug in PointToCubic()
            //
            //Console.WriteLine( "Triangle: " + triangle );
            //Console.WriteLine( "Direction: " + direction );
            //Console.WriteLine( "" );
            //Console.WriteLine( "" );

            if ( isInvalid )
            {
                throw new InvalidOperationException( "This should never happen!" );
            }
            else
            {
                return direction;
            }
        }
Пример #16
0
 HexGrid(float hexRadius)
 {
     __hexRadius = hexRadius;
     __slice     = new Vec2D(0.5f * SQRT_3 * HexRadius, 0.5f * HexRadius);
 }
Пример #17
0
 /// <summary>
 /// Returns the distance from this Vec2D to the given other.
 /// </summary>
 /// <param name="other">Any other Vec2D.</param>
 /// <returns>A float representing the distance from this Vec2D to the given other.
 /// </returns>
 public float Distance( Vec2D other )
 {
     return ( other - this ).Length();
 }