4

I can't seem to get my head around the implementation of frames in SICP.

The book states

We will use coordinates in the unit square (0< x,y< 1) to specify images

How are images expressed as coordinates? The only interpretation I can muster is that all images, being lines, can only be mapped to a frame whose boundary can not exceed that of a unit square. But I doubt that because the next line in the book, explaining a "frame coordinate map", says

The map transforms the unit square into the frame by mapping the vector v = (x,y) to the vector sum Origin(Frame) + x*Edge1(Frame) + y*Edge2(Frame)

The vector (0,0) being mapped to the origin of the frame and (1,1) to the vertex diagonally opposite the origin, only adds to my confusion. What are these vectors? The origin of the image or what?

I can't make sense of this and it's preventing me from moving further into the text as everything discussed after builds on this concept. I'd find it very helpful if I could get a detailed explanation of how any one who's read the book understood this idea.

sigjuice
  • 28,661
  • 12
  • 68
  • 93
Michael Tedla
  • 1,079
  • 1
  • 12
  • 19

3 Answers3

11

Your interpretation of images is correct. Images are made up of line segments in a unit square where the origin (0, 0) is the bottom left corner and (1, 1) is the top right corner.

Einstein drawn in the default frame

A painter maps the image into a frame using the transformation given in the question. The einsten image above is drawn in the default frame (the unit square) so it appears normal.

You can create and display an image using The SICP Picture Language in three steps:

  • define a list of line segments
  • create a segment painter from those line segments
  • call paint with the new segment painter

I do this with several simple images in by blog post SICP 2.49: Defining Primitive Painters. Here's one simple example using just two line segments:

; The painter that draws an 'X' by connecting opposite corners of the frame.
(define x-segments
 (list
  (make-segment
   (make-vect 0.0 0.0)
   (make-vect 0.99 0.99))
  (make-segment
   (make-vect 0.0 0.99)
   (make-vect 0.99 0.0))))

(define x-painter (segments->painter x-segments))

(paint x-painter)

Here's the result when I run that last command in DrRacket:

simple painter

You can flip and rotate an image by creating new frames for it to be drawn in.

A frame is defined by three vectors:

  • the origin
  • the bottom edge (edge1)
  • the left edge (edge2)

enter image description here

You can use the transform-painter function given in the text (in the section titled Transforming and combining painters) to transform an existing segment painter using a new origin and edges.

(define (transform-painter painter origin corner1 corner2)
  (lambda (frame)
    (let ((m (frame-coord-map frame)))
      (let ((new-origin (m origin)))
        (painter
         (make-frame new-origin
                     (sub-vect (m corner1) new-origin)
                     (sub-vect (m corner2) new-origin)))))))

For example, if I want to draw the original Einstein image rotated 45 degrees to the left, I just need to pass the einstein segment painter along with a new origin, bottom edge, and left edge to transform-painter and it will return a new segment painter. In other words, I need to tell transform-painter where to draw the bottom left, bottom right, and top left corners of the image, and it will do the work of transforming all of the line segments in the original segment painter.

; rotate an image 45 degrees to the left
(define (rotate-45 painter)
  ((transform-painter (make-vect 0.5 0.0)
                      (make-vect 1.0 0.5)
                      (make-vect 0.0 0.5))
   painter))

You can execute the command (paint (rotate-45 einstein)) to see the rotated image.

Einstein rotated 45 degrees

Martin
  • 157
  • 1
  • 3
  • 8
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
0

As far as I remember, the frames are vector images defined with coordinates relative to the unit square, and from there they can be scaled, mapped and in general transformed into a coordinate system with a given origin and size. It's all in the book under the "frames" section.

You can correctly assume that all images are contained in the unit square, that's how it is. However, this is not a limitation at all - there's an infinite number of coordinate points in the unit square, and any image you can dream of fits in there. Defining that the coordinates are in the range [0, 1] it's just a matter of convention; it'd be the same if they were in the range [1, 1000], you can map from one coordinate system to the other by moving the decimal point.

Martin
  • 157
  • 1
  • 3
  • 8
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • The book says "coordinates in the unit square (0< x,y< 1) are used to specify images. After that it states the following, "The frame coordinate map transforms the unit square into the frame by mapping the vector v = (x,y) to the vector sum Origin(Frame) + x*Edge1(Frame) + y*Edge2(Frame)" My understanding from that is, all images have dimensions not exceeding a unit square, but we can use frames to enlarge and diminish them. I don't think that's right. It's difficult because I feel like I'm using a misunderstanding somewhere to fill a gap which is completely throwing me off. – Michael Tedla Mar 20 '13 at 14:47
  • @user2190496 you're right in assuming that all the images are contained in the unit square, that's how it is. However, this is not a limitation at all, there's an infinite number of coordinate points in the unit square, and any image you can dream of fits in there. It's just a matter of convention, defining that the coordinates are in the range [0, 1]. It's just the same if they were in the range [1, 1000], you can map from one to the other by moving the decimal point – Óscar López Mar 20 '13 at 14:50
  • So let me see if I have this right. Since there's an infinite number of points within a unit square and all images can be represented within it, that makes a frame nothing more than a representation of the boundary of a unit square, within which we can shift and scale any image to any degree. Is that it? – Michael Tedla Mar 20 '13 at 15:10
  • @user2190496 exactly! you got it! – Óscar López Mar 20 '13 at 15:16
0

This is years later, but I have something to add to the discussion here. I just came across this section in the book, and also did not grasp the concept right away. Bill's answer is informative. I'm here to fill in a missing gap.

A frame is the box in which an image is painted. An image is a collection of pixels represented as vectors with colors that form an image. So, for example, the vector (0.5 . 0.5) might have the color black, and the painter will paint that spot with black. In very simple terms.

When the painter paints the image in the frame, the painter "goes into" the frame and acts as if that's it's only point of reference. In other words, what looks like a diamond frame to us will be treated as a regular square frame sitting on its base to the painter. That is because the painter re-orients itself to see the frame from a different angle.

See Bill's (paint (rotate-45 einstein)) example. you can see that the same image is painted, just on a tilt. The painter is looking straight at the image in the same way it would if it were sitting on its base. It is only to our eyes that it seems as if the image is "skewed".

How does the painter 're-orient' itself?

Enter frame-coord-map.

frame-coord-map takes as its argument a frame. Let's say that the frame given is a regular, square frame sitting on it's base. That frame would be created thus:

(make-frame (make-vect 0.0 0.0)
            (make-vect 1.0 0.0)
            (make-vect 0.0 1.0))

The origin point is at the 0 of the x and y axes. Edge 1 stretches evenly to the end of the x-axis, and edge 2 to the y-axis. frame-coord will now take a vector – that is, a point within the frame – say, (0.1 . 0.5). In the above-defined frame, that represents the point slightly to the left of bottom-left corner, and halfway up. frame-coord will return that very same vector – (0.1 . 0.5).

Now, let's say we gave frame-coord a "tilted" frame. A 45-degree rotated, "skewed" frame. Such a frame would be defined thus:

(make-frame (make-vect 0.5 0.0)
            (make-vect 1.0 0.5)
            (make-vect 0.0 0.5)

If we gave the same vector – (0.1 . 0.5) to frame-coord now, we would get a different return value. Now, frame-coord would return (0.6 . 0.3). The reason for that is because relative to the origin point (0.5 . 0), mapping the vector (0.1 . 0.5) will produce (0.6 0.3). This concept carries over to other parallelograms. No matter the frame's origin and edges, the painter will be able to map the vectors of the image to the frame.

This is how the painter 're-orients' itself to any frame, and that is the importance of this function.