Android Jetpack Compose, Canvas (2)
Search
🥊

Android Jetpack Compose, Canvas (2)

생성일
2022/12/27 11:52
태그

동그라미

원(동그라미)을 그려보자.
지난번에 설명한 내용을 따라 캔버스의 중앙에 점(drawCircle)을 찍어보자. 위와 같이 점을 찍으려면
drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = center )
Kotlin
복사
center에 center 값을 주면 정 중앙에 위치하게 된다. 이번에는 단순히 drawCircle을 이용해 원 하나를 그리고자 하는 것은 아니다.

목표

이번에 그리고자 하는 원은 이런 모습이다. drawCircle을 연속된 점(Dot)으로 사용해 을 그릴 것이다.
원을 그리려면 수포자도 한 번 쯤은 들어 봤을 반지름이 뭔지 알아야 한다. 원의 중심을 지나가는 직선인 지름의 절반이다.
왜 반지름을 알아야 하는가?
누구나 컴퍼스에 연필을 끼워 원(동그라미)를 그려 봤을 것이다. 여기서 중심점으로 부터 연필 까지가 반지름이다.
중심점과 연필의 거리를 10cm로 했다면 반지름은 10cm이다.
중심점으로 부터 x축으로 10cm을 지나 점을 찍어보자.
코드로 한다면 아래와 같다.
// 중심점 drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = center ) // 10cm 옆의 점 drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = Offset(center.x + 반지름, center.y), radius = 20f ), radius = 20f, center = Offset(center.x + 반지름, center.y) )
Kotlin
복사

연속된 점으로 커다란 원 드로잉

원은 지난번에 설명한 x, y 좌표를 이용해 그릴 수 없다. x값을 더하고 빼고, y값을 더하고 빼서는 원을 그릴 수 없다.
중심점으로 부터 반지름 길이 만큼 지나 점을 찍었는데, 어떻게 하면 컴퍼스로 원을 그리듯 다음 점을 찍을 수 있을까? → 그 다음 점은 각도 값을 더 주면 된다. 각도 값을 줄 때, x값에는 cos(), y값에는 sin()으로 계산해 주면 된다. 예를 들어 90도 만큼 주고 싶다면 x = x + cos( 90도.toRadian() ) * 반지름, y = y + sin( 90도.toRadian() ) * 반지름

각도

한 바퀴를 360도로 나누어 표현하는데, 이는 60분법이라고 한다. 여기서 단위는 각도(Degree)이다.
각도는 우리에게 친숙한 단위이다. “360도 회전”, “90도 직각 어깨” 등 일상 속에서 흔히 접할 수 있다.
그러나, 우리는 각도가 아닌 호도(Radian)를 사용해야 한다.

호도

굉장히 복잡해 보이지만, 위 이미지에서 안쪽에 표시된 숫자는 각도(Degree), 밖에 표시된 숫자는 호도(Radian)이다.
“각도는 뭐고 호도는 뭔데? 각각 언제 쓰는 건데?” 라고 한다면, 생활코딩 이고잉 선생님의 표현을 빌려 설명한다. ”한국에서는 미터를 사용하고, 미국에서는 피트를 쓴다. 그냥 한국에 가면 미터를 쓰면 되고~ 미국에 가면 피트를 쓰면 되는거다~”
우리는 그냥 각도(Degree)를 쓰면 되고, 컴퓨터에서는 호도(Radian)를 쓰면 되는거다~

변환

각도  호도, 아래 공식을 이용해 서로를 변환해 줄 수도 있다.
각도(Degree) → 호도(Radian): degree * pi/180
호도(Radian) → 각도(Degree): radian * 180/pi

Kotlin에서의 변환

Kotlin에서는 아래와 같이 쓰면 된다.
Math.toDegrees(10.0) //호도를 입력하면 각도를 반환 Math.toRadians(10.0) //각도를 입력하면 호도를 반환
Kotlin
복사
우리에게 친숙한 것은 각도이기 때문에, 각도를 호도로 바꿔서 컴퓨터에게 원을 그리도록 시키면 된다.
** 앞으로는 Degree는 ‘도’, Radian은 ‘rad’라는 단위를 사용하여 설명한다.

참고사항

여기서도 동일하게 Degree, Radian 모두
3시 방향을 0으로 시작해 값이 증가함에 따라 시계 방향으로 그려진다.

원 드로잉

거의 다 왔다. 이제 부터는 코드를 이용해 설명한다.
@Composable fun MyCircle(){ Canvas( modifier = Modifier .background(color = Color.LightGray) .fillMaxSize() ) { drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = center ) }
Kotlin
복사
이렇게 코드를 그려보자
center에 표시할 점을 찍었다. 우선적으로 할 것은 중앙으로부터 400f가 떨어진 곳에 점 하나를 떠 찍어준다.

우측에 점 추가

val 반지름 = 400f drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = center ) drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = Offset(center.x + 반지름, center.y), radius = 20f ), radius = 20f, center = Offset(center.x + 반지름, center.y) )
Kotlin
복사
우측에 점이 하나 더 찍힌걸 확인할 수 있다. 이제 시계 방향으로 이어서 연속된 점을 찍어준다.

시계 방향으로 1rad 만큼 드로잉

for (i in 0..Math.toDegrees(1.0).toInt()) { //1rad drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = Offset( center.x + cos(Math.toRadians(i.toDouble()).toFloat()) * 반지름, center.y + sin(Math.toRadians(i.toDouble()).toFloat()) * 반지름 ) ) }
Kotlin
복사
생각보다 길게 드로잉 되었다. 1rad == 약 57.2958도 이기 때문이다.

시계 방향으로 90도 만큼 드로잉

익숙한 각도인 90도로 값을 줘보자. 90도는 약 1.5708rad이다.
for (i in 0..Math.toDegrees(1.5708).toInt()) // 1.5708rad
Kotlin
복사
3시 방향부터 6시 방향까지 90도가 그려졌다. 앞서 설명했듯이 원은 단순히 x, y좌표를 가지고서는 그릴 수 없다. 극좌표를 이해하고 삼각함수를 이용해 그려야 하지만, 컴퓨터가 알아서 다 해준다.
우리가 알아야할 것은 딱 2개다.
cos(): x에 대한 각도(라디안) 값
sin(): y에 대한 각도(라디안) 값
center = Offset( center.x + cos(Math.toRadians(각도.toDouble()).toFloat()) * 반지름, center.y + sin(Math.toRadians(각도.toDouble()).toFloat()) * 반지름 )
Kotlin
복사

360도 한 바퀴 드로잉

이제는 한 바퀴 연속된 점을 찍어 원을 그려보자. for문에 0부터 360까지 반복해 점을 찍어줄텐데, 각도를 rad로 변환하여 그려준다.
for (각도 in 0..360) { // 360도 한 바퀴 drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = Offset( center.x + cos(Math.toRadians(각도.toDouble()).toFloat()) * 반지름, center.y + sin(Math.toRadians(각도.toDouble()).toFloat()) * 반지름 ) ) }
Kotlin
복사

전체 코드

@Composable fun MyCircle() { Canvas( modifier = Modifier .background(color = Color.LightGray) .fillMaxSize() ) { val 반지름 = 400f drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = center ) for (각도 in 0..360) { drawCircle( brush = Brush.radialGradient( colors = listOf( Color.Red, Color.Yellow ), center = center, radius = 20f ), radius = 20f, center = Offset( center.x + cos(Math.toRadians(각도.toDouble()).toFloat()) * 반지름, center.y + sin(Math.toRadians(각도.toDouble()).toFloat()) * 반지름 ) ) } } }
Kotlin
복사

정리

Offset에 x는 Math.cos(라디안), y는 Math.sin(라디안) 값을 주면 된다.
한 바퀴가 라디안으로 몇인지 알아 내는 것도 귀찮으니 우리에게 친숙한 단위인 각도를 라디안으로 변환해서 사용하면 된다. ( Math.toDegree(), Math.toRadians() )

참고