• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.airbnb.lottie.utils;
2 
3 import android.graphics.Path;
4 import android.graphics.PointF;
5 import androidx.annotation.FloatRange;
6 
7 import com.airbnb.lottie.animation.content.KeyPathElementContent;
8 import com.airbnb.lottie.model.CubicCurveData;
9 import com.airbnb.lottie.model.KeyPath;
10 import com.airbnb.lottie.model.content.ShapeData;
11 
12 import java.util.List;
13 
14 public class MiscUtils {
15   private static PointF pathFromDataCurrentPoint = new PointF();
16 
addPoints(PointF p1, PointF p2)17   public static PointF addPoints(PointF p1, PointF p2) {
18     return new PointF(p1.x + p2.x, p1.y + p2.y);
19   }
20 
getPathFromData(ShapeData shapeData, Path outPath)21   public static void getPathFromData(ShapeData shapeData, Path outPath) {
22     outPath.reset();
23     PointF initialPoint = shapeData.getInitialPoint();
24     outPath.moveTo(initialPoint.x, initialPoint.y);
25     pathFromDataCurrentPoint.set(initialPoint.x, initialPoint.y);
26     for (int i = 0; i < shapeData.getCurves().size(); i++) {
27       CubicCurveData curveData = shapeData.getCurves().get(i);
28       PointF cp1 = curveData.getControlPoint1();
29       PointF cp2 = curveData.getControlPoint2();
30       PointF vertex = curveData.getVertex();
31 
32       if (cp1.equals(pathFromDataCurrentPoint) && cp2.equals(vertex)) {
33         // On some phones like Samsung phones, zero valued control points can cause artifacting.
34         // https://github.com/airbnb/lottie-android/issues/275
35         //
36         // This does its best to add a tiny value to the vertex without affecting the final
37         // animation as much as possible.
38         // outPath.rMoveTo(0.01f, 0.01f);
39         outPath.lineTo(vertex.x, vertex.y);
40       } else {
41         outPath.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, vertex.x, vertex.y);
42       }
43       pathFromDataCurrentPoint.set(vertex.x, vertex.y);
44     }
45     if (shapeData.isClosed()) {
46       outPath.close();
47     }
48   }
49 
lerp(float a, float b, @FloatRange(from = 0f, to = 1f) float percentage)50   public static float lerp(float a, float b, @FloatRange(from = 0f, to = 1f) float percentage) {
51     return a + percentage * (b - a);
52   }
53 
lerp(double a, double b, @FloatRange(from = 0f, to = 1f) double percentage)54   public static double lerp(double a, double b, @FloatRange(from = 0f, to = 1f) double percentage) {
55     return a + percentage * (b - a);
56   }
57 
lerp(int a, int b, @FloatRange(from = 0f, to = 1f) float percentage)58   public static int lerp(int a, int b, @FloatRange(from = 0f, to = 1f) float percentage) {
59     return (int) (a + percentage * (b - a));
60   }
61 
floorMod(float x, float y)62   static int floorMod(float x, float y) {
63     return floorMod((int) x, (int) y);
64   }
65 
floorMod(int x, int y)66   private static int floorMod(int x, int y) {
67     return x - y * floorDiv(x, y);
68   }
69 
floorDiv(int x, int y)70   private static int floorDiv(int x, int y) {
71     int r = x / y;
72     boolean sameSign = (x ^ y) >= 0;
73     int mod = x % y;
74     if (!sameSign && mod != 0) {
75       r--;
76     }
77     return r;
78   }
79 
clamp(int number, int min, int max)80   public static int clamp(int number, int min, int max) {
81     return Math.max(min, Math.min(max, number));
82   }
83 
clamp(float number, float min, float max)84   public static float clamp(float number, float min, float max) {
85     return Math.max(min, Math.min(max, number));
86   }
87 
contains(float number, float rangeMin, float rangeMax)88   public static boolean contains(float number, float rangeMin, float rangeMax) {
89     return number >= rangeMin && number <= rangeMax;
90   }
91 
92   /**
93    * Helper method for any {@link KeyPathElementContent} that will check if the content
94    * fully matches the keypath then will add itself as the final key, resolve it, and add
95    * it to the accumulator list.
96    *
97    * Any {@link KeyPathElementContent} should call through to this as its implementation of
98    * {@link KeyPathElementContent#resolveKeyPath(KeyPath, int, List, KeyPath)}.
99    */
resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator, KeyPath currentPartialKeyPath, KeyPathElementContent content)100   public static void resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator,
101       KeyPath currentPartialKeyPath, KeyPathElementContent content) {
102     if (keyPath.fullyResolvesTo(content.getName(), depth)) {
103       currentPartialKeyPath = currentPartialKeyPath.addKey(content.getName());
104       accumulator.add(currentPartialKeyPath.resolve(content));
105     }
106   }
107 }
108