• crop image 需要的基础知识


    refer : 

    https://www.youtube.com/watch?v=R7dObDtw1aA

    https://www.shuxuele.com/algebra/trig-finding-angle-right-triangle.html

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan

    https://www.rapidtables.com/convert/number/how-radians-to-degrees.html

    https://www.youtube.com/watch?v=ttO1TOs8048

    https://www.youtube.com/watch?v=6MDNDjtWfMw

    1. coordinate 和 css translate 是不同的东西

    数学有 coordinate x,y , 

    左上是 ( -x, +y )

    右上是 ( +x, +y)

    左下是 ( -x, -y)

    右下是 ( +x, -y)

    css translate 是说移动的方向. 

    +x 是往右

    -x 是往左 

    +y 是往下

    -y 是往上 

    注意 : coordinate y 和 translate y 是相反的. 

    2. 三角形和 tan sin cos

    tan sin cos 在 js 里是 Math.cos, Math.sin, Math.tan

    反向是 Math.acos, Math.asin, Math.atan 

    一般上我们 cos(degree) 使用的是 degree, 但是 js 使用的是 radian

    所以要背一个转换的公式 

    radian = degree * Math.PI / 180;

    export function degreeToRadian(degree: number): number {
      return degree * Math.PI / 180;
    }
    
    export function radianToDegree(radian: number): number {
      return radian * 180 / Math.PI;
    }

    求三角形斜线的长度是 

    export function calcRadius( number, height: number): number {
      return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
    }

    求 x, y coordinate 当拥有 degree 和 radius (斜线的长度)

    cos(deg) = x / radius

    sin(deg) = y / radius

    export function calcCoordinate(radius: number, degree: number): Xy {
      return {
        x: Math.cos(degreeToRadian(degree)) * radius,
        y: Math.sin(degreeToRadian(degree)) * radius
      }
    }

    求 degree 当有 x, y

    单靠反推上面求 x,y 的公式,我们是无法获取 degree 的,因为 cos(135) === cos(225).

    所以更好的做法是通过 tan 

    tan(d) = y / x

    有一点要特别注意就是, x y 的正负值, 代表了它在不同区域. 这个是会直接影响 degree 的. 我们要特别处理.

    export function calcDegree(coordinate: Xy): number {
      const { x, y } = coordinate;
      const result = radianToDegree(Math.atan(y / x));
      if (x < 0 && y >= 0) {
        return 180 - Math.abs(result); // 这里 result 是 negative
      }
      else if (x < 0 && y < 0) {
        return 180 + result; // 这里 result 是 positive
      }
      else if (x >= 0 && y < 0) {
        return 360 - Math.abs(result) // 这里 result 是 negative
      }
      else { 
        return result; // 这里 result 是 positive
      }
    }

    最后是 js 的另一个函数来做到上面一样的效果. Math.atan2(y, x)

    export function calcDegree(coordinate: Xy): number {
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2
      const result = radianToDegree(Math.atan2(coordinate.y, coordinate.x));
      return (result > 0) ? result : 360 - Math.abs(result);
    }

    css 的 rotate 和我们数学的方向也是不太一样的, 数学我们是 右边线开始,逆时针旋转 20 degree 是这样的. 上面的算法全部基于这个概念

     

    所以如果我想说下面这个 x, y 顺势旋转 20 degree 算法应该是.. 

    export function calcCoordinateAfterRotate(currentCoordinate: Xy, rotateDegree: number): Xy {
      const radius = calcRadius(Math.abs(currentCoordinate.x), Math.abs(currentCoordinate.y));
      const degree = calcDegree(currentCoordinate);
      const degreeAfterRotate = degree - rotateDegree;
      return calcCoordinate(radius, degreeAfterRotate);
    }

    换算 coordinate 去 translate x, y

    export function calcTranslate(fromCoordinate: Xy, toCoordinate: Xy): Xy {
      return {
        x: toCoordinate.x - fromCoordinate.x,
        y: fromCoordinate.y - toCoordinate.y
      }
    }

    练习题 : 

    假设有 2 个点, a 和 b 连成一条斜线. 

    a = 1, 1

    b = 11, 11

    问 x = 7, y = 多少 ?

    先做一个十字架基于 a 点, 然后换算 b 点 和 x 坐标

     

    现在来求角度 

    10, 10 求一个角度, 上面已经有公式了, 用 atan2 

    calcDegree(10, 10);

    角度是 45 degree 

    有 degree , 和 x, 我们可以算出 radius 

    cos(degree) = x / radius 

    radius = x / cos(degree)

    8.482 = 6 / cos(45) 

    现在我们有了 三角形的底部 6 和 斜线 8.482 

    那我们要求高,公式可以用这个

    radius = sqrt( pow2(x) + pow2(y) ) 求 y 

    8.482 = sqrt( pow2(6) + pow2(y) )

    pow2(8.482) = pow2(6) + pow2(y) 

    pow2(8.482) - pow2(6) = pow2(y)

    sqrt( pow2(8.482) - pow2(6) ) = y 

    y = 5.99... 进位就是 6 了 

    x = 6 , y = 6 这个是对应 a point 的, 

    记得一开始我们画了多一个十字架来找角度吗 ? 

    那现在我们得换算回去. 

    x = 6 + a.x, y = 6 + a.y;

    所以最后是 7, 7

    这个例子比较简单, 因为都是 positive 坐标, 如果是 negetive 角度可能会取代 225 degree 

    但我们计算三角形是不会有 225 degree 的,所以要特别处理一下. 看代码自己试试吧

    export function calcHitLineCoordinateByXOrY(
      startLineCoordinate: Xy,
      endLineCoordinate: Xy,
      by: 'x' | 'y',
      xOrY: number
    ): number {
      const min = Math.min(startLineCoordinate[by], endLineCoordinate[by]);
      const max = Math.max(startLineCoordinate[by], endLineCoordinate[by]);
      if (xOrY < min || xOrY > max) { 
        console.error(`bug ! x or y over line, this is impossible to hit line`);
        throw 0;
      }
      // 对应 startLineCoordinate
      endLineCoordinate = {
        x: endLineCoordinate.x - startLineCoordinate.x,
        y: endLineCoordinate.y - startLineCoordinate.y
      }
      xOrY = xOrY - startLineCoordinate[by];
      const degree = calcDegree(endLineCoordinate);
      const degreeInside90Degree = degree % 90;
      const radius = calcRadiusByDegreeAndWidtOrhHeight(
        degreeInside90Degree,
        by === 'x' ? 'width':'height',
        Math.abs(xOrY)
      );
      const widthOrHeight = Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.abs(xOrY), 2));
      let resultXOrY = widthOrHeight;
      if (by === 'x' && degree > 180) {
        resultXOrY *= -1;
      }
      else if (by === 'y' && degree > 90 && degree < 270) { 
        resultXOrY *= -1;
      }
      return resultXOrY + startLineCoordinate[by];
    }

    3. 直线方程式 Linear equation 和 斜率 slope

    通常当我们想算出 2 条线交叉点坐标得时候就会用到下面这个公式了

    代码表达

    const lineA = {
      start: { x: 1, y: 2 },
      end: { x: 5, y: 6 }
    }
    
    const lineB = {
      start: { x: 2, y: 5 },
      end: { x: 6, y: 1 }
    }

    那我们要求得是交叉也就是坐标 3, 4 

    这题就需要直线方程式 和斜率了 

    直线方程式是这样的

    y - y0 = m * (x - x0);

    x0, y0 是点的坐标, x 和 y 则是用来求交叉的 

    m 是 slope , 就是斜率. 

    我们如果有 2 条线的 x0 y0 和 m 

    然后把 2 个公式拿来解就可以算出 x 值和 y 值, x, y 就是交叉的坐标了. 

    那么我们看看这个 m 是这么来的。 

    最开始我们有 2 条线, 也就是 4 个坐标点. 

    m = (y1 - y0) / (x1 - x0)

    这里有一个重要得点, 哪个坐标算是 0 哪个又应该是 1 呢? 

    线一定是左到右画的. 

    所以哪一个点的 x 比较小就是 start 

    线往上方走, m 将会是 positive 

    往下走是 negative 

    平行线则是 0 

    这个 positive negative 会影响算法的哦,别弄错. 

    有了这些概念,就容易了

    先算出 2 条线分别的 m 

    然后放入直线公式里,然后就可以对解 2 个公式了 

    2 个公式就可以解除 x,y 了

    下面是用 ts 的表达. 

    function calcIntersectionCoordinate(aLine: Line, bLine: Line): Xy {
      if (aLine.start.x > aLine.end.x) { 
        aLine = { start: aLine.end, end: aLine.start }
      }
      if (bLine.start.x > bLine.end.x) { 
        bLine = { start: aLine.end, end: aLine.start }
      }
      const aLineSlope = (aLine.end.y - aLine.start.y) / (aLine.end.x - aLine.start.x);
      const bLineSlope = (bLine.end.y - bLine.start.y) / (bLine.end.x - bLine.start.x);
    
      const x0 = aLine.start.x;
      const y0 = aLine.start.y;
      const m0 = aLineSlope;
      const x1 = bLine.start.x;
      const y1 = bLine.start.y;
      const m1 = bLineSlope;
     
      const x = (-(m1 * x1) + y1 - y0 + (m0 * x0)) / (m0 - m1);
      const y = (m0 * x) - (m0 * x0) + y0;
    
      return { x, y };
    }
  • 相关阅读:
    [ZOJ 3622] Magic Number
    SGU 134.Centroid(图心)
    SGU 223.Little Kings
    C++ IO 详细用法
    POJ2632 Crashing Robots 解题报告
    POJ1068 Parencodings 解题报告
    POJ3295 Tautology 解题报告
    POJ2586 Y2K Accounting Bug 解题报告
    POJ1328 Radar Installation 解题报告
    POJ3728 The merchant解题报告
  • 原文地址:https://www.cnblogs.com/keatkeat/p/10389742.html
Copyright © 2020-2023  润新知