lottie-ios 3.2.3 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/actions/setup/action.yml +32 -0
- package/.github/issue_template.md +6 -23
- package/.github/workflows/main.yml +98 -0
- package/.github/workflows/stale_issues.yml +17 -0
- package/.spi.yml +6 -0
- package/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +7 -0
- package/.swiftpm/xcode/package.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/.swiftpm/xcode/package.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/.swiftpm/xcode/xcuserdata/{brandonwithrow.xcuserdatad → cal.xcuserdatad}/xcschemes/xcschememanagement.plist +25 -15
- package/.swiftpm/xcode/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/Gemfile +4 -0
- package/Gemfile.lock +102 -0
- package/Lottie.xcodeproj/project.pbxproj +2011 -1972
- package/Lottie.xcodeproj/project.xcworkspace/contents.xcworkspacedata +1 -1
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_iOS.xcscheme → Lottie (iOS).xcscheme } +15 -18
- package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_tvOS.xcscheme → Lottie (macOS).xcscheme } +5 -18
- package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_macOS.xcscheme → Lottie (tvOS).xcscheme } +5 -18
- package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +37 -0
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +24 -0
- package/Lottie.xcworkspace/contents.xcworkspacedata +10 -0
- package/Lottie.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +34 -0
- package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/{Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad → Lottie.xcworkspace/xcuserdata/cal.xcuserdatad}/xcdebugger/Breakpoints_v2.xcbkptlist +2 -2
- package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +153 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +22 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +138 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +30 -0
- package/Package.swift +5 -15
- package/README.md +40 -60
- package/Rakefile +160 -0
- package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +81 -0
- package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +447 -0
- package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +81 -0
- package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +41 -0
- package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +55 -0
- package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +210 -0
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +229 -0
- package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +52 -0
- package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +58 -0
- package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +257 -0
- package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +124 -0
- package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +73 -0
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +205 -0
- package/Sources/Private/CoreAnimation/Animations/VisibilityAnimation.swift +37 -0
- package/Sources/Private/CoreAnimation/CompatibilityTracker.swift +130 -0
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +497 -0
- package/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +35 -0
- package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +37 -0
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +154 -0
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +83 -0
- package/Sources/Private/CoreAnimation/Layers/BaseAnimationLayer.swift +33 -0
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +88 -0
- package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +167 -0
- package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +94 -0
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +79 -0
- package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +64 -0
- package/Sources/Private/CoreAnimation/Layers/MaskCompositionLayer.swift +138 -0
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +140 -0
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +85 -0
- package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +315 -0
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +390 -0
- package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +47 -0
- package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +91 -0
- package/Sources/Private/CoreAnimation/Layers/TransformLayer.swift +11 -0
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +139 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/CompositionLayer.swift +94 -86
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ImageCompositionLayer.swift +24 -21
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/MaskContainerLayer.swift +75 -54
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/NullCompositionLayer.swift +5 -5
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/PreCompositionLayer.swift +59 -43
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ShapeCompositionLayer.swift +22 -20
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/SolidCompositionLayer.swift +26 -17
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/TextCompositionLayer.swift +42 -36
- package/{lottie-swift/src/Private/LayerContainers/AnimationContainer.swift → Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift} +200 -140
- package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +47 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/CompositionLayersInitializer.swift +33 -24
- package/{lottie-swift/src/Private/LayerContainers/Utility/TextLayer.swift → Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift} +149 -106
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/InvertedMatteLayer.swift +26 -24
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +41 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerImageProvider.swift +20 -16
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +40 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerTransformNode.swift +82 -67
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Extensions/ItemsExtension.swift +9 -4
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/NodeProperty.swift +29 -21
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyNodeProperty.swift +16 -10
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyValueContainer.swift +6 -6
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift +5 -5
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +10 -8
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueContainer.swift +25 -21
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift +23 -17
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/SingleValueProvider.swift +22 -17
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +110 -79
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +22 -16
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +19 -15
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift +22 -20
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +22 -23
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +247 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +30 -24
- package/{lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift → Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift} +93 -66
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +23 -19
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +139 -0
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +170 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +95 -58
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/ShapeNode.swift +42 -29
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +108 -69
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +155 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +51 -37
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +57 -42
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +66 -58
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +169 -0
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +138 -119
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/AnimatorNode.swift +80 -79
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/PathNode.swift +5 -3
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/RenderNode.swift +22 -17
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +27 -24
- package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +34 -25
- package/Sources/Private/Model/Animation.swift +160 -0
- package/Sources/Private/Model/Assets/Asset.swift +43 -0
- package/{lottie-swift/src → Sources}/Private/Model/Assets/AssetLibrary.swift +40 -13
- package/Sources/Private/Model/Assets/ImageAsset.swift +112 -0
- package/{lottie-swift/src → Sources}/Private/Model/Assets/PrecompAsset.swift +20 -10
- package/Sources/Private/Model/DictionaryInitializable.swift +67 -0
- package/Sources/Private/Model/Extensions/Bundle.swift +34 -0
- package/{lottie-swift/src → Sources}/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +8 -4
- package/Sources/Private/Model/Keyframes/KeyframeData.swift +113 -0
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +222 -0
- package/{lottie-swift/src → Sources}/Private/Model/Layers/ImageLayerModel.swift +21 -11
- package/Sources/Private/Model/Layers/LayerModel.swift +228 -0
- package/{lottie-swift/src → Sources}/Private/Model/Layers/PreCompLayerModel.swift +39 -22
- package/{lottie-swift/src → Sources}/Private/Model/Layers/ShapeLayerModel.swift +23 -12
- package/{lottie-swift/src → Sources}/Private/Model/Layers/SolidLayerModel.swift +31 -19
- package/{lottie-swift/src → Sources}/Private/Model/Layers/TextLayerModel.swift +33 -19
- package/Sources/Private/Model/Objects/DashPattern.swift +44 -0
- package/Sources/Private/Model/Objects/Marker.swift +33 -0
- package/Sources/Private/Model/Objects/Mask.swift +80 -0
- package/Sources/Private/Model/Objects/Transform.swift +179 -0
- package/Sources/Private/Model/ShapeItems/Ellipse.swift +74 -0
- package/Sources/Private/Model/ShapeItems/Fill.swift +74 -0
- package/Sources/Private/Model/ShapeItems/GradientFill.swift +137 -0
- package/Sources/Private/Model/ShapeItems/GradientStroke.swift +185 -0
- package/Sources/Private/Model/ShapeItems/Group.swift +48 -0
- package/{lottie-swift/src → Sources}/Private/Model/ShapeItems/Merge.swift +29 -12
- package/Sources/Private/Model/ShapeItems/Rectangle.swift +72 -0
- package/Sources/Private/Model/ShapeItems/Repeater.swift +135 -0
- package/Sources/Private/Model/ShapeItems/Shape.swift +56 -0
- package/Sources/Private/Model/ShapeItems/ShapeItem.swift +163 -0
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +135 -0
- package/Sources/Private/Model/ShapeItems/Star.swift +131 -0
- package/Sources/Private/Model/ShapeItems/Stroke.swift +101 -0
- package/Sources/Private/Model/ShapeItems/Trim.swift +77 -0
- package/Sources/Private/Model/Text/Font.swift +61 -0
- package/{lottie-swift/src → Sources}/Private/Model/Text/Glyph.swift +63 -39
- package/Sources/Private/Model/Text/TextAnimator.swift +164 -0
- package/Sources/Private/Model/Text/TextDocument.swift +123 -0
- package/Sources/Private/RootAnimationLayer.swift +51 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Debugging/AnimatorNodeDebugging.swift +7 -7
- package/{lottie-swift/src → Sources}/Private/Utility/Debugging/LayerDebugging.swift +72 -48
- package/Sources/Private/Utility/Debugging/TestHelpers.swift +10 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Extensions/AnimationKeypathExtension.swift +69 -59
- package/Sources/Private/Utility/Extensions/BlendMode+Filter.swift +31 -0
- package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +22 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Extensions/CGFloatExtensions.swift +70 -67
- package/Sources/Private/Utility/Extensions/DataExtension.swift +27 -0
- package/Sources/Private/Utility/Extensions/MathKit.swift +450 -0
- package/Sources/Private/Utility/Extensions/StringExtensions.swift +38 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Helpers/AnimationContext.swift +42 -16
- package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +134 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Interpolatable/KeyframeExtensions.swift +13 -10
- package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +59 -0
- package/{lottie-swift/src/Private/NodeRenderSystem/NodeProperties/ValueProviders → Sources/Private/Utility/Interpolatable}/KeyframeInterpolator.swift +125 -108
- package/{lottie-swift/src → Sources}/Private/Utility/Primitives/BezierPath.swift +229 -143
- package/Sources/Private/Utility/Primitives/CGPointExtension.swift +35 -0
- package/{lottie-swift/src → Sources}/Private/Utility/Primitives/ColorExtension.swift +46 -14
- package/{lottie-swift/src → Sources}/Private/Utility/Primitives/CompoundBezierPath.swift +58 -49
- package/Sources/Private/Utility/Primitives/CurveVertex.swift +184 -0
- package/Sources/Private/Utility/Primitives/PathElement.swift +75 -0
- package/Sources/Private/Utility/Primitives/UnitBezier.swift +115 -0
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +341 -0
- package/Sources/Public/Animation/AnimationPublic.swift +266 -0
- package/Sources/Public/Animation/AnimationView.swift +1335 -0
- package/Sources/Public/Animation/AnimationViewInitializers.swift +109 -0
- package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +22 -0
- package/{lottie-swift/src → Sources}/Public/AnimationCache/LRUAnimationCache.swift +22 -18
- package/Sources/Public/DynamicProperties/AnimationKeypath.swift +49 -0
- package/Sources/Public/DynamicProperties/AnyValueProvider.swift +132 -0
- package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +54 -36
- package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +40 -36
- package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +123 -0
- package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +40 -35
- package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +40 -35
- package/{lottie-swift/src → Sources}/Public/FontProvider/AnimationFontProvider.swift +15 -8
- package/Sources/Public/ImageProvider/AnimationImageProvider.swift +21 -0
- package/Sources/Public/Keyframes/Interpolatable.swift +253 -0
- package/Sources/Public/Keyframes/Keyframe.swift +92 -0
- package/Sources/Public/Logging/LottieLogger.swift +137 -0
- package/Sources/Public/LottieConfiguration.swift +143 -0
- package/{lottie-swift/src → Sources}/Public/Primitives/AnimationTime.swift +1 -1
- package/{lottie-swift/src → Sources}/Public/Primitives/Color.swift +10 -6
- package/{lottie-swift/src → Sources}/Public/Primitives/Vectors.swift +13 -12
- package/Sources/Public/TextProvider/AnimationTextProvider.swift +53 -0
- package/{lottie-swift/src → Sources}/Public/iOS/AnimatedButton.swift +42 -26
- package/{lottie-swift/src → Sources}/Public/iOS/AnimatedControl.swift +100 -91
- package/{lottie-swift/src → Sources}/Public/iOS/AnimatedSwitch.swift +128 -94
- package/{lottie-swift/src → Sources}/Public/iOS/AnimationSubview.swift +3 -3
- package/Sources/Public/iOS/AnimationViewBase.swift +78 -0
- package/{lottie-swift/src → Sources}/Public/iOS/BundleImageProvider.swift +36 -34
- package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift +4 -0
- package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationView.swift +38 -29
- package/{lottie-swift/src → Sources}/Public/iOS/FilepathImageProvider.swift +24 -21
- package/{lottie-swift/src → Sources}/Public/iOS/UIColorExtension.swift +4 -4
- package/{lottie-swift/src/Public/MacOS/AnimationSubview.swift → Sources/Public/macOS/AnimationSubview.macOS.swift} +4 -5
- package/{lottie-swift/src/Public/MacOS/LottieView.swift → Sources/Public/macOS/AnimationViewBase.macOS.swift} +58 -50
- package/{lottie-swift/src/Public/MacOS/BundleImageProvider.swift → Sources/Public/macOS/BundleImageProvider.macOS.swift} +31 -32
- package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +67 -0
- package/Tests/AnimationKeypathTests.swift +103 -0
- package/Tests/AutomaticEngineTests.swift +57 -0
- package/Tests/BundleTests.swift +25 -0
- package/Tests/DataURLTests.swift +64 -0
- package/Tests/ParsingTests.swift +43 -0
- package/Tests/PerformanceTests.swift +214 -0
- package/Tests/Samples/9squares_AlBoardman.json +1 -0
- package/Tests/Samples/Boat_Loader.json +1 -0
- package/Tests/Samples/HamburgerArrow.json +1 -0
- package/Tests/Samples/IconTransitions.json +1 -0
- package/Tests/Samples/Images/dog.png +0 -0
- package/Tests/Samples/Issues/issue_1125.json +1 -0
- package/Tests/Samples/Issues/issue_1260.json +1 -0
- package/Tests/Samples/Issues/issue_1403.json +1 -0
- package/Tests/Samples/Issues/issue_1407.json +1 -0
- package/Tests/Samples/Issues/issue_1460.json +1 -0
- package/Tests/Samples/Issues/issue_1488.json +1 -0
- package/Tests/Samples/Issues/issue_1505.json +1 -0
- package/Tests/Samples/Issues/issue_1541.json +1 -0
- package/Tests/Samples/Issues/issue_1557.json +1 -0
- package/Tests/Samples/Issues/issue_1603.json +1 -0
- package/Tests/Samples/Issues/issue_1628.json +1 -0
- package/Tests/Samples/Issues/issue_1636.json +1 -0
- package/Tests/Samples/Issues/issue_1643.json +1 -0
- package/Tests/Samples/Issues/issue_1655.json +1 -0
- package/Tests/Samples/Issues/issue_1664.json +1 -0
- package/Tests/Samples/Issues/issue_1683.json +1 -0
- package/Tests/Samples/Issues/issue_1687.json +1 -0
- package/Tests/Samples/Issues/issue_1711.json +1 -0
- package/Tests/Samples/Issues/issue_1717.json +1 -0
- package/Tests/Samples/Issues/issue_769.json +1 -0
- package/Tests/Samples/Issues/issue_885.json +1 -0
- package/Tests/Samples/Issues/issue_965.json +1 -0
- package/Tests/Samples/Issues/pr_1536.json +1 -0
- package/Tests/Samples/Issues/pr_1563.json +8439 -0
- package/Tests/Samples/Issues/pr_1592.json +5527 -0
- package/Tests/Samples/Issues/pr_1599.json +738 -0
- package/Tests/Samples/Issues/pr_1604_1.json +1 -0
- package/Tests/Samples/Issues/pr_1604_2.json +1 -0
- package/Tests/Samples/Issues/pr_1632_1.json +1 -0
- package/Tests/Samples/Issues/pr_1632_2.json +1 -0
- package/Tests/Samples/Issues/pr_1686.json +513 -0
- package/Tests/Samples/Issues/pr_1698.json +1 -0
- package/Tests/Samples/Issues/pr_1699.json +1 -0
- package/Tests/Samples/LottieFiles/LICENSE.md +14 -0
- package/Tests/Samples/LottieFiles/bounce_strokes.json +1 -0
- package/Tests/Samples/LottieFiles/cactus.json +1 -0
- package/Tests/Samples/LottieFiles/dog_car_ride.json +1 -0
- package/Tests/Samples/LottieFiles/draft_icon.json +1 -0
- package/Tests/Samples/LottieFiles/fireworks.json +1 -0
- package/Tests/Samples/LottieFiles/gradient_1.json +1 -0
- package/Tests/Samples/LottieFiles/gradient_2.json +1 -0
- package/Tests/Samples/LottieFiles/gradient_pill.json +1 -0
- package/Tests/Samples/LottieFiles/gradient_shapes.json +1 -0
- package/Tests/Samples/LottieFiles/gradient_square.json +1 -0
- package/Tests/Samples/LottieFiles/growth.json +1 -0
- package/Tests/Samples/LottieFiles/infinity_loader.json +1 -0
- package/Tests/Samples/LottieFiles/loading_dots_1.json +1 -0
- package/Tests/Samples/LottieFiles/loading_dots_2.json +1 -0
- package/Tests/Samples/LottieFiles/loading_dots_3.json +1 -0
- package/Tests/Samples/LottieFiles/loading_gradient_strokes.json +1 -0
- package/Tests/Samples/LottieFiles/settings_slider.json +1 -0
- package/Tests/Samples/LottieFiles/shop.json +1 -0
- package/Tests/Samples/LottieFiles/step_loader.json +1 -0
- package/Tests/Samples/LottieLogo1.json +1 -0
- package/Tests/Samples/LottieLogo1_masked.json +1 -0
- package/Tests/Samples/LottieLogo2.json +1 -0
- package/Tests/Samples/MotionCorpse_Jrcanest.json +1 -0
- package/Tests/Samples/Nonanimating/BasicLayers.json +1 -0
- package/Tests/Samples/Nonanimating/DisableNodesTest.json +1 -0
- package/Tests/Samples/Nonanimating/FirstText.json +1 -0
- package/Tests/Samples/Nonanimating/GeometryTransformTest.json +1 -0
- package/Tests/Samples/Nonanimating/Text_AnimatedProperties.json +1 -0
- package/Tests/Samples/Nonanimating/Text_Glyph.json +1 -0
- package/Tests/Samples/Nonanimating/Text_NoAnimation.json +1 -0
- package/Tests/Samples/Nonanimating/Text_NoGlyph.json +1 -0
- package/Tests/Samples/Nonanimating/Zoom.json +1 -0
- package/Tests/Samples/Nonanimating/_dog.json +1 -0
- package/Tests/Samples/Nonanimating/base64Test.json +1 -0
- package/Tests/Samples/Nonanimating/blend_mode_test.json +1 -0
- package/Tests/Samples/Nonanimating/keypathTest.json +1 -0
- package/Tests/Samples/Nonanimating/verifyLineHeight.json +1 -0
- package/Tests/Samples/PinJump.json +1 -0
- package/Tests/Samples/Switch.json +1 -0
- package/Tests/Samples/Switch_States.json +1 -0
- package/Tests/Samples/TwitterHeart.json +1 -0
- package/Tests/Samples/TwitterHeartButton.json +1 -0
- package/Tests/Samples/TypeFace/A.json +1 -0
- package/Tests/Samples/TypeFace/Apostrophe.json +1 -0
- package/Tests/Samples/TypeFace/B.json +1 -0
- package/Tests/Samples/TypeFace/BlinkingCursor.json +1 -0
- package/Tests/Samples/TypeFace/C.json +1 -0
- package/Tests/Samples/TypeFace/Colon.json +1 -0
- package/Tests/Samples/TypeFace/Comma.json +1 -0
- package/Tests/Samples/TypeFace/D.json +1 -0
- package/Tests/Samples/TypeFace/E.json +1 -0
- package/Tests/Samples/TypeFace/F.json +1 -0
- package/Tests/Samples/TypeFace/G.json +1 -0
- package/Tests/Samples/TypeFace/H.json +1 -0
- package/Tests/Samples/TypeFace/I.json +1 -0
- package/Tests/Samples/TypeFace/J.json +1 -0
- package/Tests/Samples/TypeFace/K.json +1 -0
- package/Tests/Samples/TypeFace/L.json +1 -0
- package/Tests/Samples/TypeFace/M.json +1 -0
- package/Tests/Samples/TypeFace/N.json +1 -0
- package/Tests/Samples/TypeFace/O.json +1 -0
- package/Tests/Samples/TypeFace/P.json +1 -0
- package/Tests/Samples/TypeFace/Q.json +1 -0
- package/Tests/Samples/TypeFace/R.json +1 -0
- package/Tests/Samples/TypeFace/S.json +1 -0
- package/Tests/Samples/TypeFace/T.json +1 -0
- package/Tests/Samples/TypeFace/U.json +1 -0
- package/Tests/Samples/TypeFace/V.json +1 -0
- package/Tests/Samples/TypeFace/W.json +1 -0
- package/Tests/Samples/TypeFace/X.json +1 -0
- package/Tests/Samples/TypeFace/Y.json +1 -0
- package/Tests/Samples/TypeFace/Z.json +1 -0
- package/Tests/Samples/Watermelon.json +1 -0
- package/Tests/Samples/setValueTest.json +1 -0
- package/Tests/Samples/timeremap.json +1 -0
- package/Tests/Samples/vcTransition1.json +1 -0
- package/Tests/Samples/vcTransition2.json +1 -0
- package/Tests/SnapshotConfiguration.swift +158 -0
- package/Tests/SnapshotTests.swift +265 -0
- package/Tests/Utils/Bundle+Module.swift +30 -0
- package/Tests/Utils/HardcodedFontProvider.swift +19 -0
- package/Tests/Utils/HardcodedImageProvider.swift +23 -0
- package/Tests/Utils/Snapshotting+presentationLayer.swift +47 -0
- package/Tests/ValueProvidersTests.swift +27 -0
- package/lottie-ios.podspec +12 -12
- package/package.json +1 -1
- package/script/test-carthage/Cartfile +1 -0
- package/script/test-carthage/Cartfile.resolved +1 -0
- package/script/test-carthage/CarthageTest/AppDelegate.swift +26 -0
- package/script/test-carthage/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/script/test-carthage/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
- package/script/test-carthage/CarthageTest/Assets.xcassets/Contents.json +6 -0
- package/script/test-carthage/CarthageTest/Base.lproj/LaunchScreen.storyboard +25 -0
- package/script/test-carthage/CarthageTest/Base.lproj/Main.storyboard +24 -0
- package/script/test-carthage/CarthageTest/Info.plist +66 -0
- package/script/test-carthage/CarthageTest/SceneDelegate.swift +10 -0
- package/script/test-carthage/CarthageTest/ViewController.swift +15 -0
- package/script/test-carthage/CarthageTest-macOS/AppDelegate.swift +7 -0
- package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
- package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/Contents.json +6 -0
- package/script/test-carthage/CarthageTest-macOS/Base.lproj/Main.storyboard +717 -0
- package/script/test-carthage/CarthageTest-macOS/CarthageTest_macOS.entitlements +10 -0
- package/script/test-carthage/CarthageTest-macOS/ViewController.swift +15 -0
- package/script/test-carthage/CarthageTest.xcodeproj/project.pbxproj +532 -0
- package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
- package/script/test-carthage/Mintfile +1 -0
- package/script/test-spm/LottieSPM.xcworkspace/contents.xcworkspacedata +7 -0
- package/script/test-spm/LottieSPM.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/script/test-spm/Mintfile +1 -0
- package/.swiftpm/xcode/package.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie/Info.plist +0 -22
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/LottieLibraryMacOS.xcscheme +0 -80
- package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/xcschememanagement.plist +0 -57
- package/lottie-swift/Assets/.gitkeep +0 -0
- package/lottie-swift/src/Private/LayerContainers/Utility/LayerFontProvider.swift +0 -37
- package/lottie-swift/src/Private/LayerContainers/Utility/LayerTextProvider.swift +0 -36
- package/lottie-swift/src/Private/Model/Animation.swift +0 -107
- package/lottie-swift/src/Private/Model/Assets/Asset.swift +0 -27
- package/lottie-swift/src/Private/Model/Assets/ImageAsset.swift +0 -48
- package/lottie-swift/src/Private/Model/Keyframes/Keyframe.swift +0 -128
- package/lottie-swift/src/Private/Model/Keyframes/KeyframeGroup.swift +0 -108
- package/lottie-swift/src/Private/Model/Layers/LayerModel.swift +0 -150
- package/lottie-swift/src/Private/Model/Objects/DashPattern.swift +0 -24
- package/lottie-swift/src/Private/Model/Objects/Marker.swift +0 -23
- package/lottie-swift/src/Private/Model/Objects/Mask.swift +0 -48
- package/lottie-swift/src/Private/Model/Objects/Transform.swift +0 -105
- package/lottie-swift/src/Private/Model/ShapeItems/Ellipse.swift +0 -50
- package/lottie-swift/src/Private/Model/ShapeItems/FillI.swift +0 -49
- package/lottie-swift/src/Private/Model/ShapeItems/GradientFill.swift +0 -86
- package/lottie-swift/src/Private/Model/ShapeItems/GradientStroke.swift +0 -125
- package/lottie-swift/src/Private/Model/ShapeItems/Group.swift +0 -32
- package/lottie-swift/src/Private/Model/ShapeItems/Rectangle.swift +0 -50
- package/lottie-swift/src/Private/Model/ShapeItems/Repeater.swift +0 -80
- package/lottie-swift/src/Private/Model/ShapeItems/Shape.swift +0 -37
- package/lottie-swift/src/Private/Model/ShapeItems/ShapeItem.swift +0 -95
- package/lottie-swift/src/Private/Model/ShapeItems/ShapeTransform.swift +0 -68
- package/lottie-swift/src/Private/Model/ShapeItems/Star.swift +0 -86
- package/lottie-swift/src/Private/Model/ShapeItems/Stroke.swift +0 -67
- package/lottie-swift/src/Private/Model/ShapeItems/Trim.swift +0 -53
- package/lottie-swift/src/Private/Model/Text/Font.swift +0 -35
- package/lottie-swift/src/Private/Model/Text/TextAnimator.swift +0 -99
- package/lottie-swift/src/Private/Model/Text/TextDocument.swift +0 -70
- package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +0 -109
- package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +0 -132
- package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +0 -141
- package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +0 -127
- package/lottie-swift/src/Private/Utility/Extensions/MathKit.swift +0 -539
- package/lottie-swift/src/Private/Utility/Extensions/StringExtensions.swift +0 -32
- package/lottie-swift/src/Private/Utility/Interpolatable/Interpolatable.swift +0 -18
- package/lottie-swift/src/Private/Utility/Interpolatable/InterpolatableExtensions.swift +0 -170
- package/lottie-swift/src/Private/Utility/Primitives/CurveVertex.swift +0 -177
- package/lottie-swift/src/Private/Utility/Primitives/PathElement.swift +0 -68
- package/lottie-swift/src/Private/Utility/Primitives/VectorsExtensions.swift +0 -218
- package/lottie-swift/src/Public/Animation/AnimationPublic.swift +0 -196
- package/lottie-swift/src/Public/Animation/AnimationView.swift +0 -1006
- package/lottie-swift/src/Public/Animation/AnimationViewInitializers.swift +0 -83
- package/lottie-swift/src/Public/AnimationCache/AnimationCacheProvider.swift +0 -24
- package/lottie-swift/src/Public/DynamicProperties/AnimationKeypath.swift +0 -46
- package/lottie-swift/src/Public/DynamicProperties/AnyValueProvider.swift +0 -29
- package/lottie-swift/src/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +0 -114
- package/lottie-swift/src/Public/ImageProvider/AnimationImageProvider.swift +0 -23
- package/lottie-swift/src/Public/MacOS/FilepathImageProvider.swift +0 -67
- package/lottie-swift/src/Public/TextProvider/AnimationTextProvider.swift +0 -39
- package/lottie-swift/src/Public/iOS/LottieView.swift +0 -62
- package/lottie-swift-testing.podspec +0 -32
|
@@ -5,35 +5,39 @@
|
|
|
5
5
|
// Created by Brandon Withrow on 1/14/19.
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
-
import Foundation
|
|
9
8
|
import CoreGraphics
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
// MARK: - Color + Codable
|
|
10
12
|
|
|
11
13
|
extension Color: Codable {
|
|
12
14
|
|
|
15
|
+
// MARK: Lifecycle
|
|
16
|
+
|
|
13
17
|
public init(from decoder: Decoder) throws {
|
|
14
18
|
var container = try decoder.unkeyedContainer()
|
|
15
|
-
|
|
19
|
+
|
|
16
20
|
var r1: Double
|
|
17
21
|
if !container.isAtEnd {
|
|
18
22
|
r1 = try container.decode(Double.self)
|
|
19
23
|
} else {
|
|
20
24
|
r1 = 0
|
|
21
25
|
}
|
|
22
|
-
|
|
26
|
+
|
|
23
27
|
var g1: Double
|
|
24
28
|
if !container.isAtEnd {
|
|
25
29
|
g1 = try container.decode(Double.self)
|
|
26
30
|
} else {
|
|
27
31
|
g1 = 0
|
|
28
32
|
}
|
|
29
|
-
|
|
33
|
+
|
|
30
34
|
var b1: Double
|
|
31
35
|
if !container.isAtEnd {
|
|
32
36
|
b1 = try container.decode(Double.self)
|
|
33
37
|
} else {
|
|
34
38
|
b1 = 0
|
|
35
39
|
}
|
|
36
|
-
|
|
40
|
+
|
|
37
41
|
var a1: Double
|
|
38
42
|
if !container.isAtEnd {
|
|
39
43
|
a1 = try container.decode(Double.self)
|
|
@@ -46,12 +50,14 @@ extension Color: Codable {
|
|
|
46
50
|
b1 = b1 / 255
|
|
47
51
|
a1 = a1 / 255
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
r = r1
|
|
54
|
+
g = g1
|
|
55
|
+
b = b1
|
|
56
|
+
a = a1
|
|
53
57
|
}
|
|
54
|
-
|
|
58
|
+
|
|
59
|
+
// MARK: Public
|
|
60
|
+
|
|
55
61
|
public func encode(to encoder: Encoder) throws {
|
|
56
62
|
var container = encoder.unkeyedContainer()
|
|
57
63
|
try container.encode(r)
|
|
@@ -59,15 +65,41 @@ extension Color: Codable {
|
|
|
59
65
|
try container.encode(b)
|
|
60
66
|
try container.encode(a)
|
|
61
67
|
}
|
|
62
|
-
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// MARK: - Color + AnyInitializable
|
|
72
|
+
|
|
73
|
+
extension Color: AnyInitializable {
|
|
74
|
+
|
|
75
|
+
init(value: Any) throws {
|
|
76
|
+
guard var array = value as? [Double] else {
|
|
77
|
+
throw InitializableError.invalidInput
|
|
78
|
+
}
|
|
79
|
+
var r: Double = array.count > 0 ? array.removeFirst() : 0
|
|
80
|
+
var g: Double = array.count > 0 ? array.removeFirst() : 0
|
|
81
|
+
var b: Double = array.count > 0 ? array.removeFirst() : 0
|
|
82
|
+
var a: Double = array.count > 0 ? array.removeFirst() : 1
|
|
83
|
+
if r > 1, g > 1, b > 1, a > 1 {
|
|
84
|
+
r /= 255
|
|
85
|
+
g /= 255
|
|
86
|
+
b /= 255
|
|
87
|
+
a /= 255
|
|
88
|
+
}
|
|
89
|
+
self.r = r
|
|
90
|
+
self.g = g
|
|
91
|
+
self.b = b
|
|
92
|
+
self.a = a
|
|
93
|
+
}
|
|
94
|
+
|
|
63
95
|
}
|
|
64
96
|
|
|
65
97
|
extension Color {
|
|
66
|
-
|
|
98
|
+
|
|
67
99
|
static var clearColor: CGColor {
|
|
68
|
-
|
|
100
|
+
CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0, 0, 0, 0])!
|
|
69
101
|
}
|
|
70
|
-
|
|
102
|
+
|
|
71
103
|
var cgColorValue: CGColor {
|
|
72
104
|
// TODO: Fix color spaces
|
|
73
105
|
let colorspace = CGColorSpaceCreateDeviceRGB()
|
|
@@ -5,112 +5,119 @@
|
|
|
5
5
|
// Created by Brandon Withrow on 1/14/19.
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
-
import Foundation
|
|
9
8
|
import CoreGraphics
|
|
9
|
+
import Foundation
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
11
|
+
/// A collection of BezierPath objects that can be trimmed and added.
|
|
12
|
+
///
|
|
15
13
|
struct CompoundBezierPath {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
let length: CGFloat
|
|
20
|
-
|
|
14
|
+
|
|
15
|
+
// MARK: Lifecycle
|
|
16
|
+
|
|
21
17
|
init() {
|
|
22
18
|
paths = []
|
|
23
19
|
length = 0
|
|
24
20
|
}
|
|
25
|
-
|
|
21
|
+
|
|
26
22
|
init(path: BezierPath) {
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
paths = [path]
|
|
24
|
+
length = path.length
|
|
29
25
|
}
|
|
30
|
-
|
|
26
|
+
|
|
31
27
|
init(paths: [BezierPath], length: CGFloat) {
|
|
32
28
|
self.paths = paths
|
|
33
29
|
self.length = length
|
|
34
30
|
}
|
|
35
|
-
|
|
31
|
+
|
|
36
32
|
init(paths: [BezierPath]) {
|
|
37
33
|
self.paths = paths
|
|
38
34
|
var l: CGFloat = 0
|
|
39
35
|
for path in paths {
|
|
40
36
|
l = l + path.length
|
|
41
37
|
}
|
|
42
|
-
|
|
38
|
+
length = l
|
|
43
39
|
}
|
|
44
|
-
|
|
40
|
+
|
|
41
|
+
// MARK: Internal
|
|
42
|
+
|
|
43
|
+
let paths: [BezierPath]
|
|
44
|
+
|
|
45
|
+
let length: CGFloat
|
|
46
|
+
|
|
45
47
|
func addPath(path: BezierPath) -> CompoundBezierPath {
|
|
46
48
|
var newPaths = paths
|
|
47
49
|
newPaths.append(path)
|
|
48
50
|
return CompoundBezierPath(paths: newPaths, length: length + path.length)
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
func combine(_ compoundBezier: CompoundBezierPath) -> CompoundBezierPath {
|
|
52
54
|
var newPaths = paths
|
|
53
55
|
newPaths.append(contentsOf: compoundBezier.paths)
|
|
54
56
|
return CompoundBezierPath(paths: newPaths, length: length + compoundBezier.length)
|
|
55
57
|
}
|
|
56
|
-
|
|
58
|
+
|
|
57
59
|
func trim(fromPosition: CGFloat, toPosition: CGFloat, offset: CGFloat, trimSimultaneously: Bool) -> CompoundBezierPath {
|
|
58
60
|
if fromPosition == toPosition {
|
|
59
61
|
return CompoundBezierPath()
|
|
60
62
|
}
|
|
61
|
-
|
|
63
|
+
|
|
62
64
|
if trimSimultaneously {
|
|
63
65
|
/// Trim each path individually.
|
|
64
66
|
var newPaths = [BezierPath]()
|
|
65
67
|
for path in paths {
|
|
66
|
-
newPaths.append(contentsOf: path.trim(
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
newPaths.append(contentsOf: path.trim(
|
|
69
|
+
fromLength: fromPosition * path.length,
|
|
70
|
+
toLength: toPosition * path.length,
|
|
71
|
+
offsetLength: offset * path.length))
|
|
69
72
|
}
|
|
70
73
|
return CompoundBezierPath(paths: newPaths)
|
|
71
74
|
}
|
|
72
|
-
|
|
75
|
+
|
|
73
76
|
/// Normalize lengths to the curve length.
|
|
74
|
-
var startPosition = (fromPosition+offset).truncatingRemainder(dividingBy: 1)
|
|
75
|
-
var endPosition =
|
|
76
|
-
|
|
77
|
+
var startPosition = (fromPosition + offset).truncatingRemainder(dividingBy: 1)
|
|
78
|
+
var endPosition = (toPosition + offset).truncatingRemainder(dividingBy: 1)
|
|
79
|
+
|
|
77
80
|
if startPosition < 0 {
|
|
78
81
|
startPosition = 1 + startPosition
|
|
79
82
|
}
|
|
80
|
-
|
|
83
|
+
|
|
81
84
|
if endPosition < 0 {
|
|
82
85
|
endPosition = 1 + endPosition
|
|
83
86
|
}
|
|
84
|
-
|
|
87
|
+
|
|
85
88
|
if startPosition == 1 {
|
|
86
89
|
startPosition = 0
|
|
87
90
|
}
|
|
88
91
|
if endPosition == 0 {
|
|
89
92
|
endPosition = 1
|
|
90
93
|
}
|
|
91
|
-
|
|
92
|
-
if
|
|
94
|
+
|
|
95
|
+
if
|
|
96
|
+
startPosition == 0 && endPosition == 1 ||
|
|
93
97
|
startPosition == endPosition ||
|
|
94
|
-
startPosition == 1 && endPosition == 0
|
|
98
|
+
startPosition == 1 && endPosition == 0
|
|
99
|
+
{
|
|
95
100
|
/// The trim encompasses the entire path. Return.
|
|
96
101
|
return self
|
|
97
102
|
}
|
|
98
|
-
|
|
103
|
+
|
|
99
104
|
var positions: [(start: CGFloat, end: CGFloat)]
|
|
100
105
|
if endPosition < startPosition {
|
|
101
|
-
positions = [
|
|
102
|
-
|
|
106
|
+
positions = [
|
|
107
|
+
(start: 0, end: endPosition * length),
|
|
108
|
+
(start: startPosition * length, end: length),
|
|
109
|
+
]
|
|
103
110
|
} else {
|
|
104
111
|
positions = [(start: startPosition * length, end: endPosition * length)]
|
|
105
112
|
}
|
|
106
|
-
|
|
113
|
+
|
|
107
114
|
var compoundPath = CompoundBezierPath()
|
|
108
115
|
var trim = positions.remove(at: 0)
|
|
109
116
|
var pathStartPosition: CGFloat = 0
|
|
110
|
-
|
|
111
|
-
var finishedTrimming
|
|
112
|
-
var i
|
|
113
|
-
|
|
117
|
+
|
|
118
|
+
var finishedTrimming = false
|
|
119
|
+
var i = 0
|
|
120
|
+
|
|
114
121
|
while !finishedTrimming {
|
|
115
122
|
if paths.count <= i {
|
|
116
123
|
/// Rounding errors
|
|
@@ -118,27 +125,29 @@ struct CompoundBezierPath {
|
|
|
118
125
|
continue
|
|
119
126
|
}
|
|
120
127
|
let path = paths[i]
|
|
121
|
-
|
|
128
|
+
|
|
122
129
|
let pathEndPosition = pathStartPosition + path.length
|
|
123
|
-
|
|
130
|
+
|
|
124
131
|
if pathEndPosition < trim.start {
|
|
125
132
|
/// Path is not included in the trim, continue.
|
|
126
133
|
pathStartPosition = pathEndPosition
|
|
127
134
|
i = i + 1
|
|
128
135
|
continue
|
|
129
|
-
|
|
136
|
+
|
|
130
137
|
} else if trim.start <= pathStartPosition, pathEndPosition <= trim.end {
|
|
131
138
|
/// Full Path is inside of trim. Add full path.
|
|
132
139
|
compoundPath = compoundPath.addPath(path: path)
|
|
133
140
|
} else {
|
|
134
|
-
if
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
141
|
+
if
|
|
142
|
+
let trimPath = path.trim(
|
|
143
|
+
fromLength: trim.start > pathStartPosition ? (trim.start - pathStartPosition) : 0,
|
|
144
|
+
toLength: trim.end < pathEndPosition ? (trim.end - pathStartPosition) : path.length,
|
|
145
|
+
offsetLength: 0).first
|
|
146
|
+
{
|
|
147
|
+
compoundPath = compoundPath.addPath(path: trimPath)
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
|
|
141
|
-
|
|
142
151
|
if trim.end <= pathEndPosition {
|
|
143
152
|
/// We are done with the current trim.
|
|
144
153
|
/// Advance trim but remain on the same path in case the next trim overlaps it.
|
|
@@ -154,5 +163,5 @@ struct CompoundBezierPath {
|
|
|
154
163
|
}
|
|
155
164
|
return compoundPath
|
|
156
165
|
}
|
|
157
|
-
|
|
166
|
+
|
|
158
167
|
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CurveVertex.swift
|
|
3
|
+
// lottie-swift
|
|
4
|
+
//
|
|
5
|
+
// Created by Brandon Withrow on 1/11/19.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import CoreGraphics
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
/// A single vertex with an in and out tangent
|
|
12
|
+
struct CurveVertex {
|
|
13
|
+
|
|
14
|
+
// MARK: Lifecycle
|
|
15
|
+
|
|
16
|
+
/// Initializes a curve point with absolute values
|
|
17
|
+
init(_ inTangent: CGPoint, _ point: CGPoint, _ outTangent: CGPoint) {
|
|
18
|
+
self.point = point
|
|
19
|
+
self.inTangent = inTangent
|
|
20
|
+
self.outTangent = outTangent
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Initializes a curve point with relative values
|
|
24
|
+
init(point: CGPoint, inTangentRelative: CGPoint, outTangentRelative: CGPoint) {
|
|
25
|
+
self.point = point
|
|
26
|
+
inTangent = point.add(inTangentRelative)
|
|
27
|
+
outTangent = point.add(outTangentRelative)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Initializes a curve point with absolute values
|
|
31
|
+
init(point: CGPoint, inTangent: CGPoint, outTangent: CGPoint) {
|
|
32
|
+
self.point = point
|
|
33
|
+
self.inTangent = inTangent
|
|
34
|
+
self.outTangent = outTangent
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// MARK: Internal
|
|
38
|
+
|
|
39
|
+
let point: CGPoint
|
|
40
|
+
|
|
41
|
+
let inTangent: CGPoint
|
|
42
|
+
let outTangent: CGPoint
|
|
43
|
+
|
|
44
|
+
var inTangentRelative: CGPoint {
|
|
45
|
+
inTangent.subtract(point)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var outTangentRelative: CGPoint {
|
|
49
|
+
outTangent.subtract(point)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func reversed() -> CurveVertex {
|
|
53
|
+
CurveVertex(point: point, inTangent: outTangent, outTangent: inTangent)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func translated(_ translation: CGPoint) -> CurveVertex {
|
|
57
|
+
CurveVertex(point: point + translation, inTangent: inTangent + translation, outTangent: outTangent + translation)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Trims a path defined by two Vertices at a specific position, from 0 to 1
|
|
61
|
+
///
|
|
62
|
+
/// The path can be visualized below.
|
|
63
|
+
///
|
|
64
|
+
/// F is fromVertex.
|
|
65
|
+
/// V is the vertex of the receiver.
|
|
66
|
+
/// P is the position from 0-1.
|
|
67
|
+
/// O is the outTangent of fromVertex.
|
|
68
|
+
/// F====O=========P=======I====V
|
|
69
|
+
///
|
|
70
|
+
/// After trimming the curve can be visualized below.
|
|
71
|
+
///
|
|
72
|
+
/// S is the returned Start vertex.
|
|
73
|
+
/// E is the returned End vertex.
|
|
74
|
+
/// T is the trim point.
|
|
75
|
+
/// TI and TO are the new tangents for the trimPoint
|
|
76
|
+
/// NO and NI are the new tangents for the startPoint and endPoints
|
|
77
|
+
/// S==NO=========TI==T==TO=======NI==E
|
|
78
|
+
func splitCurve(toVertex: CurveVertex, position: CGFloat) ->
|
|
79
|
+
(start: CurveVertex, trimPoint: CurveVertex, end: CurveVertex)
|
|
80
|
+
{
|
|
81
|
+
/// If position is less than or equal to 0, trim at start.
|
|
82
|
+
if position <= 0 {
|
|
83
|
+
return (
|
|
84
|
+
start: CurveVertex(point: point, inTangentRelative: inTangentRelative, outTangentRelative: .zero),
|
|
85
|
+
trimPoint: CurveVertex(point: point, inTangentRelative: .zero, outTangentRelative: outTangentRelative),
|
|
86
|
+
end: toVertex)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// If position is greater than or equal to 1, trim at end.
|
|
90
|
+
if position >= 1 {
|
|
91
|
+
return (
|
|
92
|
+
start: self,
|
|
93
|
+
trimPoint: CurveVertex(
|
|
94
|
+
point: toVertex.point,
|
|
95
|
+
inTangentRelative: toVertex.inTangentRelative,
|
|
96
|
+
outTangentRelative: .zero),
|
|
97
|
+
end: CurveVertex(
|
|
98
|
+
point: toVertex.point,
|
|
99
|
+
inTangentRelative: .zero,
|
|
100
|
+
outTangentRelative: toVertex.outTangentRelative))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if outTangentRelative.isZero, toVertex.inTangentRelative.isZero {
|
|
104
|
+
/// If both tangents are zero, then span to be trimmed is a straight line.
|
|
105
|
+
let trimPoint = point.interpolate(to: toVertex.point, amount: position)
|
|
106
|
+
return (
|
|
107
|
+
start: self,
|
|
108
|
+
trimPoint: CurveVertex(point: trimPoint, inTangentRelative: .zero, outTangentRelative: .zero),
|
|
109
|
+
end: toVertex)
|
|
110
|
+
}
|
|
111
|
+
/// Cutting by amount gives incorrect length....
|
|
112
|
+
/// One option is to cut by a stride until it gets close then edge it down.
|
|
113
|
+
/// Measuring a percentage of the spans does not equal the same as measuring a percentage of length.
|
|
114
|
+
/// This is where the historical trim path bugs come from.
|
|
115
|
+
let a = point.interpolate(to: outTangent, amount: position)
|
|
116
|
+
let b = outTangent.interpolate(to: toVertex.inTangent, amount: position)
|
|
117
|
+
let c = toVertex.inTangent.interpolate(to: toVertex.point, amount: position)
|
|
118
|
+
let d = a.interpolate(to: b, amount: position)
|
|
119
|
+
let e = b.interpolate(to: c, amount: position)
|
|
120
|
+
let f = d.interpolate(to: e, amount: position)
|
|
121
|
+
return (
|
|
122
|
+
start: CurveVertex(point: point, inTangent: inTangent, outTangent: a),
|
|
123
|
+
trimPoint: CurveVertex(point: f, inTangent: d, outTangent: e),
|
|
124
|
+
end: CurveVertex(point: toVertex.point, inTangent: c, outTangent: toVertex.outTangent))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// Trims a curve of a known length to a specific length and returns the points.
|
|
128
|
+
///
|
|
129
|
+
/// There is not a performant yet accurate way to cut a curve to a specific length.
|
|
130
|
+
/// This calls splitCurve(toVertex: position:) to split the curve and then measures
|
|
131
|
+
/// the length of the new curve. The function then iterates through the samples,
|
|
132
|
+
/// adjusting the position of the cut for a more precise cut.
|
|
133
|
+
/// Usually a single iteration is enough to get within 0.5 points of the desired
|
|
134
|
+
/// length.
|
|
135
|
+
///
|
|
136
|
+
/// This function should probably live in PathElement, since it deals with curve
|
|
137
|
+
/// lengths.
|
|
138
|
+
func trimCurve(toVertex: CurveVertex, atLength: CGFloat, curveLength: CGFloat, maxSamples: Int, accuracy: CGFloat = 1) ->
|
|
139
|
+
(start: CurveVertex, trimPoint: CurveVertex, end: CurveVertex)
|
|
140
|
+
{
|
|
141
|
+
var currentPosition = atLength / curveLength
|
|
142
|
+
var results = splitCurve(toVertex: toVertex, position: currentPosition)
|
|
143
|
+
|
|
144
|
+
if maxSamples == 0 {
|
|
145
|
+
return results
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for _ in 1...maxSamples {
|
|
149
|
+
let length = results.start.distanceTo(results.trimPoint)
|
|
150
|
+
let lengthDiff = atLength - length
|
|
151
|
+
/// Check if length is correct.
|
|
152
|
+
if lengthDiff < accuracy {
|
|
153
|
+
return results
|
|
154
|
+
}
|
|
155
|
+
let diffPosition = max(min((currentPosition / length) * lengthDiff, currentPosition * 0.5), currentPosition * -0.5)
|
|
156
|
+
currentPosition = diffPosition + currentPosition
|
|
157
|
+
results = splitCurve(toVertex: toVertex, position: currentPosition)
|
|
158
|
+
}
|
|
159
|
+
return results
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// The distance from the receiver to the provided vertex.
|
|
163
|
+
///
|
|
164
|
+
/// For lines (zeroed tangents) the distance between the two points is measured.
|
|
165
|
+
/// For curves the curve is iterated over by sample count and the points are measured.
|
|
166
|
+
/// This is ~99% accurate at a sample count of 30
|
|
167
|
+
func distanceTo(_ toVertex: CurveVertex, sampleCount: Int = 25) -> CGFloat {
|
|
168
|
+
if outTangentRelative.isZero, toVertex.inTangentRelative.isZero {
|
|
169
|
+
/// Return a linear distance.
|
|
170
|
+
return point.distanceTo(toVertex.point)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var distance: CGFloat = 0
|
|
174
|
+
|
|
175
|
+
var previousPoint = point
|
|
176
|
+
for i in 0..<sampleCount {
|
|
177
|
+
let pointOnCurve = splitCurve(toVertex: toVertex, position: CGFloat(i) / CGFloat(sampleCount)).trimPoint
|
|
178
|
+
distance = distance + previousPoint.distanceTo(pointOnCurve.point)
|
|
179
|
+
previousPoint = pointOnCurve.point
|
|
180
|
+
}
|
|
181
|
+
distance = distance + previousPoint.distanceTo(toVertex.point)
|
|
182
|
+
return distance
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//
|
|
2
|
+
// PathElement.swift
|
|
3
|
+
// lottie-swift
|
|
4
|
+
//
|
|
5
|
+
// Created by Brandon Withrow on 1/11/19.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import CoreGraphics
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
/// A path section, containing one point and its length to the previous point.
|
|
12
|
+
///
|
|
13
|
+
/// The relationship between this path element and the previous is implicit.
|
|
14
|
+
/// Ideally a path section would be defined by two vertices and a length.
|
|
15
|
+
/// We don't do this however, as it would effectively double the memory footprint
|
|
16
|
+
/// of path data.
|
|
17
|
+
///
|
|
18
|
+
struct PathElement {
|
|
19
|
+
|
|
20
|
+
// MARK: Lifecycle
|
|
21
|
+
|
|
22
|
+
/// Initializes a new path with length of 0
|
|
23
|
+
init(vertex: CurveVertex) {
|
|
24
|
+
length = 0
|
|
25
|
+
self.vertex = vertex
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Initializes a new path with length
|
|
29
|
+
private init(length: CGFloat, vertex: CurveVertex) {
|
|
30
|
+
self.length = length
|
|
31
|
+
self.vertex = vertex
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// MARK: Internal
|
|
35
|
+
|
|
36
|
+
/// The absolute Length of the path element.
|
|
37
|
+
let length: CGFloat
|
|
38
|
+
|
|
39
|
+
/// The vertex of the element
|
|
40
|
+
let vertex: CurveVertex
|
|
41
|
+
|
|
42
|
+
/// Returns a new path element define the span from the receiver to the new vertex.
|
|
43
|
+
func pathElementTo(_ toVertex: CurveVertex) -> PathElement {
|
|
44
|
+
PathElement(length: vertex.distanceTo(toVertex), vertex: toVertex)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func updateVertex(newVertex: CurveVertex) -> PathElement {
|
|
48
|
+
PathElement(length: length, vertex: newVertex)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Splits an element span defined by the receiver and fromElement to a position 0-1
|
|
52
|
+
func splitElementAtPosition(fromElement: PathElement, atLength: CGFloat) ->
|
|
53
|
+
(leftSpan: (start: PathElement, end: PathElement), rightSpan: (start: PathElement, end: PathElement))
|
|
54
|
+
{
|
|
55
|
+
/// Trim the span. Start and trim go into the first, trim and end go into second.
|
|
56
|
+
let trimResults = fromElement.vertex.trimCurve(toVertex: vertex, atLength: atLength, curveLength: length, maxSamples: 3)
|
|
57
|
+
|
|
58
|
+
/// Create the elements for the break
|
|
59
|
+
let spanAStart = PathElement(
|
|
60
|
+
length: fromElement.length,
|
|
61
|
+
vertex: CurveVertex(
|
|
62
|
+
point: fromElement.vertex.point,
|
|
63
|
+
inTangent: fromElement.vertex.inTangent,
|
|
64
|
+
outTangent: trimResults.start.outTangent))
|
|
65
|
+
/// Recalculating the length here is a waste as the trimCurve function also accurately calculates this length.
|
|
66
|
+
let spanAEnd = spanAStart.pathElementTo(trimResults.trimPoint)
|
|
67
|
+
|
|
68
|
+
let spanBStart = PathElement(vertex: trimResults.trimPoint)
|
|
69
|
+
let spanBEnd = spanBStart.pathElementTo(trimResults.end)
|
|
70
|
+
return (
|
|
71
|
+
leftSpan: (start: spanAStart, end: spanAEnd),
|
|
72
|
+
rightSpan: (start: spanBStart, end: spanBEnd))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Copyright (C) 2008 Apple Inc. All Rights Reserved.
|
|
2
|
+
//
|
|
3
|
+
// Redistribution and use in source and binary forms, with or without
|
|
4
|
+
// modification, are permitted provided that the following conditions
|
|
5
|
+
// are met:
|
|
6
|
+
// 1. Redistributions of source code must retain the above copyright
|
|
7
|
+
// notice, this list of conditions and the following disclaimer.
|
|
8
|
+
// 2. Redistributions in binary form must reproduce the above copyright
|
|
9
|
+
// notice, this list of conditions and the following disclaimer in the
|
|
10
|
+
// documentation and/or other materials provided with the distribution.
|
|
11
|
+
//
|
|
12
|
+
// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
13
|
+
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
14
|
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
15
|
+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
16
|
+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
17
|
+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
18
|
+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
19
|
+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
20
|
+
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
21
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
22
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
|
|
24
|
+
import CoreGraphics
|
|
25
|
+
import Foundation
|
|
26
|
+
|
|
27
|
+
/// Defines a cubic-bezier where the endpoints are (0, 0) and (1, 1)
|
|
28
|
+
///
|
|
29
|
+
/// The main use case is computing the progress of an animation at a given percent completion. For instance,
|
|
30
|
+
/// for a linear animation, the expected progress at `0.5` is `0.5`.
|
|
31
|
+
///
|
|
32
|
+
/// - Note: This is a Swift port of [Apple's WebKit code](
|
|
33
|
+
/// http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h
|
|
34
|
+
/// )
|
|
35
|
+
///
|
|
36
|
+
struct UnitBezier {
|
|
37
|
+
|
|
38
|
+
// MARK: Lifecycle
|
|
39
|
+
|
|
40
|
+
init(controlPoint1: CGPoint, controlPoint2: CGPoint) {
|
|
41
|
+
cx = 3.0 * controlPoint1.x
|
|
42
|
+
bx = 3.0 * (controlPoint2.x - controlPoint1.x) - cx
|
|
43
|
+
ax = 1.0 - cx - bx
|
|
44
|
+
cy = 3.0 * controlPoint1.y
|
|
45
|
+
by = 3.0 * (controlPoint2.y - controlPoint1.y) - cy
|
|
46
|
+
ay = 1.0 - cy - by
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// MARK: Internal
|
|
50
|
+
|
|
51
|
+
/// Computes the progress `y` value for a given `x` value
|
|
52
|
+
func value(for x: CGFloat, epsilon: CGFloat) -> CGFloat {
|
|
53
|
+
sampleCurveY(solveCurveX(x, epsilon: epsilon))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// MARK: Private
|
|
57
|
+
|
|
58
|
+
private let ax: CGFloat
|
|
59
|
+
private let bx: CGFloat
|
|
60
|
+
private let cx: CGFloat
|
|
61
|
+
private let ay: CGFloat
|
|
62
|
+
private let by: CGFloat
|
|
63
|
+
private let cy: CGFloat
|
|
64
|
+
|
|
65
|
+
/// Compute `x(t)` for a given `t`
|
|
66
|
+
private func sampleCurveX(_ t: CGFloat) -> CGFloat {
|
|
67
|
+
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
|
|
68
|
+
((ax * t + bx) * t + cx) * t
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Compute `y(t)` for a given `t`
|
|
72
|
+
private func sampleCurveY(_ t: CGFloat) -> CGFloat {
|
|
73
|
+
((ay * t + by) * t + cy) * t
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Compute `x'(t)` for a given `t`
|
|
77
|
+
private func sampleCurveDerivativeX(_ t: CGFloat) -> CGFloat {
|
|
78
|
+
(3.0 * ax * t + 2.0 * bx) * t + cx
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Given an `x` value solve for the parametric value `t`
|
|
82
|
+
private func solveCurveX(_ x: CGFloat, epsilon: CGFloat) -> CGFloat {
|
|
83
|
+
var t0, t1, t2, x2, d2: CGFloat
|
|
84
|
+
|
|
85
|
+
// First try a few iterations of Newton-Raphson -- normally very fast.
|
|
86
|
+
t2 = x
|
|
87
|
+
for _ in 0..<8 {
|
|
88
|
+
x2 = sampleCurveX(t2) - x
|
|
89
|
+
guard abs(x2) >= epsilon else { return t2 }
|
|
90
|
+
d2 = sampleCurveDerivativeX(t2)
|
|
91
|
+
guard abs(d2) >= 1e-6 else { break }
|
|
92
|
+
t2 = t2 - x2 / d2
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Fall back to the bisection method for reliability.
|
|
96
|
+
t0 = 0.0
|
|
97
|
+
t1 = 1.0
|
|
98
|
+
t2 = x
|
|
99
|
+
guard t2 >= t0 else { return t0 }
|
|
100
|
+
guard t2 <= t1 else { return t1 }
|
|
101
|
+
|
|
102
|
+
while t0 < t1 {
|
|
103
|
+
x2 = sampleCurveX(t2)
|
|
104
|
+
guard abs(x2 - x) >= epsilon else { return t2 }
|
|
105
|
+
if x > x2 {
|
|
106
|
+
t0 = t2
|
|
107
|
+
} else {
|
|
108
|
+
t1 = t2
|
|
109
|
+
}
|
|
110
|
+
t2 = (t1 - t0) * 0.5 + t0
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return t2
|
|
114
|
+
}
|
|
115
|
+
}
|