Quark-Renderer--Article 12

Posted by jammer on Sat, 25 Dec 2021 10:19:55 +0100

2021SC@SDUSC

Overview

Last time, we mainly analyzed points of geometric meaning, which have the characteristics of normal points, such as the horizontal and vertical coordinates, as well as some methods about points, which act as a basic class, then as the most basic component, through which all the following can be created.
This time we will focus on the analysis of lines in geometric sense. The js files describing lines in geometry are all contents of geometric in the same folder as describing points, in GeoLine.js, we can see the author's comment on the geometric definition of a line that is invisible and has no width for mathematical operations, an implementation improved from diagramo. The key method properties are discussed separately below.

For GeoLine. Parsing of JS

The main purpose of this js file is to describe and export the GeoLine class. The first is the constructor, which has two properties of its own, starting and ending points.

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

load function

The main purpose of load is to create a straight line from a JSON object. You need to pass in a JSON object, then call GeoLine's constructor, pass in parameters, and return the straight line

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

contains function

The function tests whether a point is on a straight line (where the line is not mathematically an infinitely extended line, but a segment), and the main algorithm used by the function is to calculate the slope to see if (x, y) is on that segment.
The main flow is as follows: First, check if the vertical line is vertical, that is, X does not change to a constant, because the slope of the vertical line does not exist, so we will discuss it separately; Then we analyze the case of non-vertical lines in else, first find the slope of the line a and his b, which are two parameters of the linear equation, and then determine if the parameter (x,y) satisfies the equation y == a * x + b, simply return this result.

  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 function

The main purpose of this function is to determine whether a point is approaching the line at an angle, and the endpoint also needs to be considered.
In this function, we need to pass in three parameters, x, y, and radius angles, representing the coordinates and angles of this point. The first step is to determine whether the line is a vertical line or not, and if it is a vertical line, it is directly based on the extent. The same is true for horizontal lines; After considering these two special cases, we need to operate on the straight line. First we determine the coordinates of the starting point and the ending point, and then we calculate the distance from the point to the straight line. This is a mathematical formula. After the calculation, we compare the result with radius, get the result, and return the result.

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;
  }

Some of their own methods on GeoLine

getPoint function

The purpose of this function is to get the endpoints and form an array to return them. The main thing is to initialize the array to hold the start and end points, and then return this.

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

getPoint function

The purpose of this function is to get a point at a specified percentage, with parameter t being a percentage. This percentage is determined by calculating the ratio, the current location information, and t to pass through the current point, and then return.

  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 function

The main function is to return a new straight line with exactly the same information, cloning.

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

equals function

The main purpose of this function is to determine whether the current line segment is the same, first to determine the type, then to return directly if the incoming line is not a segment, and then to determine whether the two lines start at the same sitting table.

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

summary

That's all about GeoLine. The two most critical methods are the contain and near methods, which determine whether a point is on or near this line. Next, we discuss some of their own methods.
All in all, we've finished working on GeoLine.js analysis, in the next section, we will use this knowledge of points and lines to analyze other geometric models.

Topics: Javascript