PathTest.kt revision 9c80550cbbe357a89e2abeeb9c7769fcaefc3a65
1245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy/*
2245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * Copyright (C) 2018 The Android Open Source Project
3245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy *
4245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * you may not use this file except in compliance with the License.
6245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * You may obtain a copy of the License at
7245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy *
8245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy *       http://www.apache.org/licenses/LICENSE-2.0
9245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy *
10245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * Unless required by applicable law or agreed to in writing, software
11245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * See the License for the specific language governing permissions and
14245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy * limitations under the License.
15245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy */
16245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
179c80550cbbe357a89e2abeeb9c7769fcaefc3a65Jake Whartonpackage androidx.core.graphics
18245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
19245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyimport android.graphics.Path
20245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyimport android.graphics.PointF
214df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guyimport android.graphics.RectF
228770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Whartonimport android.support.test.filters.SdkSuppress
239c80550cbbe357a89e2abeeb9c7769fcaefc3a65Jake Whartonimport androidx.testutils.fail
24245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyimport org.junit.Assert.assertEquals
25245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyimport org.junit.Assert.assertNotEquals
264df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guyimport org.junit.Assert.assertTrue
27245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyimport org.junit.Test
28245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
29245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guyclass PathTest {
308770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 26)
31245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy    @Test fun testFlattenEmptyPath() {
32245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        Path().flatten().forEach { fail("An empty path should not have segments: " + it) }
33245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy    }
34245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
358770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 26)
36245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy    @Test fun testFlatten() {
37245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        val p = Path()
38245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
39245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Single line
40245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(10.0f, 10.0f)
41245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        assertEquals(
42ec87f3d0ed8fb2a23ee2bbe8b323fdd7bdcbf4eaJake Wharton            PathSegment(PointF(), 0.0f, PointF(10.0f, 10.0f), 1.0f),
43ec87f3d0ed8fb2a23ee2bbe8b323fdd7bdcbf4eaJake Wharton            p.flatten().iterator().next())
44245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
45245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Only moves
46245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.reset()
47245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(10.0f, 10.0f)
48245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(20.0f, 20.0f)
49245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.flatten().forEach { fail("A path with only moves should not have segments: " + it) }
50245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
51245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Mix of moves/lines
52245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.reset()
53245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(10.0f, 10.0f)
54245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(20.0f, 20.0f)
55245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(60.0f, 20.0f)
56245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
57245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        var count = 0
58245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.flatten().forEach {
59245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy            count++
60245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy            assertNotEquals(it.startFraction, it.endFraction)
61245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        }
62245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        assertEquals(2, count)
63245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
64245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Mix of moves/lines, starts with moves, ends with moves
65245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.reset()
66245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Start with several moves
67245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(5.0f, 5.0f)
68245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(10.0f, 10.0f)
69245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(20.0f, 20.0f)
70245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(30.0f, 10.0f)
71245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // Several moves in the middle
72245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(40.0f, 10.0f)
73245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(50.0f, 10.0f)
74245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.lineTo(60.0f, 20.0f)
75245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        // End with several moves
76245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(10.0f, 10.0f)
77245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.moveTo(30.0f, 30.0f)
78245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy
79245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        count = 0
80245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        p.flatten().forEach {
81245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy            count++
82245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy            assertNotEquals(it.startFraction, it.endFraction)
83245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        }
84245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy        assertEquals(3, count)
85245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy    }
864df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
878770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
884df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testUnion() {
894df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
9026fbe188a9873102721c3585be159e0dccdfa6b2Romain Guy        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
914df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
924df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 + r2
934df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r = RectF()
944df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        p.computeBounds(r, true)
954df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
964df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
974df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
984df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
998770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
1004df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testAnd() {
1014df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
10226fbe188a9873102721c3585be159e0dccdfa6b2Romain Guy        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
1034df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1044df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 and r2
1054df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r = RectF()
1064df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        p.computeBounds(r, true)
1074df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1084df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
1094df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
1104df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1118770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
1124df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testDifference() {
1134df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
1144df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
1154df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1164df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 - r2
1174df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r = RectF()
1184df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        p.computeBounds(r, true)
1194df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1204df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        assertEquals(RectF(0.0f, 0.0f, 5.0f, 10.0f), r)
1214df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
1224df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1238770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
1244df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testIntersection() {
1254df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
12626fbe188a9873102721c3585be159e0dccdfa6b2Romain Guy        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
1274df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1284df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 or r2
1294df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r = RectF()
1304df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        p.computeBounds(r, true)
1314df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
13226fbe188a9873102721c3585be159e0dccdfa6b2Romain Guy        assertEquals(RectF(5.0f, 0.0f, 10.0f, 10.0f), r)
1334df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
1344df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1358770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
1364df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testEmptyIntersection() {
1374df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 2.0f, 2.0f, Path.Direction.CW) }
1384df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r2 = Path().apply { addRect(5.0f, 5.0f, 7.0f, 7.0f, Path.Direction.CW) }
1394df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1404df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 or r2
1414df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        assertTrue(p.isEmpty)
1424df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
1434df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1448770f84ffe4cf2ee98744f30ee8b4cd659a65633Jake Wharton    @SdkSuppress(minSdkVersion = 19)
1454df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    @Test fun testXor() {
1464df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
1474df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r2 = Path().apply { addRect(5.0f, 5.0f, 15.0f, 15.0f, Path.Direction.CW) }
1484df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1494df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val p = r1 xor r2
1504df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        val r = RectF()
1514df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        p.computeBounds(r, true)
1524df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy
1534df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
1544df8629cfe9f924b507ff26e53f896e025eb9ff7Romain Guy    }
155245f352e7e7a8b37faebc5aefd52ce98ae9f08e6Romain Guy}
156