돌아가기 PCD 어노테이터 스키마
## PCD 어노테이터 전용 스키마

### PCD 전용 **추가 메타데이터(`extra`)**

| 키 예시 | 타입 | 설명 |
| --- | --- | --- |
| `sensor_type` | string | 라이다 기종·센서명 (예: `LiDAR_HDL-64E`) |
| `timestamp` | string | ISO-8601 캡처 시각 |
| `vehicle_speed_kmh` | number | 캡처 시 차량 속도(km/h) |

### 지원 도구(Tools)

| Tool Code          | 설명            | UI 표시명    |
| ------------------ | --------------- | ------------ |
| `object_mode`      | 객체 모드       | Object Mode  |
| `3d_bounding_box`  | 3D 바운딩 박스  | Cuboid       |
| `3d_segmentation`  | 3D 세그멘테이션 | Segmentation |
| `3d_polygon`       | 3D 폴리곤       | Polygon      |
| `3d_polyline`      | 3D 폴리라인     | Polyline     |
| `review_comment`   | 리뷰 코멘트     | -            |
| `tracking_mode`    | 트래킹 모드     | -            |
| `selection_color`  | 색상 선택       | -            |
| `projected_images` | 투영 이미지     | -            |
| `roi`              | ROI             | -            |
| `roi_box`          | ROI 박스        | -            |

### Point3D 타입

```typescript
type Point3D = {
  x: number
  y: number
  z: number
  id?: string // 폴리곤/폴리라인 포인트에서 사용
  isLocked?: boolean // PSR 내부에서 사용
}
```

### annotationsData 구조 (도구별)

**3D Bounding Box (Cuboid) - PSR 구조:**

```json
{
  "id": "LG3lpgJs6P",
  "tool": "3d_bounding_box",
  "psr": {
    "position": { "x": 10.62, "y": 6.46, "z": 0.91, "isLocked": false },
    "scale": { "x": 1.92, "y": 2.72, "z": 1.36, "isLocked": false },
    "rotation": { "x": 0, "y": 0, "z": 2.23, "isLocked": false }
  }
}
```

**3D Segmentation:**

```json
{
  "id": "Av1KRf5ZSj",
  "tool": "3d_segmentation",
  "points": [21056, 21058, 21060, 21062, 21064] // 포인트클라우드 인덱스 배열
}
```

**3D Polygon / Polyline:**

```json
{
  "id": "7gAI0zKpcg",
  "tool": "3d_polygon",
  "points": [
    { "x": 7.19, "y": 6.98, "z": -0.82, "id": "0JvJ3arXzi" },
    { "x": 6.27, "y": -5.56, "z": 1.52, "id": "MQNruYWfsj" },
    { "x": 11.18, "y": -10.85, "z": 0, "id": "CWOovnGwoK" }
  ]
}
```

### beforeAction Hook

```javascript
// 빈 points 배열을 가진 3d_segmentation 어노테이션 자동 삭제
beforeAction: (annotatorData, variables) => {
  const validatePoint = (annotatorData) => {
    for (const annotation of pcdData) {
      if (annotation?.points?.length === 0 && annotations[i]?.tool === '3d_segmentation') {
        deleteAnnotationIdList.push(annotations[i].id)
      }
    }
  }
  validatePoint(annotatorData)
  return dataGrooming(annotatorData, variables)
}
```

### 샘플

3D 바운딩박스, 세그멘테이션, 폴리곤을 포함한 예제:

```json
{
  "extra": {
    "pcd": {
      "pointCount": 125000,
      "sensorType": "lidar",
      "coordinateSystem": "ego_vehicle",
      "boundingBox": {
        "min": { "x": -50, "y": -50, "z": -5 },
        "max": { "x": 50, "y": 50, "z": 10 }
      }
    }
  },
  "relations": {
    "pcd": [
      {
        "id": "pcd_001pcd_002",
        "tool": "relation",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "annotationId": "pcd_001",
        "targetAnnotationId": "pcd_002",
        "classification": {
          "class": "상호작용",
          "interaction_type": "following"
        },
        "label": ["상호작용"]
      }
    ]
  },
  "annotations": {
    "pcd": [
      {
        "id": "pcd_001",
        "tool": "3d_bounding_box",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "차량",
          "vehicle_type": "car",
          "color": "white",
          "occlusion": "none"
        },
        "label": ["차량", "car"]
      },
      {
        "id": "pcd_002",
        "tool": "3d_bounding_box",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "차량",
          "vehicle_type": "truck",
          "color": "blue",
          "occlusion": "partial"
        },
        "label": ["차량", "truck"]
      },
      {
        "id": "pcd_003",
        "tool": "3d_bounding_box",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "보행자",
          "pose": "standing",
          "age_group": "adult"
        },
        "label": ["보행자"]
      },
      {
        "id": "seg_001",
        "tool": "3d_segmentation",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "도로",
          "surface_type": "asphalt"
        },
        "label": ["도로"]
      },
      {
        "id": "seg_002",
        "tool": "3d_segmentation",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "식생",
          "vegetation_type": "tree"
        },
        "label": ["식생"]
      },
      {
        "id": "poly_001",
        "tool": "3d_polygon",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "차선",
          "lane_type": "solid_white"
        },
        "label": ["차선"]
      },
      {
        "id": "line_001",
        "tool": "3d_polyline",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "경계선",
          "boundary_type": "curb"
        },
        "label": ["경계선"]
      }
    ]
  },
  "annotationsData": {
    "pcd": [
      {
        "id": "pcd_001",
        "tool": "3d_bounding_box",
        "psr": {
          "position": { "x": 10.62, "y": 6.46, "z": 0.91, "isLocked": false },
          "scale": { "x": 4.5, "y": 1.8, "z": 1.5, "isLocked": false },
          "rotation": { "x": 0, "y": 0, "z": 1.57, "isLocked": false }
        }
      },
      {
        "id": "pcd_002",
        "tool": "3d_bounding_box",
        "psr": {
          "position": { "x": 25.3, "y": 8.12, "z": 1.2, "isLocked": false },
          "scale": { "x": 8.0, "y": 2.5, "z": 3.0, "isLocked": false },
          "rotation": { "x": 0, "y": 0, "z": 1.52, "isLocked": false }
        }
      },
      {
        "id": "pcd_003",
        "tool": "3d_bounding_box",
        "psr": {
          "position": { "x": 5.2, "y": -3.5, "z": 0.9, "isLocked": false },
          "scale": { "x": 0.6, "y": 0.6, "z": 1.8, "isLocked": false },
          "rotation": { "x": 0, "y": 0, "z": 0.0, "isLocked": false }
        }
      },
      {
        "id": "seg_001",
        "tool": "3d_segmentation",
        "points": [
          21056, 21058, 21060, 21062, 21064, 21066, 21068, 22100, 22102, 22104, 22106, 22108, 22110, 23050, 23052,
          23054, 23056, 23058
        ],
        "isCompressed": false
      },
      {
        "id": "seg_002",
        "tool": "3d_segmentation",
        "points": [0, 500, 10000, 300, 50000, 800],
        "isCompressed": true,
        "compressionFormat": "rle"
      },
      {
        "id": "poly_001",
        "tool": "3d_polygon",
        "points": [
          { "x": -2.0, "y": -15.0, "z": 0.0, "id": "pt_001" },
          { "x": -2.0, "y": 0.0, "z": 0.0, "id": "pt_002" },
          { "x": -1.8, "y": 0.0, "z": 0.0, "id": "pt_003" },
          { "x": -1.8, "y": -15.0, "z": 0.0, "id": "pt_004" }
        ]
      },
      {
        "id": "line_001",
        "tool": "3d_polyline",
        "points": [
          { "x": 10.0, "y": -20.0, "z": 0.15, "id": "ln_001" },
          { "x": 10.0, "y": -10.0, "z": 0.15, "id": "ln_002" },
          { "x": 10.0, "y": 0.0, "z": 0.15, "id": "ln_003" },
          { "x": 10.0, "y": 10.0, "z": 0.15, "id": "ln_004" },
          { "x": 10.0, "y": 20.0, "z": 0.15, "id": "ln_005" }
        ]
      }
    ]
  },
  "annotationGroups": {
    "pcd": [
      {
        "id": "group_vehicles",
        "tool": "annotationGroup",
        "isLocked": false,
        "isValid": true,
        "annotationList": [
          { "annotationId": "pcd_001", "children": [] },
          { "annotationId": "pcd_002", "children": [] }
        ],
        "classification": {
          "class": "차량_그룹",
          "scenario": "traffic_flow"
        }
      }
    ]
  },
  "assignmentId": 8001
}
```