blob: 83755ae605a393ad05bdba8dda73dbccffc786fd [file] [log] [blame]
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.graphics.shapes
import android.graphics.PointF
import androidx.core.graphics.minus
import androidx.test.filters.SmallTest
import kotlin.AssertionError
import kotlin.math.sqrt
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test
/**
* Tests the utility shape-creating functions like Circle and Star
*/
@SmallTest
class ShapesTest {
val Zero = PointF(0f, 0f)
val Epsilon = .01f
fun distance(start: PointF, end: PointF): Float {
val vector = end - start
return sqrt(vector.x * vector.x + vector.y * vector.y)
}
/**
* Test that the given point is radius distance away from [center]. If two radii are provided
* it is sufficient to lie on either one (used for testing points on stars).
*/
fun assertPointOnRadii(
point: PointF,
radius1: Float,
radius2: Float = radius1,
center: PointF = Zero
) {
val dist = distance(center, point)
try {
assertEquals(radius1, dist, Epsilon)
} catch (e: AssertionError) {
assertEquals(radius2, dist, Epsilon)
}
}
fun assertCubicOnRadii(
cubic: Cubic,
radius1: Float,
radius2: Float = radius1,
center: PointF = Zero
) {
assertPointOnRadii(cubic.p0, radius1, radius2, center)
assertPointOnRadii(cubic.p3, radius1, radius2, center)
}
/**
* Tests points along the curve of the cubic by comparing the distance from that point to the
* center, compared to the requested radius. The test is very lenient since the Circle shape is
* only a 4x cubic approximation of the circle and varies from the true circle.
*/
fun assertCircularCubic(cubic: Cubic, radius: Float, center: PointF) {
var t = 0f
while (t <= 1f) {
val pointOnCurve = cubic.pointOnCurve(t)
val distanceToPoint = distance(center, pointOnCurve)
assertEquals(radius, distanceToPoint, Epsilon)
t += .1f
}
}
fun assertCircleShape(shape: CubicShape, radius: Float = 1f, center: PointF = Zero) {
for (cubic in shape.cubics) {
assertCircularCubic(cubic, radius, center)
}
}
@Test
fun circleTest() {
val circle = Circle()
assertCircleShape(circle.toCubicShape())
val bigCircle = Circle(radius = 3f)
assertCircleShape(bigCircle.toCubicShape(), radius = 3f)
val center = PointF(1f, 2f)
val offsetCircle = Circle(center = center)
assertCircleShape(offsetCircle.toCubicShape(), center = center)
}
/**
* Stars are complicated. For the unrounded version, we can check whether the vertices
* are the right distance from the center. For the rounded versions, just check that the
* shape is within the appropriate bounds.
*/
@Test
fun starTest() {
var star = Star(4, innerRadius = .5f)
var shape = star.toCubicShape()
var radius = 1f
var innerRadius = .5f
for (cubic in shape.cubics) {
assertCubicOnRadii(cubic, radius, innerRadius)
}
val center = PointF(1f, 2f)
star = Star(4, innerRadius = innerRadius, center = center)
shape = star.toCubicShape()
for (cubic in shape.cubics) {
assertCubicOnRadii(cubic, radius, innerRadius, center)
}
radius = 4f
innerRadius = 2f
star = Star(4, radius, innerRadius)
shape = star.toCubicShape()
for (cubic in shape.cubics) {
assertCubicOnRadii(cubic, radius, innerRadius)
}
}
@Test
fun roundedStarTest() {
val rounding = CornerRounding(.1f)
val innerRounding = CornerRounding(.2f)
val perVtxRounded = listOf<CornerRounding>(rounding, innerRounding, rounding, innerRounding,
rounding, innerRounding, rounding, innerRounding)
var star = Star(4, innerRadius = .5f, rounding = rounding)
val min = PointF(-1f, -1f)
val max = PointF(1f, 1f)
assertInBounds(star.toCubicShape(), min, max)
star = Star(4, innerRadius = .5f, innerRounding = innerRounding)
assertInBounds(star.toCubicShape(), min, max)
star = Star(
4, innerRadius = .5f, rounding = rounding,
innerRounding = innerRounding
)
assertInBounds(star.toCubicShape(), min, max)
star = Star(4, innerRadius = .5f, perVertexRounding = perVtxRounded)
assertInBounds(star.toCubicShape(), min, max)
assertThrows(IllegalArgumentException::class.java) {
star = Star(
6, innerRadius = .5f,
perVertexRounding = perVtxRounded
)
}
}
}