2.50

练习 2.50 请定义变换 flip-horiz,它能在水平方向上反转画家。再定义出对画家做反时针方向上180度和270度旋转的变换。


先用 js 来直观地体验一下,后面再将 js 实现翻译成 scheme。

先复用一下上一练习的代码:

 
cons = (x, y) => [x, y];
car = (z) => z[0];
cdr = (z) => z[1];
makeVect = cons;
xCorVect = car;
yCorVect = cdr;
makeSegment = cons;
startSegment = car;
endSegment = cdr;
o = makeVect(0, 0);
e1 = makeVect(300, 0);
e2 = makeVect(0, 150); 
s = makeSegment(makeVect(1, 0), makeVect(0, 1)); 
console.log('s = ', s);
console.log(startSegment(s));
console.log(endSegment(s));
x
 
"s = " Array [
  Array [
    1,
    0,
  ],
  Array [
    0,
    1,
  ],
]
Array [
  1,
  0,
]
Array [
  0,
  1,
]
undefined
 
makeFrame = (origin, edge1, edge2) => {
  return [origin, edge1, edge2];
};
originFrame = (frame) => frame[0];
edge1Frame = (frame) => frame[1];
edge2Frame = (frame) => frame[2];
addVect = (v1, v2) => makeVect(xCorVect(v1) + xCorVect(v2), yCorVect(v1) + yCorVect(v2));
subVect = (v1, v2) => makeVect(xCorVect(v1) - xCorVect(v2), yCorVect(v1) - yCorVect(v2));
scaleVect = (s, v) => makeVect(s * xCorVect(v), s * yCorVect(v));
frameCoordMap = (frame) => {
  return (v) => {
    return addVect(
      originFrame(frame),
      addVect(
        scaleVect(
          xCorVect(v),
          edge1Frame(frame)
        ),
        scaleVect(
          yCorVect(v),
          edge2Frame(frame)
        )
      )
    );
  };
}
f = makeFrame(o, e1, e2);
 
Array [
  Array [
    0,
    0,
  ],
  Array [
    300,
    0,
  ],
  Array [
    0,
    150,
  ],
]
 
drawLine = (v1, v2) => {
  return (ctx) => {
    ctx.beginPath();
    ctx.moveTo(xCorVect(v1), yCorVect(v1));
    ctx.lineTo(xCorVect(v2), yCorVect(v2));
    ctx.stroke();
  }
};
segmentsPainter = (segmentList) => {
  return (frame) => (ctx) => {
    segmentList.forEach((segment) => {
      drawLine(
        (frameCoordMap(frame))(startSegment(segment)),
        (frameCoordMap(frame))(endSegment(segment))
      )(ctx);
    });
  }
}
applyToCanvas = (painter, canvasSelector) => {
  const canvas = document.querySelector(canvasSelector);
  const ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height); 
  painter(ctx);
}
 
[Function applyToCanvas]
 
wavePainter = (frame) => {
  const v1 = makeVect(0.4, 0);
  const v2 = makeVect(0.6, 0);
  const v3 = makeVect(0, 0.2);
  const v4 = makeVect(0.3, 0.2);
  const v5 = makeVect(0.7, 0.2);
  const v6 = makeVect(0, 0.4);
  const v7 = makeVect(0.2, 0.4);
  const v8 = makeVect(0.3, 0.35);
  const v9 = makeVect(0.42, 0.4);
  const v10 = makeVect(0.6, 0.4);
  const v11 = makeVect(0.8, 0.4);
  const v12 = makeVect(0.3, 0.4);
  const v13 = makeVect(0.2, 0.55);
  const v14 = makeVect(0.31, 0.5);
  const v15 = makeVect(0.6, 0.51);
  const v16 = makeVect(1, 0.7);
  const v17 = makeVect(0.5, 0.8);
  const v18 = makeVect(1, 0.85);
  const v19 = makeVect(0.35, 1);
  const v20 = makeVect(0.4, 1);
  const v21 = makeVect(0.6, 1);
  const v22 = makeVect(0.7, 1);
  return segmentsPainter([
    makeSegment(v1, v4),
    makeSegment(v2, v5),
    makeSegment(v3, v7), 
    makeSegment(v7, v8),
    makeSegment(v8, v9),
    makeSegment(v9, v4),
    makeSegment(v10, v5),
    makeSegment(v10, v11),
    makeSegment(v6, v13),
    makeSegment(v13, v12),
    makeSegment(v12, v14),
    makeSegment(v16, v11),
    makeSegment(v18, v15),
    makeSegment(v19, v14),
    makeSegment(v20, v17),
    makeSegment(v21, v17),
    makeSegment(v22, v15),
  ])(frame); 
}
applyToCanvas(wavePainter(f), '#wave-canvas');
 
undefined

先将以上 wave 在水平上做个翻转:

 
transformPainter = (painter, origin, corner1, corner2) => {
  return (frame) => {
    const m = frameCoordMap(frame);
    const newOrigin = m(origin);
    return painter(
      makeFrame(
        newOrigin, 
        subVect(m(corner1), newOrigin),
        subVect(m(corner2), newOrigin)
      )
    );
  }
}
flipHoriz = (painter) => {
  return transformPainter(
    painter,
    makeVect(1, 0),
    makeVect(0, 0),
    makeVect(1, 1)
  )
}
applyToCanvas(flipHoriz(wavePainter)(f), '#flip-horiz-canvas');
 
undefined

再将最初的 wave 在反时针方向上旋转 180 度:

 
rotateLeft180 = (painter) => {
  return transformPainter(
    painter,
    makeVect(1, 1),
    makeVect(0, 1),
    makeVect(1, 0)
  )
}
applyToCanvas(rotateLeft180(wavePainter)(f), '#rotate-left-180-canvas');
 
undefined

最后将最初的 wave 向反时针方向上旋转 270 度。

 
rotateLeft270 = (painter) => {
  return transformPainter(
    painter,
    makeVect(1, 0),
    makeVect(1, 1),
    makeVect(0, 0)
  )
}
applyToCanvas(rotateLeft270(wavePainter)(f), '#rotate-left-270-canvas');
 
undefined
 
console.log('done');
 
"done"
undefined

results matching ""

    No results matching ""