'use strict';
var Thing = require('./thing.js');
/**
* @class Polygon
* @augments Thing
*/
function Polygon() {
if (arguments.length !== 0) {
throw new Error('You should pass exactly 0 arguments to <span ' +
'class="code">new Polygon()</span>');
}
Thing.call(this);
this.points = [];
this.width = 0; // max x-distance of points in the polygon
this.height = 0; // max y-distance of points in the polygon
this.type = 'Polygon';
}
Polygon.prototype = new Thing();
Polygon.prototype.constructor = Polygon;
/**
* Draws the polygon in the canvas.
*
* @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module.
*/
Polygon.prototype.draw = function(__graphics__) {
if (this.points.length === 0) {
return;
}
var context = __graphics__.getContext();
context.fillStyle = this.color.toString();
context.beginPath();
var first = this.points[0];
context.moveTo(first.x, first.y);
for (var i = 1; i < this.points.length; i++) {
var cur = this.points[i];
context.lineTo(cur.x, cur.y);
}
context.closePath();
context.fill();
};
/**
* Checks if the passed point is contained in the polygon.
*
* @param {number} x - The x coordinate of the point being tested.
* @param {number} y - The y coordinate of the point being tested.
* @returns {boolean} Whether the passed point is contained in the polygon.
*/
Polygon.prototype.containsPoint = function(x, y) {
for (var i = 0; i < this.points.length; i++) {
if (x == this.points[i].x && y == this.points[i].y) {
return true;
}
}
var edges = [];
for (var i = 1; i < this.points.length; i++) {
var edge = {
x1: this.points[i-1].x,
y1: this.points[i-1].y,
x2: this.points[i].x,
y2: this.points[i].y,
}
edges.push(edge);
if (i == this.points.length - 1) {
edge = {
x1: this.points[i].x,
y1: this.points[i].y,
x2: this.points[0].x,
y2: this.points[0].y,
}
edges.push(edge);
}
}
var numIntersections = 0;
for (var i = 0; i < edges.length; i++) {
var betweenYs = (edges[i].y1 <= y && y <= edges[i].y2) || (edges[i].y2 <= y && y <= edges[i].y1);
if (edges[i].x1 == edges[i].x2) {
return (betweenYs && edges[i].x1 >= x);
}
var slope = (edges[i].y2 - edges[i].y1)/(edges[i].x2 - edges[i].x1);
var xIntersect = ((y - edges[i].y1)/slope) + edges[i].x1;
if (betweenYs && xIntersect >= x) {
numIntersections++;
}
}
return (numIntersections % 2 == 1);
};
/**
* Gets the width of the rectangle.
*
* @returns {number} Width of the rectangle.
*/
Polygon.prototype.getWidth = function() {
return this.width;
};
/**
* Gets the height of the rectangle.
*
* @returns {number} Height of the rectangle.
*/
Polygon.prototype.getHeight = function() {
return this.height;
};
/**
* Adds a vertex to the polygon.
*
* @param {number} x - The x coordinate of the desired new vertex.
* @param {number} y - The y coordinate of the desired new vertex.
*/
Polygon.prototype.addPoint = function(x, y) {
if (arguments.length !== 2) {
throw new Error('You should pass exactly 2 arguments to <span ' +
'class="code">addPoint(x, y)</span>');
}
if (typeof x !== 'number' || !isFinite(x)) {
throw new TypeError('Invalid value for x-coordinate. ' +
'Make sure you are passing finite numbers to ' +
'<span class="code">addPoint(x, y)</span>.');
}
if (typeof y !== 'number' || !isFinite(y)) {
throw new TypeError('Invalid value for y-coordinate. ' +
'Make sure you are passing finite numbers to ' +
'<span class="code">addPoint(x, y)</span>.');
}
for (var i = 0; i < this.points.length; i++) {
if (Math.abs(x - this.points[i].x) > this.width) {
this.width = Math.abs(x - this.points[i].x);
}
if (Math.abs(y - this.points[i].y) > this.height) {
this.height = Math.abs(y - this.points[i].y);
}
}
this.points.push({x: x, y: y});
};
/**
* Moves the entire polygon.
*
* @param {number} dx - The change in x coordinate of all starting and ending points.
* @param {number} dy - The change in y coordinate of all starting and ending points.
*/
Polygon.prototype.move = function(dx, dy) {
if (arguments.length !== 2) {
throw new Error(
'You should pass exactly 2 arguments to <span ' + 'class="code">move</span>'
);
}
if (typeof dx !== 'number' || !isFinite(dx)) {
throw new TypeError(
'Invalid number passed for <span class="code">' +
'dx</span>. Make sure you are passing finite numbers to <span ' +
'class="code">move(dx, dy)</span>'
);
}
if (typeof dy !== 'number' || !isFinite(dy)) {
throw new TypeError(
'Invalid number passed for <span class="code">' +
'dy</span>. Make sure you are passing finite numbers to <span ' +
'class="code">move(dx, dy)</span>'
);
}
for (var i = 0; i < this.points.length; i++) {
this.points[i].x += dx;
this.points[i].y += dy;
}
};
module.exports = Polygon;