Home Manual Reference Source Test Repository

src/misc/Line.js

'use strict';
/** @namespace misc */

const Point = require('./Point');

/**
 * Line in 2D space
 * @memberof misc
 */
class Line {
    /**
     * @param startPoint {misc.Point} - Start point of the line
     * @param endPoint {misc.Point} - End point of the line
     */
    constructor(startPoint, endPoint) {
        this._startPoint = startPoint;
        this._endPoint = endPoint;
    }

    /**
     * Get start point
     * @return {misc.Point}
     */
    getStartPoint() {
        return this._startPoint;
    }

    /**
     * Get end point
     * @return {misc.Point}
     */
    getEndPoint() {
        return this._endPoint;
    }

    /**
     * Check if it intersect with another line
     * @param line {misc.Line} - Another line to check intersection with
     * @return {Boolean} - True if two lines intersect
     */
    isIntersectWithLine(line) {
        return this._intersect(
            line.getStartPoint().getX(),
            line.getStartPoint().getY(),
            line.getEndPoint().getX(),
            line.getEndPoint().getY(),
            this._startPoint.getX(),
            this._startPoint.getY(),
            this._endPoint.getX(),
            this._endPoint.getY()
        );
    }

    // Reference: http://stackoverflow.com/a/40953705/1983050
    findIntersectionWithLine(line) {
        let slopeA = (this._startPoint.getY() - this._endPoint.getY()) / (this._startPoint.getX() - this._endPoint.getX());  // slope of line 1
        let slopeB = (line._startPoint.getY() - line._endPoint.getY()) / (line._startPoint.getX() - line._endPoint.getX());  // slope of line 2

        if ( slopeA - slopeB < Number.EPSILON) {
            return undefined;
        } else {
            return new Point(
                (slopeA * this._startPoint.getX() - slopeB * line._startPoint.getX() + line._startPoint.getY() - this._startPoint.getY()) / (slopeA - slopeB),
                (slopeA * slopeB * (line._startPoint.getX() - this._startPoint.getX()) + slopeB * this._startPoint.getY() - slopeA * line._startPoint.getY()) / (slopeB - slopeA)
            );
        }
    }

    findIntersectionWithPolygon(polygon) {
        let intersection = this.findIntersectionWithLine(new Line(
            polygon.getPoints()[0],
            polygon.getPoints()[polygon.getPoints().length - 1]
        ));
        if (intersection !== undefined) {
            return intersection;
        }

        for (let i = 0; i < polygon.getPoints().length - 1; i++) {
            let intersection = this.findIntersectionWithLine(new Line(
                    polygon.getPoints()[i],
                    polygon.getPoints()[i + 1]
                ));
            if (intersection !== undefined) {
                return intersection;
            }
        }
        return undefined;
    }


    /**
     * Check if it intersect with polygon
     * @param polygon {misc.Polygon} - Polygon to check intersection with
     * @returns {Boolean} - True if line intersect polygon
     */
    isIntersectWithPolygon(polygon) {
        if (this.isIntersectWithLine(new Line(
                polygon.getPoints()[polygon.getPoints().length - 1],
                polygon.getPoints()[0]
            )) === true) {
            return true;
        }

        for (let i = 0; i < polygon.getPoints().length - 1; i++) {
            if (this.isIntersectWithLine(new Line(
                polygon.getPoints()[i],
                polygon.getPoints()[i + 1]
            )) === true) {
                return true;
            }
        }
        return false;
    }

    // Reference: https://gist.github.com/Joncom/e8e8d18ebe7fe55c3894
    _intersect(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) {
        let s1_x, s1_y, s2_x, s2_y;
        s1_x = p1_x - p0_x;
        s1_y = p1_y - p0_y;
        s2_x = p3_x - p2_x;
        s2_y = p3_y - p2_y;

        let s, t;
        s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
        t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

        return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
    }


}

module.exports = Line;