Quark-Renderer----第十三篇

2021SC@SDUSC

综述

上次,我们主要对几何学意思上的点进行了分析,它具有正常点的特征,如横纵坐标,以及一些关于点的方法,该类主要作为一个基本的类,然后作为最基本的构件,后面的所有都可以通过这个来进行创建。
本次我们主要对几何意义上的线进行分析。描述几何意义上的线的js文件在描述点的同一文件夹下,都是geometric中的内容,在GeoLine.js中,我们可以看到作者的注释,关于对几何意义上的直线的定义,它看不见,没有宽度,用来进行数学运算,此实现从diagramo改进而来。下面我们将对其中的关键的方法属性分别讨论。

对GeoLine.js的解析

在该js文件中主要就是对于GeoLine类的描述,并将其导出。首先是构造函数,有两个自身属性,分别是起始点和终点。

  constructor(startPoint, endPoint) {
    
    
    this.startPoint = startPoint;
    this.endPoint = endPoint;
  }

load函数

load主要是的作用就是从JSON对象中创建直线,需要传一个JSON对象,然后调用GeoLine的构造函数,传入参数,然后返回这个直线

  static load(o) {
    
    
    let newLine = new GeoLine(GeoPoint.load(o.startPoint), GeoPoint.load(o.endPoint));
    return newLine;
  }

contains函数

该函数的作用就是测试某个点是否位于直线上(这里的直线不是数学意义上的无限延长的直线,而是线段),该函数用到的主要算法就是计算斜率,看看(x,y)是否处在这个线段上.
主要流程如下:先检查是否是竖线,即x不变为常数,因为竖线的斜率不存在,因此我们要单独讨论;而后我们在else中进行分析非竖线的情况,先求出直线的斜率a,以及他的b,这个是直线方程式的两个参数,然后判断参数(x,y)是否满足这个式子y == a * x + b,只需返回这个结果就可以了。

  contains(x, y) {
    
    
    // if the point is inside rectangle bounds of the segment
    if (
      mathMin(this.startPoint.x, this.endPoint.x) <= x &&
      x <= mathMax(this.startPoint.x, this.endPoint.x) &&
      mathMin(this.startPoint.y, this.endPoint.y) <= y &&
      y <= mathMax(this.startPoint.y, this.endPoint.y)
    ) {
    
    
      // check for vertical line
      if (this.startPoint.x == this.endPoint.x) {
    
    
        return x == this.startPoint.x;
      } else {
    
    
        // usual (not vertical) line can be represented as y = a * x + b
        let a = (this.endPoint.y - this.startPoint.y) / (this.endPoint.x - this.startPoint.x);
        let b = this.startPoint.y - a * this.startPoint.x;
        return y == a * x + b;
      }
    } else {
    
    
      return false;
    }
  }

near函数

该函数的主要作用是判断某个点是否在某个角度上接近这条线,端点也需要考虑。
在该函数中,我们需要传入三个参数,分别是x,y和radius角度,分别表示这个点的坐标和角度。首先判断这个直线是否是竖线,如果是竖线,则直接根据范围进行判断;对于横线也是如此;将这两种特殊情况考虑完之后,我们就需要对该直线进行操作,首先确定起始点和终点的坐标,然后计算点到直线的距离,这个是一个数学式子,通过计算得到的结果,我们再与radius进行比较,得到结果,最后返回结果。

near(x, y, radius) {
    
    
    if (this.endPoint.x === this.startPoint.x) {
    
    
      //Vertical line, so the vicinity area is a rectangle
      return (
        ((this.startPoint.y - radius <= y && this.endPoint.y + radius >= y) || (this.endPoint.y - radius <= y && this.startPoint.y + radius >= y)) &&
        x > this.startPoint.x - radius &&
        x < this.startPoint.x + radius
      );
    }

    if (this.startPoint.y === this.endPoint.y) {
    
    
      //Horizontal line, so the vicinity area is a rectangle
      return (
        ((this.startPoint.x - radius <= x && this.endPoint.x + radius >= x) || (this.endPoint.x - radius <= x && this.startPoint.x + radius >= x)) &&
        y > this.startPoint.y - radius &&
        y < this.startPoint.y + radius
      );
    }

    let startX = mathMin(this.endPoint.x, this.startPoint.x);
    let startY = mathMin(this.endPoint.y, this.startPoint.y);
    let endX = mathMax(this.endPoint.x, this.startPoint.x);
    let endY = mathMax(this.endPoint.y, this.startPoint.y);

    /*We will compute the distance from point to the line
     * by using the algorithm from
     * http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
     * */

    //First we need to find a,b,c of the line equation ax + by + c = 0
    let a = this.endPoint.y - this.startPoint.y;
    let b = this.startPoint.x - this.endPoint.x;
    let c = -(this.startPoint.x * this.endPoint.y - this.endPoint.x * this.startPoint.y);

    //Secondly we get the distance 
    let d = mathAbs((a * x + b * y + c) / mathSqrt(mathPow(a, 2) + mathPow(b, 2)));

    //Thirdly we get coordinates of closest line's point to target point
    let closestX = (b * (b * x - a * y) - a * c) / (mathPow(a, 2) + mathPow(b, 2));
    let closestY = (a * (-b * x + a * y) - b * c) / (mathPow(a, 2) + mathPow(b, 2));

    let r =
      (d <= radius && endX >= closestX && closestX >= startX && endY >= closestY && closestY >= startY) || //the projection of the point falls INSIDE of the segment
      this.startPoint.near(x, y, radius) ||
      this.endPoint.near(x, y, radius); //the projection of the point falls OUTSIDE of the segment

    return r;
  }

GeoLine上的一些自身方法

getPoint函数

该函数的作用就是获得端点,然后构成数组返回。主要就是初始化数组用来存放起始点和终点,然后将这个返回。

  getPoints() {
    
    
    let points = [];
    points.push(this.startPoint);
    points.push(this.endPoint);
    return points;
  }

getPoint 函数

该函数的作用就是获取指定百分比上的点,参数t是百分比。这个百分比主要是通过计算比率,再当前的位置信息,通过t来确定通过当前的点,然后返回。

  getPoint(t) {
    
    
    let xp = t * (this.endPoint.x - this.startPoint.x) + this.startPoint.x;
    let yp = t * (this.endPoint.y - this.startPoint.y) + this.startPoint.y;
    return new GeoPoint(xp, yp);
  }

clone函数

该函数得主要作用就是返回一个新的直线,并且直线的信息完全相同,即克隆。

  clone() {
    
    
    let ret = new GeoLine(this.startPoint.clone(), this.endPoint.clone());
    return ret;
  }

equals函数

该函数的主要作用就是判断当前的线段是否为同一条,首先判断类型,如果传入的不是线段,那么直接返回,其次在判断这两条线的起始点的坐表是否相同。

  equals(anotherLine) {
    
    
    if (!(anotherLine instanceof GeoLine)) {
    
    
      return false;
    }
    return this.startPoint.equals(anotherLine.startPoint) && this.endPoint.equals(anotherLine.endPoint);
  }

总结

以上便是所有的关于GeoLine的内容,最关键的两个方法就是contain和near方法,判断一个点是否再这条直线上或者是否在附近,其次我们也对他们的自身的一些方法进行了讨论。
总而言之,我们完成了对GeoLine.js的分析,下篇,我们将通过这两次学到的点和线的知识 进行分析其他几何意义上的模型。

猜你喜欢

转载自blog.csdn.net/qq_53259920/article/details/121971718
今日推荐