1 /*
2  * Copyright 2022 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 
17 package androidx.graphics.shapes.test
18 
19 import android.graphics.PointF
20 import androidx.core.graphics.plus
21 import androidx.graphics.shapes.CornerRounding
22 import androidx.graphics.shapes.RoundedPolygon
23 import androidx.graphics.shapes.star
24 import kotlin.math.cos
25 import kotlin.math.sin
26 
27 /** This class holds standard Material shape design implementations. */
28 class MaterialShapes {
29     companion object {
30 
31         private val FloatPI = Math.PI.toFloat()
32 
33         // TODO: remove this when it is integrated into Ktx
timesnull34         operator fun PointF.times(factor: Float): PointF {
35             return PointF(this.x * factor, this.y * factor)
36         }
37 
38         private val SquarePoints = floatArrayOf(1f, 1f, -1f, 1f, -1f, -1f, 1f, -1f)
39 
toRadiansnull40         internal fun Float.toRadians(): Float {
41             return this / 360f * 2 * FloatPI
42         }
43 
44         private val Zero = PointF(0f, 0f)
45 
directionVectornull46         internal fun directionVector(angleRadians: Float) =
47             PointF(cos(angleRadians), sin(angleRadians))
48 
49         private fun radialToCartesian(radius: Float, angleRadians: Float, center: PointF = Zero) =
50             directionVector(angleRadians) * radius + center
51 
52         @JvmStatic
53         fun triangleChip(innerRadius: Float, rounding: CornerRounding): RoundedPolygon {
54             val points =
55                 floatArrayOf(
56                     radialToCartesian(1f, 270f.toRadians()).x,
57                     radialToCartesian(1f, 270f.toRadians()).y,
58                     radialToCartesian(1f, 30f.toRadians()).x,
59                     radialToCartesian(1f, 30f.toRadians()).y,
60                     radialToCartesian(innerRadius, 90f.toRadians()).x,
61                     radialToCartesian(innerRadius, 90f.toRadians()).y,
62                     radialToCartesian(1f, 150f.toRadians()).x,
63                     radialToCartesian(1f, 150f.toRadians()).y
64                 )
65             return RoundedPolygon(points, rounding)
66         }
67 
68         @JvmOverloads
69         @JvmStatic
quartynull70         fun quarty(roundnessRatio: Float, smooth: Float = 0f): RoundedPolygon {
71             return RoundedPolygon(
72                 SquarePoints,
73                 perVertexRounding =
74                     listOf(
75                         CornerRounding(),
76                         CornerRounding(),
77                         CornerRounding(),
78                         CornerRounding(roundnessRatio, smooth)
79                     )
80             )
81         }
82 
83         @JvmOverloads
84         @JvmStatic
blobRnull85         fun blobR(innerRadius: Float, roundness: Float, smooth: Float = 0f): RoundedPolygon {
86             val sx = innerRadius.coerceAtLeast(0.1f)
87             val sy = roundness.coerceAtLeast(0.1f)
88             return RoundedPolygon(
89                 vertices =
90                     floatArrayOf(
91                         -sx,
92                         -sy,
93                         sx,
94                         -sy,
95                         sx,
96                         sy,
97                         -sx,
98                         sy,
99                     ),
100                 CornerRounding(roundness, smooth)
101             )
102         }
103 
104         @JvmOverloads
105         @JvmStatic
cornerSouthEastnull106         fun cornerSouthEast(roundnessRatio: Float, smooth: Float = 0f): RoundedPolygon {
107             return RoundedPolygon(
108                 SquarePoints,
109                 perVertexRounding =
110                     listOf(
111                         CornerRounding(roundnessRatio, smooth),
112                         CornerRounding(),
113                         CornerRounding(),
114                         CornerRounding()
115                     )
116             )
117         }
118 
119         @JvmStatic
scallopnull120         fun scallop(): RoundedPolygon {
121             return RoundedPolygon.star(
122                 12,
123                 innerRadius = .928f,
124                 rounding = CornerRounding(radius = .928f)
125             )
126         }
127 
128         @JvmOverloads
129         @JvmStatic
clovernull130         fun clover(
131             rounding: Float = .32f,
132             innerRadius: Float = .352f,
133             innerRounding: CornerRounding? = null,
134             scale: Float = 1f
135         ): RoundedPolygon {
136             val poly =
137                 RoundedPolygon.star(
138                     4,
139                     innerRadius = innerRadius,
140                     rounding = CornerRounding(rounding * scale),
141                     innerRounding = innerRounding
142                 )
143             return poly
144         }
145 
146         @JvmStatic
alicenull147         fun alice(): RoundedPolygon {
148             return triangleChip(0.1f, CornerRounding(.22f))
149         }
150 
151         @JvmStatic
wiggleStarnull152         fun wiggleStar(): RoundedPolygon {
153             return RoundedPolygon.star(8, .784f, rounding = CornerRounding(.82f))
154         }
155 
156         @JvmStatic
wovelnull157         fun wovel(): RoundedPolygon {
158             return RoundedPolygon.star(15, .892f, rounding = CornerRounding(1f))
159         }
160 
161         @JvmStatic
morenull162         fun more(): RoundedPolygon {
163             return RoundedPolygon(numVertices = 3, rounding = CornerRounding(.2f))
164         }
165 
166         @JvmStatic
cube5Dnull167         fun cube5D(): RoundedPolygon {
168             return RoundedPolygon(numVertices = 6, rounding = CornerRounding(.3f))
169         }
170 
171         @JvmStatic
pentagonnull172         fun pentagon(): RoundedPolygon {
173             return RoundedPolygon(numVertices = 5, rounding = CornerRounding(.3f))
174         }
175     }
176 }
177