Beispiel #1
0
        /// <summary>
        /// Calculates the length of the generated path in world units.
        /// </summary>
        /// <param name="from">The start of the segment to calculate the length of</param>
        /// <param name="to">The end of the segment</param>
        /// <returns></returns>
        public virtual float CalculateLength(double from = 0.0, double to = 1.0, EvaluateMode mode = EvaluateMode.Cached)
        {
            if (mode == EvaluateMode.Accurate)
            {
                return(spline.CalculateLength(from, to));
            }
            float   length         = 0f;
            Vector3 pos            = EvaluatePosition(from);
            int     sampleIndex    = DMath.CeilInt(from * (samples.Length - 1));
            int     endSampleIndex = DMath.FloorInt(to * (samples.Length - 1));

            for (int i = sampleIndex; i < endSampleIndex; i++)
            {
                length += Vector3.Distance(samples[i].position, pos);
                pos     = samples[i].position;
            }
            length += Vector3.Distance(EvaluatePosition(to), pos);
            return(length);
        }
Beispiel #2
0
        /// <summary>
        /// Project a world space point onto the spline and write to a SplineSample.
        /// </summary>
        /// <param name="point">3D Point in world space</param>
        /// <param name="result">The SplineSample object to write the result into</param>
        /// <param name="from">Sample from [0-1] default: 0.0</param>
        /// <param name="to">Sample to [0-1] default: 1.0</param>
        /// <returns></returns>
        public virtual void Project(Vector3 point, SplineSample result, double from = 0.0, double to = 1.0, EvaluateMode mode = EvaluateMode.Cached)
        {
            if (mode == EvaluateMode.Accurate)
            {
                spline.Evaluate(result, spline.Project(point, 4, from, to));
                return;
            }
            if (samples.Length == 0)
            {
                return;
            }
            if (samples.Length == 1)
            {
                if (result == null)
                {
                    result = new SplineSample(samples[0]);
                }
                else
                {
                    result.CopyFrom(samples[0]);
                }
                return;
            }
            //First make a very rough sample of the from-to region
            int steps = 2;

            if (spline != null)
            {
                steps = (spline.points.Length - 1) * 6;                 //Sampling six points per segment is enough to find the closest point range
            }
            int step = samples.Length / steps;

            if (step < 1)
            {
                step = 1;
            }
            float minDist   = (point - samples[0].position).sqrMagnitude;
            int   fromIndex = 0;
            int   toIndex   = samples.Length - 1;

            if (from != 0.0)
            {
                fromIndex = DMath.FloorInt(from * (samples.Length - 1));
            }
            if (to != 1.0)
            {
                toIndex = Mathf.CeilToInt((float)to * (samples.Length - 1));
            }
            int checkFrom = fromIndex;
            int checkTo   = toIndex;

            //Find the closest point range which will be checked in detail later
            for (int i = fromIndex; i <= toIndex; i += step)
            {
                if (i > toIndex)
                {
                    i = toIndex;
                }
                float dist = (point - samples[i].position).sqrMagnitude;
                if (dist < minDist)
                {
                    minDist   = dist;
                    checkFrom = Mathf.Max(i - step, 0);
                    checkTo   = Mathf.Min(i + step, samples.Length - 1);
                }
                if (i == toIndex)
                {
                    break;
                }
            }
            minDist = (point - samples[checkFrom].position).sqrMagnitude;

            int index = checkFrom;

            //Find the closest result within the range
            for (int i = checkFrom + 1; i <= checkTo; i++)
            {
                float dist = (point - samples[i].position).sqrMagnitude;
                if (dist < minDist)
                {
                    minDist = dist;
                    index   = i;
                }
            }
            //Project the point on the line between the two closest samples
            int backIndex = index - 1;

            if (backIndex < 0)
            {
                backIndex = 0;
            }
            int frontIndex = index + 1;

            if (frontIndex > samples.Length - 1)
            {
                frontIndex = samples.Length - 1;
            }
            Vector3 back             = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, point);
            Vector3 front            = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, point);
            float   backLength       = (samples[index].position - samples[backIndex].position).magnitude;
            float   frontLength      = (samples[index].position - samples[frontIndex].position).magnitude;
            float   backProjectDist  = (back - samples[backIndex].position).magnitude;
            float   frontProjectDist = (front - samples[frontIndex].position).magnitude;

            if (backIndex < index && index < frontIndex)
            {
                if ((point - back).sqrMagnitude < (point - front).sqrMagnitude)
                {
                    SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result);
                }
                else
                {
                    SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result);
                }
            }
            else if (backIndex < index)
            {
                SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result);
            }
            else
            {
                SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Returns the percent from the spline at a given distance from the start point
        /// </summary>
        /// <param name="start">The start point</param>
        /// <param name="distance">The distance to travel</param>
        /// <param name="direction">The direction towards which to move</param>
        /// <param name="traveled">Returns the distance actually traveled. Usually equal to distance but could be less if the travel distance exceeds the remaining spline length.</param>
        /// <param name="mode">If set to EvaluateMode.Accurate, the actual spline will be evaluated instead of the cached samples.</param>
        /// <returns></returns>
        public virtual double Travel(double start, float distance, Spline.Direction direction, out float traveled, EvaluateMode mode = EvaluateMode.Cached)
        {
            traveled = 0f;
            if (mode == EvaluateMode.Accurate)
            {
                return(spline.Travel(start, distance, direction));
            }
            if (samples.Length <= 1)
            {
                return(0.0);
            }
            if (direction == Spline.Direction.Forward && start >= 1.0)
            {
                return(1.0);
            }
            else if (direction == Spline.Direction.Backward && start <= 0.0)
            {
                return(0.0);
            }
            if (distance == 0f)
            {
                return(DMath.Clamp01(start));
            }
            Vector3 lastPosition    = EvaluatePosition(start);
            double  lastPercent     = start;
            int     nextSampleIndex = direction == Spline.Direction.Forward ? DMath.CeilInt(start * (samples.Length - 1)) : DMath.FloorInt(start * (samples.Length - 1));
            float   lastDistance    = 0f;

            while (true)
            {
                lastDistance = Vector3.Distance(samples[nextSampleIndex].position, lastPosition);
                lastPosition = samples[nextSampleIndex].position;
                traveled    += lastDistance;
                if (traveled >= distance)
                {
                    break;
                }
                lastPercent = samples[nextSampleIndex].percent;
                if (direction == Spline.Direction.Forward)
                {
                    if (nextSampleIndex == samples.Length - 1)
                    {
                        break;
                    }
                    nextSampleIndex++;
                }
                else
                {
                    if (nextSampleIndex == 0)
                    {
                        break;
                    }
                    nextSampleIndex--;
                }
            }
            return(DMath.Lerp(lastPercent, samples[nextSampleIndex].percent, 1f - (traveled - distance) / lastDistance));
        }
Beispiel #4
0
        /// <summary>
        /// 将板块的相对坐标转换成
        /// </summary>
        /// <returns></returns>
        public Point PointFToPoint(PointF coord, SizeF unit, PointF parent = default(PointF), EvaluateMode mode = EvaluateMode.Round)
        {
            PointF p = new PointF(parent.X, parent.Y);

            p.X += coord.X * unit.Width;
            p.Y += coord.Y * unit.Height;
            switch (mode)
            {
            case EvaluateMode.Truncate:
                return(Point.Truncate(p));

            case EvaluateMode.Celling:
                return(Point.Ceiling(p));

            case EvaluateMode.Round:
                return(Point.Round(p));

            case EvaluateMode.Floor:
                return(new Point((int)Math.Floor(p.X), (int)Math.Floor(p.Y)));

            default:
                break;
            }
            return(Point.Truncate(p));
        }