private void Update(EvaluationContext context) { var sourcePoints = SourcePoints.GetValue(context) as StructuredList <Point>; var destinationPoints = DestinationsPoints.GetValue(context) as StructuredList <Point>; if (sourcePoints == null || destinationPoints == null || sourcePoints.NumElements == 0 || destinationPoints.NumElements == 0) { _pointList.SetLength(0); ResultList.Value = _pointList; return; } var count = sourcePoints.NumElements * destinationPoints.NumElements; if (_pointList.NumElements != count) { _pointList.SetLength(count); } for (var destinationIndex = 0; destinationIndex < destinationPoints.NumElements; destinationIndex++) { var destination = destinationPoints.TypedElements[destinationIndex]; for (var sourceIndex = 0; sourceIndex < sourcePoints.NumElements; sourceIndex++) { var source = sourcePoints.TypedElements[sourceIndex]; _pointList.TypedElements[destinationIndex * sourcePoints.NumElements + sourceIndex] = new Point() { Position = destination.Position + Vector3.Transform(source.Position, destination.Orientation), W = source.W, Orientation = Quaternion.Multiply(destination.Orientation, source.Orientation), }; } } ResultList.Value = _pointList; }
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(); }