# Dart에서의 2D 그래픽 처리

#### 그래픽 처리 개요

Dart에서 2D 그래픽을 처리하기 위해서는 다양한 라이브러리와 도구를 활용할 수 있다. 특히 Flutter는 Dart에서 2D 그래픽을 다루는 데 매우 유용한 도구를 제공한다. Flutter에서는 `CustomPainter` 클래스를 활용하여 화면에 2D 그래픽을 그릴 수 있다. 이 클래스는 화면을 직접 제어할 수 있는 강력한 기능을 제공하며, 다양한 그래픽 요소를 캔버스에 그릴 수 있도록 지원한다.

#### CustomPainter 개념

`CustomPainter`는 Flutter에서 제공하는 클래스로, 사용자가 원하는 그래픽 요소를 그릴 수 있는 도구이다. 이 클래스를 통해 기본적인 도형부터 복잡한 패턴에 이르기까지 다양한 2D 그래픽을 구현할 수 있다. 다음은 `CustomPainter`를 사용하는 방법에 대한 기본 흐름이다.

```dart
class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 5;

    // 직선을 그린다
    canvas.drawLine(Offset(0, 0), Offset(size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}
```

위의 예제는 간단한 직선을 그리는 코드이다. `Canvas` 객체는 화면에 그리는 역할을 하고, `Paint` 객체는 그릴 도형의 스타일을 정의한다.

#### 2D 좌표계

Dart에서의 2D 그래픽 처리는 기본적으로 좌표계를 바탕으로 한다. `Canvas`에서의 좌표계는 왼쪽 상단을 기준으로 하여 오른쪽과 아래쪽으로 증가하는 방식이다. 이 좌표계는 수학에서의 좌표계와 다르며, 원점을 기준으로 X축은 오른쪽, Y축은 아래쪽으로 향한다.

이를 수학적으로 표현하면 다음과 같다.

$$
\mathbf{x}*{canvas} = \begin{pmatrix} x*{1} \ y\_{1} \end{pmatrix}, \quad \mathbf{x}*{math} = \begin{pmatrix} x*{1} \ -y\_{1} \end{pmatrix}
$$

#### 직선 그리기

직선을 그리는 것은 2D 그래픽에서 가장 기본적인 작업 중 하나이다. Dart에서는 `Canvas` 객체를 사용하여 직선을 그릴 수 있다. 직선은 두 점 사이를 연결하는 것으로, 두 점을 `(x_1, y_1)`과 `(x_2, y_2)`로 정의할 수 있다. 수학적으로 직선 방정식은 다음과 같이 정의할 수 있다.

$$
y - y\_1 = \frac{y\_2 - y\_1}{x\_2 - x\_1} (x - x\_1)
$$

이 방정식을 통해 두 점 사이의 직선을 그릴 수 있다. Dart에서는 이를 다음과 같이 구현할 수 있다.

```dart
canvas.drawLine(Offset(x1, y1), Offset(x2, y2), paint);
```

여기서 `Offset`은 좌표를 나타내는 객체이고, `paint`는 그릴 스타일을 지정한다.

#### 원 그리기

Dart에서는 `drawCircle` 메소드를 사용하여 원을 그릴 수 있다. 원은 중심점과 반지름으로 정의되며, 수학적으로는 다음과 같이 정의된다.

$$
(x - h)^2 + (y - k)^2 = r^2
$$

여기서 $(h, k)$는 원의 중심 좌표이고, $r$은 반지름이다. 이 공식을 바탕으로 Dart에서 원을 그리는 방법은 다음과 같다.

```dart
canvas.drawCircle(Offset(h, k), r, paint);
```

#### 다각형 그리기

다각형을 그리는 방법은 여러 개의 직선을 연결하여 닫힌 도형을 만드는 방식이다. Dart에서는 `drawPath` 메소드를 사용하여 여러 점을 연결한 도형을 그릴 수 있다. 예를 들어, 삼각형을 그리기 위해서는 세 개의 점을 지정하고 이들을 `Path` 객체로 연결하면 된다.

수학적으로 삼각형은 세 꼭짓점 $(x\_1, y\_1)$, $(x\_2, y\_2)$, $(x\_3, y\_3)$로 정의되며, Dart에서 이를 그리는 방법은 다음과 같다.

```dart
var path = Path();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.close();

canvas.drawPath(path, paint);
```

이 코드는 세 점을 연결하여 삼각형을 그린 후, 경로를 닫는 `close` 메소드를 호출하여 다각형을 완성한다.

#### 곡선 그리기

Dart에서는 `Canvas` 객체를 통해 다양한 형태의 곡선을 그릴 수 있다. 곡선은 기본적으로 베지어 곡선을 사용하여 구현된다. Dart에서 제공하는 `drawPath` 메소드를 사용하면 곡선을 더욱 정밀하게 그릴 수 있다.

**2차 베지어 곡선**

2차 베지어 곡선은 시작점, 제어점, 끝점으로 정의된다. 수학적으로, 2차 베지어 곡선은 다음과 같은 식으로 표현된다.

$$
\mathbf{P}(t) = (1 - t)^2 \mathbf{P}\_0 + 2(1 - t)t \mathbf{P}\_1 + t^2 \mathbf{P}\_2, \quad 0 \leq t \leq 1
$$

여기서 $\mathbf{P}\_0$는 시작점, $\mathbf{P}\_1$은 제어점, $\mathbf{P}\_2$는 끝점이다. Dart에서 2차 베지어 곡선을 그리기 위해 `quadraticBezierTo` 메소드를 사용할 수 있다.

```dart
var path = Path();
path.moveTo(startX, startY);
path.quadraticBezierTo(controlX, controlY, endX, endY);

canvas.drawPath(path, paint);
```

**3차 베지어 곡선**

3차 베지어 곡선은 시작점, 두 개의 제어점, 끝점으로 정의된다. 수학적으로는 다음과 같은 식으로 표현된다.

$$
\mathbf{P}(t) = (1 - t)^3 \mathbf{P}\_0 + 3(1 - t)^2 t \mathbf{P}\_1 + 3(1 - t) t^2 \mathbf{P}\_2 + t^3 \mathbf{P}\_3, \quad 0 \leq t \leq 1
$$

여기서 $\mathbf{P}\_0$는 시작점, $\mathbf{P}\_1$과 $\mathbf{P}\_2$는 제어점, $\mathbf{P}\_3$는 끝점이다. 3차 베지어 곡선을 Dart에서 구현할 때는 `cubicTo` 메소드를 사용한다.

```dart
var path = Path();
path.moveTo(startX, startY);
path.cubicTo(controlX1, controlY1, controlX2, controlY2, endX, endY);

canvas.drawPath(path, paint);
```

#### 그라디언트 및 채우기

Dart에서는 2D 그래픽을 그릴 때 색상뿐만 아니라 그라디언트(Gradient)도 활용할 수 있다. `Paint` 객체를 설정하여 색상을 그라디언트로 지정하면 점진적인 색상 변화를 표현할 수 있다.

**선형 그라디언트**

선형 그라디언트는 두 점 사이의 색상 변화를 표현한다. 수학적으로는 두 점 $(x\_1, y\_1)$에서 $(x\_2, y\_2)$까지의 선을 따라 색상이 변하는 방식이다. Dart에서는 `LinearGradient` 클래스를 사용하여 선형 그라디언트를 설정할 수 있다.

```dart
var paint = Paint()
  ..shader = LinearGradient(
    colors: [Colors.red, Colors.blue],
    begin: Alignment.topLeft,
    end: Alignment.bottomRight,
  ).createShader(Rect.fromLTWH(0, 0, 200, 200));

canvas.drawRect(Rect.fromLTWH(0, 0, 200, 200), paint);
```

**방사형 그라디언트**

방사형 그라디언트는 중심점에서 바깥쪽으로 색상이 변하는 방식이다. 수학적으로 방사형 그라디언트는 중심점 $(x\_c, y\_c)$에서 반지름 $r$까지의 범위 내에서 색상이 변화하는 패턴을 나타낸다. Dart에서 이를 구현할 때는 `RadialGradient` 클래스를 사용한다.

```dart
var paint = Paint()
  ..shader = RadialGradient(
    colors: [Colors.yellow, Colors.green],
  ).createShader(Rect.fromCircle(center: Offset(100, 100), radius: 100));

canvas.drawCircle(Offset(100, 100), 100, paint);
```

#### 클리핑 (Clipping)

클리핑은 그래픽을 그릴 때 특정 영역 외부의 부분을 자르는 작업을 의미한다. 이를 통해 그래픽의 일부만 보이게 할 수 있으며, Dart에서는 `clipRect`, `clipPath` 등을 사용하여 클리핑 작업을 할 수 있다. 예를 들어, 사각형 영역을 클리핑하여 그 안에서만 그래픽을 그리도록 할 수 있다.

```dart
canvas.clipRect(Rect.fromLTWH(50, 50, 100, 100));
canvas.drawCircle(Offset(100, 100), 50, paint);
```

이 코드는 사각형 영역 내에서만 원이 그려지도록 제한한다.

#### 변환 (Transform)

Dart에서는 2D 그래픽 요소를 변환할 수 있는 기능을 제공한다. 변환에는 이동, 회전, 스케일링 등의 작업이 포함된다. 변환 행렬을 사용하여 그래픽 요소의 좌표계를 조정할 수 있다.

**이동 변환**

이동 변환은 그래픽 요소를 특정 방향으로 이동시키는 작업이다. 수학적으로 이동 변환은 다음과 같은 행렬로 표현된다.

$$
\mathbf{T} = \begin{pmatrix} 1 & 0 & t\_x \ 0 & 1 & t\_y \ 0 & 0 & 1 \end{pmatrix}
$$

여기서 $t\_x$와 $t\_y$는 각각 x축과 y축 방향으로의 이동 거리를 나타낸다. Dart에서는 `translate` 메소드를 사용하여 이동 변환을 적용할 수 있다.

```dart
canvas.translate(50, 50);
canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
```

**회전 변환**

회전 변환은 그래픽 요소를 중심점 기준으로 회전시키는 작업이다. 수학적으로 회전 변환은 다음과 같은 행렬로 표현된다.

$$
\mathbf{R} = \begin{pmatrix} \cos \theta & -\sin \theta & 0 \ \sin \theta & \cos \theta & 0 \ 0 & 0 & 1 \end{pmatrix}
$$

여기서 $\theta$는 회전 각도이다. Dart에서는 `rotate` 메소드를 사용하여 회전 변환을 적용할 수 있다.

```dart
canvas.rotate(math.pi / 4);
canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
```

**스케일 변환**

스케일 변환은 그래픽 요소의 크기를 조정하는 작업이다. 수학적으로 스케일 변환은 다음과 같은 행렬로 표현된다.

$$
\mathbf{S} = \begin{pmatrix} s\_x & 0 & 0 \ 0 & s\_y & 0 \ 0 & 0 & 1 \end{pmatrix}
$$

여기서 $s\_x$와 $s\_y$는 각각 x축과 y축 방향으로의 스케일 팩터이다. Dart에서는 `scale` 메소드를 사용하여 스케일 변환을 적용할 수 있다.

```dart
canvas.scale(2, 2);
canvas.drawRect(Rect.fromLTWH(0, 0, 50, 50), paint);
```

이 코드는 사각형을 두 배로 확대하여 그린다.
