绘制镜像线条了解一下?

功能需求:“用户绘制一条线,而后镜像出另一条线。”canvas

下面是我实现的过程,怕之后要用,就记下来了。bash

首先对问题的描述转化了一下:“求p(x, y)点, 关于直线p1(x1, y1), p2(x2, y2)镜像 获得P(Px, Py)” 。动画

带着这个问题开始思考,也在网上找了一些数学计算的公式。ui

step1 分析

先求关于点p1,p2的直线方程。(直线的通常方程Ax + By + C = 0spa

关于直线p1,p2对称有如下几种形式:3d

  • 关于X轴的对称code

    (p1.x = p2.x) 可知 直线(p1 p2) 与X轴垂直,获得直线方程 x = p1.x;cdn

  • 关于Y轴的对称blog

    (p1.y = p2.y) 可知 直线(p1 p2) 与Y轴垂直,获得直线方程 y = p1.y;ip

  • 关于某直线(p1, p2)的对称

    (p1.x != p2.x) && (p1.y != p2.y) 带入两点式 (y - p1.y) / (p2.y - p1.y) = (x - p1.x) / (p2.x - p1.x)

    直线(p1, p2)的斜率为 k = (p2.y - p1.y) / (p2.x - p1.x)

    获得直线方程:y = k * (x - p1.x) + p1.y;

step2 计算

求计算(p.x, p.y)关于直线Ax + By + C = 0对称的点:

Px = p.x - 2 * A (A * p.x + B * p.y + C) / (A^2 + B^2);
Py = p.y - 2 * B (A * p.x + B * p.y + C) / (A^2 + B^2);
复制代码
  • 关于X轴的对称

    有直线方程 x - p1.x = 0A = 1, B = 0, C = -p1.x,带入对称点计算公式获得

    Px = 2 * p1.x - p.x;
    
    Py = p.y;
    复制代码
  • 关于Y轴的对称

    有直线方程 y - p1.y = 0A = 0, B = 1, C = -p1.y,带入对称点计算公式获得

    Px = p.x;
     
    Py = 2 * p1.y - p.y;
    复制代码
  • 关于某直线(p1, p2)的对称

    有直线方程 y = k * (x - p1.x) + p1.yA = k, B = -1, C = -k * p1.x + p1.y,带入对称点计算公式获得

    Px = p.x - 2 * k * ( k * p.x - p.y + (-k * p1.x + p1.y)) / (Math.pow(k, 2) + 1);
     
     Py = p.y - 2 * -1 * ( k * p.x - p.y + (-k * p1.x + p1.y)) / (Math.pow(k, 2) + 1);
    复制代码

step3 绘制

点的公式都获得了,剩下的就是canvas绘制了。canvas的绘制这里就很少讲,直接写个demo直观点。

  • 创建直线
// 这里我绘制三条轴的起始点和终点(两点肯定一条直线),便于观察绘制的图形。

let canvasWidth = ctx.canvas.width;
let canvasHeight = ctx.canvas.height;
        
let axleX = {
    start: {
        x: canvasWidth,
        y: canvasHeight / 2
    },
    end: {
        x: 0,
        y: canvasHeight / 2
    }
};

let axleY = {
    start: {
        x: canvasWidth / 2,
        y: 0
    },
    end: {
        x: canvasWidth / 2,
        y: canvasHeight
    }
};

let axle = {
    start: {
        x: canvasWidth,
        y: 0
    },
    end: {
        x: 0,
        y: canvasHeight

    }
};

function drawAxle () {
    ctx.lineWidth = 1;
    ctx.lineJoin = ctx.lineCap = 'round';

    ctx.strokeStyle = '#000';

    ctx.beginPath();
    // x
    ctx.moveTo(axleX.start.x, axleX.start.y);
    ctx.lineTo(axleX.end.x, axleX.end.y);
    ctx.stroke();

    // y
    ctx.beginPath();
    ctx.moveTo(axleY.start.x, axleY.start.y);
    ctx.lineTo(axleY.end.x, axleY.end.y);
    ctx.stroke();

    // 对角
    ctx.beginPath();
    ctx.moveTo(axle.start.x, axle.start.y);
    ctx.lineTo(axle.end.x, axle.end.y);
    ctx.stroke();
};

drawAxle();

复制代码

分别关于X轴、Y轴、任意线(这里对角线为例子)

图一
  • 计算对称点(核心)

    由上述获得公式获得。

    function calcSymmetryPoint (p1, p2, p) {
    
        if (p1.x  ==  p2.x) {
        	 // 关于Y轴镜像
            return   {
                x: 2 * p1.x - p.x,
                y: p.y
            }
        } else if (p1.y  ==  p2.y) {
            // 关于X轴镜像
            return   {
                x: p.x,
                y: 2 * p1.y - p.y
            }
        }
        
        //  关于任意直线镜像
        let k1 = (p2.y - p1.y) / (p2.x - p1.x);
        
        let x = p.x - 2 * k1 * ( k1 * p.x - p.y + (-k1 * p1.x + p1.y))/ (Math.pow(k1, 2) + 1);
        let y = p.y - 2 * -1 * ( k1 * p.x - p.y + (-k1 * p1.x + p1.y))/ (Math.pow(k1, 2) + 1);
        
    	return   {
            x: x,
            y: y
        }
    }
    复制代码
  • 绘制

    伪代码以下:

    ...
    
      function mousemoveHandler (event) {
      	// 获得须要镜像的点(p.x, p.y)
      	let x = e.clientX - (w - canvasWidth) / 2;
      	let y = e.clientY - (h - canvasHeight) / 2;
      	  
      	// 获得镜像以后点的(Px,Py)
      	calcSymmetryPoint({x: axleX.start.x, y: axleX.start.y}, {x: axleX.end.x, y: axleX.end.y}, {x: x, y: y});
    
        calcSymmetryPoint({x: axleY.start.x, y: axleY.start.y}, {x: axleY.end.x, y: axleY.end.y}, {x: x, y: y});
    
        calcSymmetryPoint({x: axle.start.x, y: axle.start.y}, {x: axle.end.x, y: axle.end.y}, {x: x, y: y}); 
      	  
      	// 绘制.. 
      	// ctx.beginPath();
      	// ctx.moveTo(...);
      	// ctx.lineTo(...);
      	// ctx.stroke();
    }
    
    ...
    
    复制代码

    效果演示以下:

图二

这里只是重点描述一下怎么计算镜像点的坐标,(计算的方式还有矩阵)咱们能够用这个来作不少有趣的效果动画,另外也能够拓展到3d空间里去作镜像。

参考:

斜率: zh.wikipedia.org/wiki/%E6%96…

直线方程:zh.wikipedia.org/wiki/%E7%9B…

直线方程:baike.baidu.com/item/%E7%9B…


my_blog: www.flowers1225.com/

相关文章
相关标签/搜索