website

source code for the ttmaths.uk website
Log | Files | Refs | README

DoubleReflectionQuestion.jsx (3777B)


      1 import Plot from "../plotting/Plot";
      2 import Line from "../plotting/Line";
      3 import Polygon from "../plotting/Polygon";
      4 import Question from "../Question";
      5 import Point from "../plotting/Point";
      6 import Equation from "../Equation";
      7 import RotationTextElement from "../RotationTextElement";
      8 import { getRandomChoice, getRandomInt } from "../../scripts/randomUtils";
      9 import { formatLine, formatVec } from "../../scripts/formatUtils";
     10 
     11 function reflectPoint(point, line = {a: 1, b: 1, c: 0}) {
     12   const [px, py] = point
     13   const k = (line.a*px + line.b*py + line.c) / (line.a**2 + line.b**2)
     14   return [px - 2*line.a*k, py - 2*line.b*k]
     15 }
     16 
     17 function getLineAngle(line) {
     18   // gradient is -b/a. need -arctan(b/a)
     19   return -Math.atan(line.b/line.a)
     20 }
     21 
     22 function findIntersect(line1, line2) {
     23   const k = line1.a*line2.b - line2.a*line1.b
     24   // parallel
     25   if (k == 0) {
     26     return null
     27   }
     28   return [(line2.c*line1.b - line1.c*line2.b) / k, (line2.a*line1.c - line1.a*line2.c) / k]
     29 }
     30 
     31 function randomLine(seed, lineType, excludedLine = {a: 100, b: 100, c: 100}) {
     32   let f = (seed) => {return {a: 0, b: 1, c: 1}}
     33   switch (lineType) {
     34     case 'horizontal':
     35       f = (seed) => {return {a: 0, b: 1, c: getRandomInt(-2, 2, seed)}}
     36       break
     37     case 'vertical':
     38       f = (seed) => {return {a: 1, b: 0, c: getRandomInt(-2, 2, seed)}}
     39       break
     40     case 'diagonal':
     41       f = (seed) => {return {a: 1, b: getRandomChoice([-1, 1], seed), c: 0}}
     42       break
     43   }
     44 
     45   let output = excludedLine
     46   while (output.a == excludedLine.a && output.b == excludedLine.b && output.c == excludedLine.c) {
     47     output = f(seed++)
     48   }
     49   return output
     50 }
     51 
     52 export default function DoubleReflectionQuestion({ seed, showAnswer }) {
     53   const viewBox = [-7, -7, 14, 14]
     54   const originalShape = [[0, 1], [2, 1], [0, 2]]
     55 
     56   const lineTypes = ['horizontal', 'vertical', 'diagonal']
     57   const line1Type = getRandomChoice(lineTypes, seed++)
     58   const line2Type = getRandomChoice(lineTypes, seed++)
     59 
     60   const line1 = randomLine(seed++, line1Type)
     61   const line2 = randomLine(seed++, line2Type, line1)
     62 
     63   const question = (<>
     64     <p>
     65       Reflect P in <Equation equation={formatLine(line1)} /> then <Equation equation={formatLine(line2)} />.<br />
     66       What single transformation describes this?
     67     </p>
     68     <Plot viewBox={viewBox} width="300" height="300">
     69       <Polygon points={originalShape} label="P" colour="1" />
     70       <Line line={line1} colour="2" />
     71       <Line line={line2} colour="3" />
     72     </Plot>
     73   </>)
     74 
     75   const midShape = originalShape.map((point) => reflectPoint(point, line1))
     76   const endShape = midShape.map((point) => reflectPoint(point, line2))
     77 
     78   const intersect = findIntersect(line1, line2)
     79   let answerTextElement = <></>
     80   let answerGraphElement = <></>
     81   if (intersect === null) { // translation, lines parallel
     82     const xTrans = 2*(line1.c*line1.a - line2.c*line2.a)
     83     const yTrans = 2*(line1.c*line1.b - line2.c*line2.b)
     84     answerTextElement = <p>Translation by vector <Equation equation={formatVec([xTrans, yTrans])} /></p>
     85   } else { // rotation
     86     const angle = 2*(getLineAngle(line2) - getLineAngle(line1))
     87     answerTextElement = <p>Rotation <RotationTextElement angle={angle} /> about <Equation equation={`(${intersect[0]}, ${intersect[1]}).`} /></p>
     88     answerGraphElement = <Point point={intersect} />
     89   }
     90   const answer = (<>
     91     {answerTextElement}
     92     <Plot viewBox={viewBox} width="300" height="300">
     93       <Polygon points={originalShape} label="P" colour="1" />
     94       <Polygon points={midShape} label="Q" colour="2" />
     95       <Polygon points={endShape} label="R" colour="3" />
     96       <Line line={line1} colour="2" />
     97       <Line line={line2} colour="3" />
     98       {answerGraphElement}
     99     </Plot>
    100   </>)
    101 
    102   return <Question question={question} answer={answer} showAnswer={showAnswer} />
    103 }