/// Returns the stripe vertex of the last point of the curve. The vertex lies on the way from the point to
    /// the terrain boundary. The distance is computed so that it corresponds to the desired thickness of the stripe.
    private Vector3 ComputeLastStripeVertex()
    {
        // boundary point
        Vector2 endBorderPoint = TerrainCurve[TerrainCurve.Count - 1].position;

        Boundary.ProjectEndPointToBoundary(ref endBorderPoint);
        Vector3 lastStripeVertex = endBorderPoint;

        if (endBorderPoint != TerrainCurve[TerrainCurve.Count - 1].position)
        {
            Vector2 delta2          = TerrainCurve[TerrainCurve.Count - 1].position - TerrainCurve[TerrainCurve.Count - 2].position;
            Vector2 move2           = GetNodeStripeSize(TerrainCurve.Count - 1) * new Vector2(delta2.y, -delta2.x).normalized;
            Vector2 borderDirection = endBorderPoint - TerrainCurve[TerrainCurve.Count - 1].position;
            Vector2 move;
            if (!e2dUtils.HalfLineAndLineIntersect(Vector2.zero, borderDirection, move2, move2 + delta2, out move))
            {
                // the segment is perpendicular to the border or is in concave angle to the border
                move = Vector2.zero;
            }
            lastStripeVertex = TerrainCurve[TerrainCurve.Count - 1].position + move;
            Boundary.EnsurePointIsInBoundary(ref lastStripeVertex);
        }

        return(lastStripeVertex);
    }
    /// Returns the stripe vertex of the first point of the curve. The vertex lies on the way from the point to
    /// the terrain boundary. The distance is computed so that it corresponds to the desired thickness of the stripe.
    private Vector3 ComputeFirstStripeVertex()
    {
        // boundary point
        Vector2 startBorderPoint = TerrainCurve[0].position;

        Boundary.ProjectStartPointToBoundary(ref startBorderPoint);
        Vector3 firstStripeVertex = startBorderPoint;

        if (startBorderPoint != TerrainCurve[0].position)
        {
            Vector2 delta1          = TerrainCurve[1].position - TerrainCurve[0].position;
            Vector2 move1           = GetNodeStripeSize(0) * new Vector2(delta1.y, -delta1.x).normalized;
            Vector2 borderDirection = startBorderPoint - TerrainCurve[0].position;
            Vector2 move;
            if (!e2dUtils.HalfLineAndLineIntersect(Vector2.zero, borderDirection, move1, move1 + delta1, out move))
            {
                // the segment is perpendicular to the border or is in concave angle to the border
                move = Vector2.zero;
            }
            firstStripeVertex = TerrainCurve[0].position + move;
            Boundary.EnsurePointIsInBoundary(ref firstStripeVertex);
        }

        return(firstStripeVertex);
    }
    /// Returns the stripe vertex of the given segment of the curve. The vertex goes towards the inside of the terrain.
    /// The direction and distance is computed so that it complies to the desired thickness of the stripe.
    private Vector3 ComputeStripeVertex(int nodeIndex)
    {
        // compute the stripe point from the segment stripes around this point
        Vector2 delta1 = TerrainCurve[nodeIndex + 0].position - TerrainCurve[nodeIndex - 1].position;
        Vector2 delta2 = TerrainCurve[nodeIndex + 1].position - TerrainCurve[nodeIndex + 0].position;
        Vector2 move1  = new Vector2(delta1.y, -delta1.x).normalized;
        Vector2 move2  = new Vector2(delta2.y, -delta2.x).normalized;
        Vector2 move   = GetNodeStripeSize(nodeIndex) * (move1 + move2).normalized;

        Vector3 stripeVertex = TerrainCurve[nodeIndex].position + move;

        // NOTE: by disabling this we allowed the stripe to reach out of the terrain boundary. The user will fix
        // the boundary if he doesn't like that.
        // But right now it seems better when it's enabled.
        Boundary.EnsurePointIsInBoundary(ref stripeVertex);

        return(stripeVertex);
    }