computational-geometry

3 개의 포스트

figma

기능 비하인드: (새 탭에서 열림)

Figma의 그림자 `spread` 기능은 겉보기와 달리 단순히 도형을 확대하는 문제를 넘어선다. 사각형에서는 기하 도형을 키우는 방식이 작동하지만, 구멍이나 복잡한 윤곽을 가진 도형에서는 “모든 방향으로 일정 거리만큼 확장”해야 하므로 별도의 알고리즘과 렌더링 설계가 필요하다. 이 글은 CSS `box-shadow`와 호환되는 기능을 만들기 위해 알고리즘, W3C 명세, 기존 렌더러의 제약, 제품 우선순위를 검토한 과정을 설명한다. ## 그림자 `spread`가 필요한 이유 - Figma는 2020년 7월 23일부터 사각형, 타원, 프레임 배경, 컴포넌트 배경에 그림자 확산 거리를 조절하는 기능을 제공했다. - CSS의 `box-shadow`와 마찬가지로 `spread` 값은 그림자를 모든 방향으로 확장하거나 수축하는 거리다. - 사용자는 오랫동안 이 기능을 요청했지만, 기본적인 CSS 기능처럼 보이는 요구사항이 실제로는 그래픽스 엔진 수준의 문제였다. ## 기존 그림자 렌더링 방식 - 일반적인 드롭 섀도는 다음 순서로 만든다. - 원본 객체의 기하 구조를 복사한다. - 단일 색상으로 채운다. - 블러 효과를 적용한다. - 원본 노드 아래에 렌더링한다. - 이 방식은 단순한 도형의 그림자를 만드는 데는 충분하다. - 특히 사각형은 그림자 기하 구조를 확대하는 것만으로도 어느 정도 `spread` 효과를 낼 수 있다. ## 단순한 확대가 실패하는 복잡한 도형 - 복잡한 도형이나 Figma 로고처럼 내부에 구멍이 있는 도형은 전체 기하 구조를 스케일링하면 올바른 결과가 나오지 않는다. - 스케일링은 도형의 중심과 전체 비율을 기준으로 크기를 바꾸지만, `spread`는 원래 윤곽선에서 모든 방향으로 일정한 픽셀 거리만큼 확장해야 한다. - 따라서 원하는 결과는 단순히 외곽 크기가 커지는 것이 아니라 다음과 같은 형태다. - 볼록하거나 오목한 윤곽을 각각 일정 거리만큼 이동한다. - 내부 구멍도 동일한 규칙에 따라 확장 또는 축소한다. - 각 경계와 꼭짓점에서 일정한 거리 관계를 유지한다. ## 알고리즘과 렌더러의 제약 - 그림자 확산을 구현하는 알고리즘적 방법은 여러 가지가 있지만, 기존 Figma 렌더링 시스템에 자연스럽게 끼워 넣기 어려웠다. - 스트로크를 이용해 그림자를 흉내 내는 비알고리즘적 접근도 검토했지만 적합하지 않았다. - Figma의 스트로크는 특정 꼭짓점 각도를 그림자 확산에 필요한 방식과 다르게 처리한다. - 프로토타입 렌더러에는 스트로크 생성 코드 자체가 없었다. - Figma는 서로 다른 두 렌더링 코드베이스를 사용하고 있었기 때문에, 복잡한 기하 생성 로직을 양쪽에 모두 추가하는 방식은 유지보수 비용이 컸다. - 결국 문제는 “그림자를 크게 만드는 것”이 아니라, 기존 렌더링 구조를 크게 훼손하지 않으면서 임의의 2D 도형을 일정 거리만큼 확장하는 방법을 찾는 일이었다. ## 기능 개발 과정에서의 판단 - 작성자는 Maker Week에서 며칠 만에 끝낼 수 있는 간단한 기능이라고 생각했지만, 실제로는 몇 주가 걸리는 프로젝트가 되었다. - 개발 과정에서 처음 시도한 접근이 잘못되었음을 확인하고, 도형 확장 알고리즘과 W3C 명세를 다시 검토했다. - 이 사례는 사용자에게 단순해 보이는 기능도 다음 요소를 함께 고려해야 한다는 점을 보여준다. - 시각적으로 정확한 결과 - CSS와의 동작 호환성 - 기존 렌더링 엔진과의 통합 가능성 - 구현 복잡도와 장기적인 유지보수 비용 복잡한 도형의 그림자 `spread`를 구현할 때는 단순 확대나 스트로크 재활용만으로 해결하려 하지 말고, “윤곽선에서 모든 방향으로 일정 거리”라는 의미를 먼저 명확히 정의해야 한다. 이후 정확도, 렌더링 성능, 기존 코드베이스와의 통합 비용을 비교해 가장 현실적인 구현 방식을 선택하는 것이 중요하다.

figma

스쿼클을 간절히 찾 (새 탭에서 열림)

피그마 엔지니어가 iOS의 ‘스퀴클(squircle)’을 Figma에 구현하기 위해 수학적 형태를 분석한 과정을 설명한다. 스퀴클은 단순한 둥근 사각형이 아니라 직선과 곡선의 연결부에서 곡률이 연속적으로 변해 더 자연스럽고 독립적인 형태로 인식된다. 처음에는 슈퍼타원으로 설명할 수 있다고 보았지만, 실제 애플 아이콘과 비교한 결과 체계적인 오차가 발견되며 더 정교한 모델이 필요해졌다. ## 디자인 문제로서의 스퀴클 - 스퀴클은 ‘square’와 ‘circle’을 합친 표현으로, iOS 7에서 애플 앱 아이콘에 적용되며 널리 알려졌다. - 기존의 둥근 사각형은 직선과 원호가 만나는 지점에서 곡률이 갑자기 바뀐다. - 스퀴클은 이 전환을 부드럽게 만들어 외곽선 전체의 곡률이 연속적으로 이어진다. - 수학적으로 작은 차이지만, 시각적으로는 형태가 단순히 모서리를 깎은 사각형이 아니라 하나의 유기적인 물체처럼 보이게 한다. - 맥북 모서리나 유선 이어버드 케이스처럼 산업 디자인에서도 곡률의 연속성은 표면의 하이라이트와 물체의 인상에 큰 영향을 준다. ## 공학에도 적용되는 디자인의 제약 - 글은 Charles Eames의 디자인 정의인 “특정 목적을 달성하기 위해 요소를 배열하는 계획”에서 출발한다. - 디자인의 핵심은 가능한 많은 제약을 인식하고, 그 제약 안에서 작업하는 데 있다. - 엔지니어링에서도 시간, 단순성, 유지보수성, 미적 완성도 같은 제약을 함께 고려해야 한다. - 스퀴클 구현 과정은 수학적 문제를 다루지만, 탐색·실패·숨은 문제 발견·제약의 변화·해결이라는 전형적인 디자인 과정과 동일한 구조를 가진다. ## 슈퍼타원이라는 첫 번째 해법 - 스퀴클의 정확한 수학적 표현을 찾기 위해 기존 연구를 조사했고, 초기에는 슈퍼타원이 유력한 후보로 제시됐다. - 슈퍼타원은 다음과 같은 형태로 표현할 수 있다. \[ \left|\frac{x}{a}\right|^n + \left|\frac{y}{b}\right|^n = 1 \] - \(n=2\)이면 일반적인 타원이 된다. - \(a=b=1, n=2\)이면 단위원이 된다. - \(n>2\)로 설정하면 모서리가 점점 사각형에 가까워진다. - \(n\)이 무한대로 커지면 경계가 직사각형에 가까워진다. - 초기 분석에서는 \(n=5\) 정도의 슈퍼타원이 애플 아이콘과 매우 비슷하게 보였다. - 이 모델이 정확하다면 Bézier 곡선 여러 개로 근사한 뒤 Figma의 도형 시스템에 통합할 수 있었다. ## 실제 아이콘과의 불일치 - 슈퍼타원은 시각적으로는 매우 유사했지만 실제 iOS 아이콘의 외곽선을 정확히 설명하지 못했다. - 가능한 \(n\) 값을 바꿔도 실제 형태와 비교하면 작지만 일관된 차이가 남았다. - 이는 단순한 측정 오차가 아니라 모델 자체의 구조적 한계였다. - 따라서 “비슷하게 보이는 우아한 공식”을 사용하는 것만으로는 충분하지 않았고, 사용자가 기대하는 실제 애플 형태를 재현하려면 더 정확한 곡선 모델이 필요했다. - 이후 연구에서는 여러 개의 Bézier 곡선을 조합해 스퀴클 모서리를 구성하는 가설이 제시되며 다음 단계로 이어진다. 정확한 그래픽 구현에서는 시각적으로 비슷한 근사식과 실제 디자인을 충실히 재현하는 모델을 구분해야 한다. 특히 곡률 연속성처럼 작은 수학적 차이가 최종 형태의 인상과 품질을 좌우할 수 있으므로, 공식의 단순성보다 실제 데이터와의 검증이 중요하다.

figma

벡터 네트워크의 삭제 및 복구 | (새 탭에서 열림)

Figma의 “삭제 후 복구(Delete and Heal)”는 정점을 단순히 제거하는 기능이 아니라, 주변 선과 곡률을 최대한 보존하며 벡터 구조를 재구성하는 작업이다. 단순한 경로에서는 인접 정점을 연결하면 되지만, 곡선과 벡터 네트워크에서는 베지어 곡선 근사와 그래프 구조를 함께 고려해야 한다. Figma는 이 기능을 통해 복잡한 벡터 네트워크에서도 자연스러운 편집 결과를 제공한다. ## 삭제와 삭제 후 복구의 차이 - 일반적인 정점 삭제는 해당 정점에 연결된 모든 선분과 그 선분에 닿는 채우기 영역을 함께 제거한다. - “삭제 후 복구”는 삭제된 정점 양쪽의 구조를 새 선으로 연결해 기존 형태를 유지하려는 기능이다. - 한쪽에만 선이 연결된 정점은 연결할 대상이 없으므로 선을 제거한다. - 삼각형처럼 정점 수가 줄어드는 경우에도 결과가 항상 같지는 않다. - 어떤 경우에는 두 정점 사이의 단일 선으로 축소된다. - 다른 경우에는 두 개의 선이 유지될 수 있다. - Figma는 정점과 선의 연결 관계에 따라 결과를 다르게 처리한다. ## 곡선의 형태를 보존하는 복구 - 곡선 위의 정점을 삭제하면 단순히 양 끝점을 직선으로 연결할 경우 기존 곡률이 사라진다. - 다른 도구는 인접 정점의 곡률 핸들 위치를 그대로 유지하는 경우가 많다. - Figma는 원래 곡선을 최대한 근사하도록 인접 정점의 제어 핸들을 조정한다. - 각 곡선 선분은 cubic Bézier curve로 표현된다. - 복구 문제는 다음 두 개의 cubic Bézier 곡선을 하나의 곡선으로 근사하는 문제로 바뀐다. - 첫 번째 곡선: `(P0, P1, P2, P3)` - 두 번째 곡선: `(P3, P4, P5, P6)` - 새 곡선: `(P’0, P’1, P’2, P’3)` - 벡터 네트워크의 나머지 부분을 변경하지 않기 위해 새 곡선의 양 끝점은 고정한다. - `P’0 = P0` - `P’3 = P6` - 따라서 계산해야 하는 것은 새 곡선의 제어점 `P’1`, `P’2`다. ## 베지어 곡선 근사 알고리즘 - 먼저 두 기존 곡선을 따라 여러 샘플 점을 생성한다. - cubic Bézier의 매개변수 `t`에 값을 대입해 곡선 위의 점을 계산한다. - 두 곡선이 공유하는 끝점은 중복해서 세지 않는다. - 예를 들어 각 구간에 여러 `t` 값을 적용하면 전체 연결 곡선 위의 샘플 점 목록을 얻을 수 있다. - 생성된 점들을 하나의 cubic Bézier 곡선으로 피팅한다. - Figma는 Philip J. Schneider의 “An Algorithm for Automatically Fitting Digitized Curves” 알고리즘과 관련 구현을 활용한다. - 결과적으로 삭제 전의 곡률을 완벽히 복원하지는 않지만, 시각적으로 자연스러운 단일 곡선을 얻는다. ## 벡터 네트워크와 그래프 기반 삭제 - Figma의 벡터 객체는 일반적인 순차 경로가 아니라 무방향 그래프로 표현된다. - 더 정확히는 각 선 자체의 식별성을 가진 무방향 멀티그래프다. - 따라서 하나의 정점에 최대 두 개의 선만 연결된다는 경로 기반 도구의 가정을 사용할 수 없다. - 삭제 대상 정점에 세 개 이상의 선이 연결될 수 있으며, 이 경우 어떤 선끼리 연결할지 결정해야 한다. - 연결된 선의 개수가 홀수라면 모든 인접 선을 제거한다. - 남는 선을 자연스럽게 짝지을 방법이 없기 때문이다. - 연결된 선의 개수가 짝수라면 선들을 쌍으로 묶어 새 선을 만든다. - 이때 “서로 반대편에 있는 선”을 정의하기 위해 정점에서 뻗어나가는 선을 각도 기준으로 정렬한다. - 정렬된 방향을 바탕으로 서로 마주 보는 선끼리 연결해 네트워크 구조를 복구한다. ## 실용적인 결론 벡터 편집기의 삭제 기능은 단순한 데이터 제거가 아니라, 그래프 연결성·곡선 근사·사용자 기대를 함께 처리하는 기하학적 재구성 문제다. 특히 벡터 네트워크를 지원하려면 정점 차수가 2를 넘는 상황과 곡선 제어점까지 고려해야 하며, Bézier 샘플링과 곡선 피팅을 결합하는 방식이 실용적인 해결책이 된다.