I have a certain figure drawn in Canvas. It is necessary to mirror the shape of a given line. Tell me how to implement JavaScript?

Photo example

  • I ask for ideas, because I myself can not think of anything :) - pishak
  • @pishak Are the coordinates of the first triangle and the line known before you begin to make a mirror image? - Mr. Brightside
  • In general, this question is not JS and not canvas'a, but rather a question of algorithm and mathematics, or rather, geometry. You need to study the issue of building symmetries - Mr. Brightside
  • @ Mr.Brightside data on the figure and the line must be known otherwise the problem will not be solved - ampawd
  • ctx.save //save ctx.draw //draw shape ctx.scale(-1, 1); //rotate shape ctx.restore // restore ctx.save //save ctx.draw //draw shape ctx.scale(-1, 1); //rotate shape ctx.restore // restore - TitaN

1 answer 1

Something I got into this task))

In general, one way to build a reflection is to drop the perpendicular from each point of the polygon to a line, find the coordinates of these points, and shift them to the vector of this perpendicular, since this value should be the same for both the reflected and the original polygon.

Essentially, it all comes down to finding these points on a line.

Let P0 a certain point of a polygon, denote by P1 , P2 points through which the line passes.

and let A be the point on the line obtained by the method described above.

then, due to the fact that the angle between the vectors (P0, A)(P1, P2) straight line - their scalar product (P0, A)(P1, P2) = 0

but on the other hand, A belongs to the line (P1, P2)

therefore, we get a simple system of two equations with two unknowns (Ax, Ay)

 (Ax - P0.x)*(P2.x - P1.x) + (Ay - P0.y)*(P2.y - P1.y) = 0 (Ax - P1.x)*(P2.y - P1.y) - (Ay - P1.y)*(P2.x - P1.x) = 0 

denote by B = P2.x - P1.x and C = P2.y - P1.y

after the simplest identity transformations of this system, we obtain an equivalent system

 B*Ax + C*Ay = B*P0.x + C*P0.y C*Ax - B*Ay = C*P1.x - B*P1.y 

trivially solvable, for example, by the cramer method.

  |B*P0.x + C*P0.y, C| |C*P1.x - B*P1.y, -B| Ax = --------------------- -B*B - C*C |B, B*P0.x + C*P0.y| |C, C*P1.y - B*P1.y| Ay = --------------------- -B*B - C*C 

and the final formula of a certain point of the reflected polygon will be

 x = Ax + (Ax - P0.x) y = Ay + (Ay - P0.y) 

interactive result

 (function() { const cnv = document.getElementById("cnv"); const ctx = cnv.getContext("2d"); const reflectbtn = document.getElementById("reflect"); const againbtn = document.getElementById("again"); function initApp() { cnv.width = window.innerWidth; cnv.height = window.innerHeight; } let Vec2 = function(x = 0, y = 0) { this.x = x; this.y = y; } let polygonVertices = [ new Vec2(150, 110), new Vec2(230, 10), new Vec2(300, 110) ]; let reflectionLinePoints = [ new Vec2(200, 310), new Vec2(300, 10) ]; function drawPolygon(vertices) { if (vertices.length == 0) return; vertices.forEach(function(v) { drawPoint(v); }); ctx.beginPath(); vertices.forEach(function(v) { ctx.lineTo(vx, vy); }); ctx.lineTo(vertices[0].x, vertices[0].y); ctx.stroke(); ctx.closePath(); } function drawLine(linePoints) { drawPoint(linePoints[0]); drawPoint(linePoints[1]); ctx.save(); ctx.beginPath(); ctx.setLineDash([5, 5]); ctx.moveTo(linePoints[0].x, linePoints[0].y); ctx.lineTo(linePoints[1].x, linePoints[1].y); ctx.stroke(); ctx.closePath(); ctx.restore(); } function computeA(p0, p1, p2) { let b = p2.x - p1.x; let c = p2.y - p1.y; let denom = b * (-b) - c * c; let ax = -b * (b * p0.x + c * p0.y) - c * (c * p1.x - b * p1.y); let ay = b * (c * p1.x - b * p1.y) - c * (b * p0.x + c * p0.y); return new Vec2( ax / denom, ay / denom ); } function drawPoint(p) { ctx.beginPath(); ctx.arc(px, py, 3, 0, 2 * Math.PI, false); ctx.fill(); ctx.closePath(); } function reflect(linePoints, polygonPoints) { let points = []; polygonPoints.forEach(function(p, i) { let a = computeA(p, linePoints[0], linePoints[1]); ax += ax - px; ay += ay - py; points.push(a); }); return points; } initApp(); drawPolygon(polygonVertices); drawLine(reflectionLinePoints); reflectbtn.onclick = function() { ctx.clearRect(0, 0, cnv.width, cnv.height); drawPolygon(polygonVertices); drawLine(reflectionLinePoints); let reflectedPoints = reflect(reflectionLinePoints, polygonVertices); drawPolygon(reflectedPoints); } againbtn.onclick = function() { ctx.clearRect(0, 0, cnv.width, cnv.height); drawPolygon(polygonVertices); drawLine(reflectionLinePoints); } }()); 
 <button id="reflect">reflect</button> <button id="again">again</button> <canvas id="cnv"></canvas>