/**
* @file Class Triplet.
* @version March 12, 2017
*
* @author Olivier Pirson --- http://www.opimedia.be/
* @license GPLv3 --- Copyright (C) 2017 Olivier Pirson
*/
/**
* A triplet of points.
*/
class Triplet {
/**
* Constructs a triplet (a, b, c) of points.
*
* @param {Point} a
* @param {Point} b
* @param {Point} c
*/
constructor(a, b, c) {
assert(a instanceof Point, a);
assert(b instanceof Point, b);
assert(c instanceof Point, c);
this._a = a;
this._b = b;
this._c = c;
}
/**
* Returns the first point.
*
* @returns {Point}
*/
get a() { return this._a; }
/**
* Returns the second point.
*
* @returns {Point}
*/
get b() { return this._b; }
/**
* Returns the third point.
*
* @returns {Point}
*/
get c() { return this._c; }
/**
* Returns a new triplet, copied of this.
*
* @returns {Triplet}
*/
copy() {
return new Triplet(this.a, this.b, this.c);
}
/**
* Returns the cross product of the vector ab and bc.
*
* @returns {number}
*/
crossProductMagnitude() {
const a = this.a;
const b = this.b;
const c = this.c;
return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
}
/**
* Returns true iff a, b and c are on the same line.
*
* @returns {boolean}
*/
isCollinear() {
return isFloat0(this.orientation());
}
/**
* Returns true iff p is in the triangle formed by the triplet.
*
* Cf. http://stackoverflow.com/a/2049593/1333666
*
* @param {Point} p
*
* @returns {boolean}
*/
isIn(p) {
assert(p instanceof Point, p);
const ps = [this.a, this.b, this.c];
sortRadiallyAroundFirst(ps);
const a = ps[0];
const b = ps[1];
const c = ps[2];
const orient1 = (new Triplet(p, a, b)).isLeftOn();
const orient2 = (new Triplet(p, b, c)).isLeftOn();
const orient3 = (new Triplet(p, c, a)).isLeftOn();
return (orient1 === orient2) && (orient2 === orient3);
}
/**
* Returns true iff c is left to ab.
*
* @returns {boolean}
*/
isLeft() {
return (this.orientation() > 0);
}
/**
* Returns true iff c is left to ab or collinear.
*
* @returns {boolean}
*/
isLeftOn() {
return (this.orientation() >= 0);
}
/**
* Returns true iff c is right to ab.
*
* @returns {boolean}
*/
isRight() {
return (this.orientation() < 0);
}
/**
* Returns true iff c is right to ab or collinear.
*
* @returns {boolean}
*/
isRightOn() {
return (this.orientation() <= 0);
}
/**
* Returns the orientation of the point c compared to ab.
*
* If -1 then c is on the right,
* else if 0 then c is on the same line that ab,
* else if 1 then c is on the left.
*
* @returns {number} -1, 0 or 1
*/
orientation() {
const magnitude = this.crossProductMagnitude();
return Math.sign(magnitude);
}
/**
* Returns a string representation of the triplet.
*
* Each number is represented with at most precision figures after the decimal point.
*
* @returns {String}
*/
toString(precision=2) {
assert(Number.isInteger(precision), precision);
assert(precision >= 0, precision);
return (this.a.toString(precision)
+ ":" + this.b.toString(precision)
+ ":" + this.c.toString(precision));
}
}