(Lispex)sicp.io
2.14 · 그림 언어 · 페인터와 프레임

페인터는 프레임을 유한한 선분 집합으로 바꾼다.

벡터와 선분과 프레임은 작은 기하 데이터 언어를 이룹니다. 페인터는 단위 정사각형의 끝점을 적용할 때 받은 프레임으로 옮겨 절대 좌표와 분리됩니다.

생각해 볼 질문

페인터 하나가 정사각형과 기울어진 프레임과 크기가 다른 프레임 안에서 같은 그림을 어떻게 설명할까요?

  • 생성자와 선택자 인터페이스로 벡터와 선분 나타내기
  • 원점과 두 모서리 벡터로 프레임 나타내기
  • 단위 정사각형 좌표를 구체적인 프레임으로 옮기기
  • 프레임을 선분 목록으로 바꾸는 프로시저로 페인터 만들기
  • 반환값을 유지하면서 기계가 읽을 수 있는 SEG 줄 출력하기
  • 흑백 SVG를 실제 리스펙스 출력의 렌더링으로 읽기

선분 데이터는 단위 정사각형 좌표로 작성됩니다. frame-coordinate-map은 x와 y 성분을 상대 위치로 읽고 프레임 원점에 두 모서리 벡터의 비례값을 더합니다. segments->painter는 유한한 선분 목록을 캡처하고 나중에 받은 프레임을 통해 모든 끝점을 옮기는 프로시저를 반환합니다.

첫 실행은 테두리와 대각선 페인터를 정사각형 프레임에 놓습니다. 두 번째 실행은 마름모 페인터를 기울어진 프레임에 적용합니다. 페인터 정의에는 마지막 화면 좌표가 들어 있지 않습니다. 실행은 옮긴 선분마다 SEG 줄 하나를 출력하고 앱 로컬 시각화가 transcript 줄을 흑백 SVG로 읽습니다. 반환되는 (segments n) 값은 별도 관찰로 남습니다.

리스펙스 · SICP 코드SICP에 필요한 Scheme 호환 문법을 리스펙스 SICP 프로필로 실행합니다.
(begin
  (define (make-vect x y) (list x y))
  (define (xcor-vect vector) (car vector))
  (define (ycor-vect vector) (cadr vector))
  (define (add-vect left right)
    (make-vect (+ (xcor-vect left) (xcor-vect right))
               (+ (ycor-vect left) (ycor-vect right))))
  (define (scale-vect factor vector)
    (make-vect (* factor (xcor-vect vector))
               (* factor (ycor-vect vector))))
  (define (make-segment start end) (list start end))
  (define (start-segment segment) (car segment))
  (define (end-segment segment) (cadr segment))
  (define (make-frame origin edge1 edge2)
    (list origin edge1 edge2))
  (define (origin-frame frame) (car frame))
  (define (edge1-frame frame) (cadr frame))
  (define (edge2-frame frame) (caddr frame))
  (define (frame-coordinate-map frame)
    (lambda (vector)
      (add-vect
        (origin-frame frame)
        (add-vect
          (scale-vect (xcor-vect vector) (edge1-frame frame))
          (scale-vect (ycor-vect vector) (edge2-frame frame))))))
  (define (map-segment coordinate-map segment)
    (make-segment
      (coordinate-map (start-segment segment))
      (coordinate-map (end-segment segment))))
  (define (segments->painter segment-list)
    (lambda (frame)
      (let ((coordinate-map (frame-coordinate-map frame)))
        (map (lambda (segment)
               (map-segment coordinate-map segment))
             segment-list))))
  (define (emit-segment segment)
    (let ((start (start-segment segment))
          (end (end-segment segment)))
      (display "SEG ")
      (display (xcor-vect start))
      (display " ")
      (display (ycor-vect start))
      (display " ")
      (display (xcor-vect end))
      (display " ")
      (display (ycor-vect end))
      (newline)))
  (define (paint painter frame)
    (let ((segments (painter frame)))
      (for-each emit-segment segments)
      (list 'segments (length segments))))
  (define p00 (make-vect 0.0 0.0))
  (define p10 (make-vect 1.0 0.0))
  (define p11 (make-vect 1.0 1.0))
  (define p01 (make-vect 0.0 1.0))
  (define outline-and-cross
    (segments->painter
      (list
        (make-segment p00 p10)
        (make-segment p10 p11)
        (make-segment p11 p01)
        (make-segment p01 p00)
        (make-segment p00 p11)
        (make-segment p01 p10))))
  (paint outline-and-cross
         (make-frame (make-vect 0.08 0.08)
                     (make-vect 0.84 0.0)
                     (make-vect 0.0 0.84))))
리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 2,452 / 1,048,576바이트
예제
결과
출력
진단
보이는 실행 흐름0 / 0 개의 실행 이벤트
    이 브라우저 결과는 리스펙스 바우치나 권한이 아닙니다.wasm —
    실행과 연결된 그림 언어리스펙스가 만든 선분을 그립니다.
    런타임 불러오는 중
    이번 실행에서 올바른 SEG 줄을 만들지 못했습니다.
    로컬 리스펙스 transcript에서 선분 0개를 읽었습니다.
    SVG는 이 브라우저 실행이 출력한 SEG 줄에서 만들어집니다. 하나의 제한된 실행을 교육용으로 그린 것이며 증명이나 권한 기록이 아닙니다.
    예상 관찰

    첫 프로그램은 SEG 줄 여섯 개를 출력하고 (segments 6)을 반환합니다. 두 번째는 변환된 SEG 줄 네 개를 출력하고 (segments 4)를 반환합니다. 작업대 옆 SVG는 그 transcript 줄에서 만들어집니다.

    실행 흐름에서 볼 점

    페인터 적용에서 frame-coordinate-map으로 들어간 뒤 각 끝점이 프레임 원점과 x 배의 첫 모서리와 y 배의 두 번째 모서리 합으로 만들어지는 과정을 따라가세요. transcript 출력과 반환한 선분 수는 서로 다른 관찰입니다.

    직접 해보기

    힌트를 보기 전에 프로그램을 바꿔 보세요.

    첫 페인터에 네 변의 중점을 잇는 내부 마름모 선분 네 개를 추가하세요. 새 선분 수를 예상한 뒤 SEG 출력에서 시각화가 추가 모양을 그리는지 확인하세요.

    힌트 하나 보기

    네 중점은 (0.5, 0.0), (1.0, 0.5), (0.5, 1.0), (0.0, 0.5)입니다. 페인터는 마지막 프레임과 계속 분리됩니다.