Example #1
0
        private void Update(EvaluationContext context)
        {
            if (!(SourcePoints.GetValue(context) is StructuredList <Point> sourcePoints))
            {
                return;
            }

            if (sourcePoints.NumElements == 0)
            {
                sourcePoints.SetLength(0);
                ResultList.Value = sourcePoints;
                return;
            }

            var spread     = Spread.GetValue(context);
            var spreadMode = (SpreadModes)SpreadMode.GetValue(context);

            var indexWithinSegment = 0;
            var lineSegmentLength  = 0f;
            var totalLength        = 0f;
            var maxLength          = float.NegativeInfinity;

            var randomizeStart    = RandomizeStart.GetValue(context);
            var randomizeDuration = RandomizeDuration.GetValue(context);

            // Measure...
            segments.Clear();
            for (var pointIndex = 0; pointIndex < sourcePoints.NumElements; pointIndex++)
            {
                if (float.IsNaN(sourcePoints.TypedElements[pointIndex].W))
                {
                    var hasAtLeastTwoPoints = indexWithinSegment > 1;
                    if (hasAtLeastTwoPoints)
                    {
                        if (lineSegmentLength > maxLength)
                        {
                            maxLength = lineSegmentLength;
                        }

                        totalLength += lineSegmentLength;
                        segments.Add(new Segment
                        {
                            PointIndex        = pointIndex - indexWithinSegment,
                            PointCount        = indexWithinSegment,
                            AccumulatedLength = totalLength,
                            SegmentLength     = lineSegmentLength
                        });
                    }

                    lineSegmentLength  = 0;
                    indexWithinSegment = 0;
                }
                else
                {
                    if (indexWithinSegment > 0)
                    {
                        lineSegmentLength += Vector3.Distance(sourcePoints.TypedElements[pointIndex - 1].Position,
                                                              sourcePoints.TypedElements[pointIndex].Position);
                    }

                    indexWithinSegment++;
                }
            }

            if (totalLength < 0.0001f || segments.Count < 2)
            {
                Log.Warning("Stroke animation requires at least two segments with of some length");
                return;
            }

            // Write offsets...
            float dist = maxLength / (segments.Count - 1);

            _random = new Random(42);

            for (var segmentIndex = 0; segmentIndex < segments.Count; segmentIndex++)
            {
                var segmentOffset = ComputeOverlappingProgress(0, segmentIndex, segments.Count, spread);
                var lengthProgressWithingSegment = 0f;
                var segment = segments[segmentIndex];

                // see https://www.figma.com/file/V5k13NMMIsnAnbWH651clI/Untitled?node-id=205%3A96
                var stackedRange = TimeRange.FromStartAndDuration(segment.AccumulatedLength - segment.SegmentLength, segment.SegmentLength) * (1 / totalLength);

                var anchor      = segmentIndex * segment.SegmentLength / (segments.Count - 1);
                var pGrid       = segmentIndex * dist;
                var packedRange = TimeRange.FromStartAndDuration(pGrid - anchor, segment.SegmentLength) * (1 / maxLength);
                var range       = TimeRange.Lerp(packedRange, stackedRange, spread);

                if (Math.Abs(randomizeStart) > 0.0001f)
                {
                    var randomStart = (float)_random.NextDouble() * (1 - range.Duration);
                    range.Start = MathUtils.Lerp(range.Start, randomStart, randomizeStart);
                }

                if (Math.Abs(randomizeDuration) > 0.0001f)
                {
                    var randomDuration = (float)_random.NextDouble() * (1 - range.Start);
                    range.Duration = MathUtils.Lerp(range.Duration, randomDuration, randomizeDuration);
                }

                for (var pointIndexInSegment = 0; pointIndexInSegment < segment.PointCount; pointIndexInSegment++)
                {
                    var pi = segment.PointIndex + pointIndexInSegment;
                    if (pointIndexInSegment > 0)
                    {
                        lengthProgressWithingSegment += Vector3.Distance(sourcePoints.TypedElements[pi - 1].Position,
                                                                         sourcePoints.TypedElements[pi].Position);
                    }

                    var   normalizedSegmentPosition = pointIndexInSegment / (segment.PointCount - 1);
                    float w = 0;
                    switch (spreadMode)
                    {
                    case SpreadModes.IgnoreStrokeLengths:
                        var f = lengthProgressWithingSegment / segment.SegmentLength.Clamp(0.001f, 999999f);
                        w = (f - segmentOffset) / (segments.Count + 1);
                        break;

                    case SpreadModes.UseStrokeLength:
                        w = MathUtils.Lerp(range.Start, range.End, normalizedSegmentPosition);
                        break;

                    case SpreadModes.Weird:
                        w = segmentOffset * 0.2f + pointIndexInSegment / segment.PointCount / 2;
                        break;
                    }

                    sourcePoints.TypedElements[pi].W = w;
                }
            }

            StrokeCount.Value = segments.Count;
            ResultList.Value  = sourcePoints;
            StrokeCount.DirtyFlag.Clear();
            ResultList.DirtyFlag.Clear();
        }