평면도에 문 표시하려면 생각보다 할 게 많다.

문 추가


문 데이터

interface Door {
  id: string;
  x: number;
  y: number;
  width: number;       // 문 너비
  wallSide: 'top' | 'bottom' | 'left' | 'right';  // 어느 벽에 붙는지
  openDirection: 'inward' | 'outward';  // 안/밖으로 열림
  hingeSide: 'left' | 'right';  // 경첩 위치
}

문 그리기

문은 두 부분으로 구성:

  1. 문짝 (사각형)
  2. 열림 호 (Arc)
<template>
  <v-group :config="{ x: door.x, y: door.y }">
    <!-- 문짝 -->
    <v-rect
      :config="{
        width: door.width,
        height: 10,
        fill: '#8B4513'
      }"
    />
    <!-- 열림  -->
    <v-arc
      :config="arcConfig"
    />
  </v-group>
</template>

호(Arc) 계산

이게 까다로웠다.

function getArcConfig(door: Door) {
  const radius = door.width;
  
  // 경첩 위치에 따라 시작점 다름
  let x = door.hingeSide === 'left' ? 0 : door.width;
  let y = door.openDirection === 'inward' ? 10 : 0;
  
  // 각도
  let angle = 90;
  let rotation = 0;
  
  if (door.hingeSide === 'left') {
    if (door.openDirection === 'inward') {
      rotation = -90;
    } else {
      rotation = 180;
    }
  } else {
    if (door.openDirection === 'inward') {
      rotation = 180;
    } else {
      rotation = -90;
    }
  }
  
  return {
    x,
    y,
    innerRadius: 0,
    outerRadius: radius,
    angle,
    rotation,
    fill: 'transparent',
    stroke: '#666',
    strokeWidth: 1,
    dash: [5, 5]
  };
}

경첩 위치(좌/우) × 열림 방향(안/밖) = 4가지 경우.

각각 rotation이 다르다. 이거 맞추느라 시간 좀 걸렸다.


벽 스냅

문을 드래그하면 벽에 붙어야 한다.

function snapToWall(door: Door, room: Room) {
  const walls = [
    { side: 'top', y: room.y, x1: room.x, x2: room.x + room.width },
    { side: 'bottom', y: room.y + room.height, x1: room.x, x2: room.x + room.width },
    { side: 'left', x: room.x, y1: room.y, y2: room.y + room.height },
    { side: 'right', x: room.x + room.width, y1: room.y, y2: room.y + room.height }
  ];
  
  const threshold = 20;  // 20px 이내면 스냅
  
  // 가장 가까운 벽 찾기
  let closestWall = null;
  let minDistance = threshold;
  
  for (const wall of walls) {
    const distance = getDistanceToWall(door, wall);
    if (distance < minDistance) {
      minDistance = distance;
      closestWall = wall;
    }
  }
  
  if (closestWall) {
    // 벽에 붙이기
    return snapPosition(door, closestWall);
  }
  
  return null;
}

단축키

  • D: 열림 방향 토글 (inward ↔ outward)
  • H: 경첩 위치 토글 (left ↔ right)
function handleKeyDown(e: KeyboardEvent) {
  if (!selectedDoor) return;
  
  if (e.key === 'd' || e.key === 'D') {
    toggleOpenDirection();
  }
  if (e.key === 'h' || e.key === 'H') {
    toggleHingeSide();
  }
}

다음 글에서 측정 도구.

#11 - 측정 도구