1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.transition;
18
19import static org.junit.Assert.assertEquals;
20
21import android.graphics.Path;
22import android.support.test.filters.SmallTest;
23import android.support.test.runner.AndroidJUnit4;
24
25import org.junit.Test;
26import org.junit.runner.RunWith;
27
28@SmallTest
29@RunWith(AndroidJUnit4.class)
30public class ArcMotionTest extends PathMotionTest {
31
32    @Test
33    public void test90Quadrants() {
34        ArcMotion arcMotion = new ArcMotion();
35        arcMotion.setMaximumAngle(90);
36
37        Path expected = arcWithPoint(0, 100, 100, 0, 100, 100);
38        Path path = arcMotion.getPath(0, 100, 100, 0);
39        assertPathMatches(expected, path);
40
41        expected = arcWithPoint(100, 0, 0, -100, 0, 0);
42        path = arcMotion.getPath(100, 0, 0, -100);
43        assertPathMatches(expected, path);
44
45        expected = arcWithPoint(0, -100, -100, 0, 0, 0);
46        path = arcMotion.getPath(0, -100, -100, 0);
47        assertPathMatches(expected, path);
48
49        expected = arcWithPoint(-100, 0, 0, 100, -100, 100);
50        path = arcMotion.getPath(-100, 0, 0, 100);
51        assertPathMatches(expected, path);
52    }
53
54    @Test
55    public void test345Triangles() {
56        // 3-4-5 triangles are easy to calculate the control points
57        ArcMotion arcMotion = new ArcMotion();
58        arcMotion.setMaximumAngle(90);
59        Path expected;
60        Path path;
61
62        expected = arcWithPoint(0, 120, 160, 0, 125, 120);
63        path = arcMotion.getPath(0, 120, 160, 0);
64        assertPathMatches(expected, path);
65
66        expected = arcWithPoint(0, 160, 120, 0, 120, 125);
67        path = arcMotion.getPath(0, 160, 120, 0);
68        assertPathMatches(expected, path);
69
70        expected = arcWithPoint(-120, 0, 0, 160, -120, 125);
71        path = arcMotion.getPath(-120, 0, 0, 160);
72        assertPathMatches(expected, path);
73
74        expected = arcWithPoint(-160, 0, 0, 120, -125, 120);
75        path = arcMotion.getPath(-160, 0, 0, 120);
76        assertPathMatches(expected, path);
77
78        expected = arcWithPoint(0, -120, -160, 0, -35, 0);
79        path = arcMotion.getPath(0, -120, -160, 0);
80        assertPathMatches(expected, path);
81
82        expected = arcWithPoint(0, -160, -120, 0, 0, -35);
83        path = arcMotion.getPath(0, -160, -120, 0);
84        assertPathMatches(expected, path);
85
86        expected = arcWithPoint(120, 0, 0, -160, 0, -35);
87        path = arcMotion.getPath(120, 0, 0, -160);
88        assertPathMatches(expected, path);
89
90        expected = arcWithPoint(160, 0, 0, -120, 35, 0);
91        path = arcMotion.getPath(160, 0, 0, -120);
92        assertPathMatches(expected, path);
93    }
94
95    private static Path arcWithPoint(float startX, float startY, float endX, float endY,
96            float eX, float eY) {
97        float c1x = (eX + startX) / 2;
98        float c1y = (eY + startY) / 2;
99        float c2x = (eX + endX) / 2;
100        float c2y = (eY + endY) / 2;
101        Path path = new Path();
102        path.moveTo(startX, startY);
103        path.cubicTo(c1x, c1y, c2x, c2y, endX, endY);
104        return path;
105    }
106
107    @Test
108    public void testMaximumAngle() {
109        ArcMotion arcMotion = new ArcMotion();
110        arcMotion.setMaximumAngle(45f);
111        assertEquals(45f, arcMotion.getMaximumAngle(), 0.0f);
112
113        float ratio = (float) Math.tan(Math.PI / 8);
114        float ex = 50 + (50 * ratio);
115        float ey = ex;
116
117        Path expected = arcWithPoint(0, 100, 100, 0, ex, ey);
118        Path path = arcMotion.getPath(0, 100, 100, 0);
119        assertPathMatches(expected, path);
120    }
121
122    @Test
123    public void testMinimumHorizontalAngle() {
124        ArcMotion arcMotion = new ArcMotion();
125        arcMotion.setMinimumHorizontalAngle(45);
126        assertEquals(45, arcMotion.getMinimumHorizontalAngle(), 0.0f);
127
128        float ex = 37.5f;
129        float ey = (float) (Math.tan(Math.PI / 4) * 50);
130        Path expected = arcWithPoint(0, 0, 100, 50, ex, ey);
131        Path path = arcMotion.getPath(0, 0, 100, 50);
132        assertPathMatches(expected, path);
133
134        // Pretty much the same, but follows a different path.
135        expected = arcWithPoint(0, 0, 100.001f, 50, ex, ey);
136        path = arcMotion.getPath(0, 0, 100.001f, 50);
137        assertPathMatches(expected, path);
138
139        // Moving in the opposite direction.
140        expected = arcWithPoint(100, 50, 0, 0, ex, ey);
141        path = arcMotion.getPath(100, 50, 0, 0);
142        assertPathMatches(expected, path);
143
144        // With x < y.
145        ex = 0;
146        ey = (float) (Math.tan(Math.PI / 4) * 62.5f);
147        expected = arcWithPoint(0, 0, 50, 100, ex, ey);
148        path = arcMotion.getPath(0, 0, 50, 100);
149        assertPathMatches(expected, path);
150
151        // Pretty much the same, but follows a different path.
152        expected = arcWithPoint(0, 0, 50, 100.001f, ex, ey);
153        path = arcMotion.getPath(0, 0, 50, 100.001f);
154        assertPathMatches(expected, path);
155
156        // Moving in the opposite direction.
157        expected = arcWithPoint(50, 100, 0, 0, ex, ey);
158        path = arcMotion.getPath(50, 100, 0, 0);
159        assertPathMatches(expected, path);
160    }
161
162    @Test
163    public void testMinimumVerticalAngle() {
164        ArcMotion arcMotion = new ArcMotion();
165        arcMotion.setMinimumVerticalAngle(45);
166        assertEquals(45, arcMotion.getMinimumVerticalAngle(), 0.0f);
167
168        float ex = 0;
169        float ey = 62.5f;
170        Path expected = arcWithPoint(0, 0, 50, 100, ex, ey);
171        Path path = arcMotion.getPath(0, 0, 50, 100);
172        assertPathMatches(expected, path);
173
174        // Pretty much the same, but follows a different path.
175        expected = arcWithPoint(0, 0, 50, 100.001f, ex, ey);
176        path = arcMotion.getPath(0, 0, 50, 100.001f);
177        assertPathMatches(expected, path);
178
179        // Moving in opposite direction.
180        expected = arcWithPoint(50, 100, 0, 0, ex, ey);
181        path = arcMotion.getPath(50, 100, 0, 0);
182        assertPathMatches(expected, path);
183
184        // With x > y.
185        ex = (float) (Math.tan(Math.PI / 4) * 37.5f);
186        ey = 50;
187        expected = arcWithPoint(0, 0, 100, 50, ex, ey);
188        path = arcMotion.getPath(0, 0, 100, 50);
189        assertPathMatches(expected, path);
190
191        // Pretty much the same, but follows a different path.
192        expected = arcWithPoint(0, 0, 100.001f, 50, ex, ey);
193        path = arcMotion.getPath(0, 0, 100.001f, 50);
194        assertPathMatches(expected, path);
195
196        // Moving in opposite direction.
197        expected = arcWithPoint(100, 50, 0, 0, ex, ey);
198        path = arcMotion.getPath(100, 50, 0, 0);
199        assertPathMatches(expected, path);
200
201    }
202
203}
204