Source: geom/Rectangle.js

//------------------------------------------------------------------------------
// Constructor scope
//------------------------------------------------------------------------------

/**
 * Creates a new Rectangle object with the top-left corner specified by the x 
 * and y parameters and with the specified width and height parameters.
 *
 * @constructor
 * @extends rune.geom.Point
 *
 * @param {number} [x=0.0] The x coordinate of the top-left corner of the rectangle.
 * @param {number} [y=0.0] The y coordinate of the top-left corner of the rectangle.
 * @param {number} [width=0.0] The y coordinate of the top-left corner of the rectangle.
 * @param {number} [height=0.0] The height of the rectangle, in pixels.
 * 
 * @class
 * @classdesc
 * 
 * A Rectangle object is an area defined by its position, as indicated by its 
 * top-left corner point (x, y) and by its width and its height.
 */
rune.geom.Rectangle = function(x, y, width, height) {

	//--------------------------------------------------------------------------
	// Protected properties
	//--------------------------------------------------------------------------

	/**
	 * The width of the rectangle, in pixels.
	 *
	 * @type {number}
	 * @protected
	 * @ignore
	 */
	this.m_width = width || 0.0;

	/**
	 * The height of the rectangle, in pixels.
	 *
	 * @type {number}
	 * @protected
	 * @ignore
	 */
	this.m_height = height || 0.0;

	//--------------------------------------------------------------------------
	// Super call
	//--------------------------------------------------------------------------
	
	/**
	 * Extend rune.geom.Point
	 */
	rune.geom.Point.call(this, x, y);
};

//------------------------------------------------------------------------------
// Inheritance
//------------------------------------------------------------------------------

rune.geom.Rectangle.prototype = Object.create(rune.geom.Point.prototype);
rune.geom.Rectangle.prototype.constructor = rune.geom.Rectangle;

//------------------------------------------------------------------------------
// Public static methods
//------------------------------------------------------------------------------

/**
 * Determines whether a point is contained within a rectangular region.
 *
 * @param {number} x1 The x coordinate of the rectangle.
 * @param {number} y1 The y coordinate of the rectangle.
 * @param {number} w1 The width of the rectangle.
 * @param {number} h1 The height of the rectangle.
 * @param {number} x2 The x coordinate of the point.
 * @param {number} y2 The y coordinate of the point.
 *
 * @return {boolean} A value of true if the rectangle contains the specified point; otherwise false.
 */
rune.geom.Rectangle.containsPoint = function(x1, y1, w1, h1, x2, y2) {
	return (x2 >= x1 &&
			x2 <= x1 + w1 &&
			y2 >= y1 &&
			y2 <= y1 + h1);
};

/**
 * Determines if a rectangle is contained by another rectangle.
 *
 * @param {number} x1 The x coordinate of the first rectangle.
 * @param {number} y1 The y coordinate of the first rectangle.
 * @param {number} w1 The width of the first rectangle.
 * @param {number} h1 The height of the first rectangle.
 * @param {number} x2 The x coordinate of the second rectangle.
 * @param {number} y2 The y coordinate of the second rectangle.
 * @param {number} w2 The width of the second rectangle.
 * @param {number} h2 The height of the second rectangle.
 *
 * @return {boolean} A value of true if the rectangle is contained by another rectangle; otherwise false.
 */
rune.geom.Rectangle.containsRectangle = function(x1, y1, w1, h1, x2, y2, w2, h2) {
	if ((w2 * h2) > (w1 * h1)) return false;
	
	return ((x2 >= x1 && x2 <= x1 + w1) &&
			(x2  + w2 >= x1 && x2 + w2 <= x1 + w1) &&
			(y2 >= y1 && y2 <= y1 + h1) &&
			(y2  + h2 >= y1 && y2 + h2 <= y1 + h2));
};

/**
 * Creates a clone of a Rectangle object.
 *
 * @param {rune.geom.Rectangle} from The Rectangle object to be cloned.
 *
 * @return {rune.geom.Rectangle} The new, cloned Rectangle object.
 */
rune.geom.Rectangle.clone = function(from) {
	return new rune.geom.Rectangle(
		from['x'],
		from['y'],
		from['width'],
		from['height']
	);
};

/**
 * Copies the properties of one Rectangle object to another Rectangle object.
 *
 * @param {rune.geom.Rectangle} from Rectangle objects to copy from.
 * @param {rune.geom.Rectangle} to Rectangle objects to copy to.
 *
 * @return {rune.geom.Rectangle} The rectangle object that represents the copy.
 */
rune.geom.Rectangle.copy = function(from, to) {
	to['x'] = from['x'];
	to['y'] = from['y'];
	to['width']  = from['width'];
	to['height'] = from['height'];
	
	return to;
};

/**
 * Returns the area of intersection as a Rectangle object.
 * 
 * @param {number} x1 The x coordinate of the first rectangle.
 * @param {number} y1 The x coordinate of the first rectangle.
 * @param {number} w1 The width of the first rectangle.
 * @param {number} h1 The height of the first rectangle.
 * @param {number} x2 The x coordinate of the second rectangle.
 * @param {number} y2 The y coordinate of the second rectangle.
 * @param {number} w2 The width of the second rectangle.
 * @param {number} h2 The height of the second rectangle.
 * @param {rune.geom.Rectangle} [o] Store results in this object.
 * 
 * @return {rune.geom.Rectangle} A Rectangle object that equals the area of intersection.
 */
rune.geom.Rectangle.intersection = function(x1, y1, w1, h1, x2, y2, w2, h2, o) {
	o = o || new rune.geom.Rectangle(0, 0, 0, 0);
	if (rune.geom.Rectangle.intersects(x1, y1, w1, h1, x2, y2, w2, h2)) {
		o['x'] = Math.max(x1, x2);
		o['y'] = Math.max(y1, y2);
		o['width']  = Math.min(x1 + w1,  x2 + w2) - o['x'];
		o['height'] = Math.min(y1 + h1,  y2 + h2) - o['y'];
	}
	
	return o;
};

/**
 * Determine whether or not two rectangles intersects.
 * 
 * @param {number} x1 The x coordinate of the first rectangle.
 * @param {number} y1 The x coordinate of the first rectangle.
 * @param {number} w1 The width of the first rectangle.
 * @param {number} h1 The height of the first rectangle.
 * @param {number} x2 The x coordinate of the second rectangle.
 * @param {number} y2 The y coordinate of the second rectangle.
 * @param {number} w2 The width of the second rectangle.
 * @param {number} h2 The height of the second rectangle.
 * 
 * @return {boolean} A value of true if the specified point intersects with this rectangle; otherwise false.
 */
rune.geom.Rectangle.intersects = function(x1, y1, w1, h1, x2, y2, w2, h2) {
	return ((x1 <= x2 + w2) && 
			(x1  + w1 > x2) && 
			(y1 <= y2 + h2) && 
			(y1  + h1 > y2));
};

//------------------------------------------------------------------------------
// Public getter and setter methods
//------------------------------------------------------------------------------

/**
 * The sum of the y and height properties.
 *
 * @member {number} bottom
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "bottom", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['y'] + this['height'];
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['y'] = value - this['height'];
	}
});

/**
 * The location of the Rectangle object's bottom-left corner, determined by the
 * values of the left and bottom properties.
 *
 * @member {rune.geom.Rectangle} bottomLeft
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "bottomLeft", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(this['x'], this['y'] + this['height']);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value.x;
		this['y'] = value.y - this['height'];
	}
});

/**
 * The location of the Rectangle object's bottom-right corner, determined by the
 * values of the right and bottom properties.
 *
 * @member {rune.geom.Rectangle} bottomRight
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "bottomRight", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(this['x'] + this['width'], this['y'] + this['height']);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value['x'] - this['width'];
		this['y'] = value['y'] - this['height'];
	}
});

/**
 * The center point of the rectangle object.
 *
 * @member {rune.geom.Point} center
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "center", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(this['x'] + (this['width'] >> 1), this['y'] + (this['height'] >> 1));
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value.x - (this['width']  >> 1);
		this['y'] = value.y - (this['height'] >> 1);
	}
});

/**
 * The x coordinate of the center of the object.
 *
 * @member {number} centerX
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "centerX", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['x'] + (this['width'] >> 1);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value - (this['width'] >> 1);
	}
});

/**
 * The y coordinate of the center of the object.
 *
 * @member {number} centerY
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "centerY", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['y'] + (this['height'] >> 1);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['y'] = value - (this['height']  >> 1);
	}
});

/**
 * The height of the rectangle, in pixels.
 *
 * @member {number} height
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "height", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this.m_height;
	},

	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this.m_height = value;
	}
});

/**
 * The x coordinate of the top-left corner of the rectangle.
 *
 * @member {number} left
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "left", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['x'];
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value;
	}
});

/**
 * The sum of the x and width properties.
 *
 * @member {number} right
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "right", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['x'] + this['width'];
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value - this['width'];
	}
});

/**
 * The size of the Rectangle object, expressed as a Point object with the values
 * of the width and height properties.
 *
 * @member {rune.geom.Point} size
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "size", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(
			this['width'],
			this['height']
		);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['width']  = value['x'];
		this['height'] = value['y'];
	}
});

/**
 * The y coordinate of the top-left corner of the rectangle.
 *
 * @member {number} top
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "top", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this['y'];
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['y'] = value;
	}
});

/**
 * The location of the Rectangle object's top-left corner, determined by the x 
 * and y coordinates of the point.
 *
 * @member {rune.geom.Point} topLeft
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "topLeft", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(this['x'], this['y']);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value['x'];
		this['y'] = value['y'];
	}
});

/**
 * The location of the Rectangle object's top-right corner, determined by the x 
 * and y coordinates of the point.
 *
 * @member {rune.geom.Point} topRight
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "topRight", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return new rune.geom.Point(this['x'] + this['width'], this['y']);
	},
	
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this['x'] = value.x - this['width'];
		this['y'] = value.y;
	}
});

/**
 * The width of the rectangle, in pixels.
 *
 * @member {number} width
 * @memberof rune.geom.Rectangle
 * @instance
 */
Object.defineProperty(rune.geom.Rectangle.prototype, "width", {
	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	get : function() {
		return this.m_width;
	},

	/**
	 * @this rune.geom.Rectangle
	 * @ignore
	 */
	set : function(value) {
		this.m_width = value;
	}
});

//------------------------------------------------------------------------------
// Override public prototype methods
//------------------------------------------------------------------------------

/**
 * Builds and returns a string that lists the horizontal and vertical positions 
 * and the width and height of the Rectangle object.
 *
 * @return {string}
 */
rune.geom.Rectangle.prototype.toString = function() {
	return "[{Rectangle (x=" + this['x'] + " y=" + this['y'] + " width=" + this['width'] + " height=" + this['height'] + ")}]";
};

//------------------------------------------------------------------------------
// Public prototype methods
//------------------------------------------------------------------------------

/**
 * Determines whether the specified point is contained within the rectangular 
 * region defined by this Rectangle object.
 *
 * @param {rune.geom.Point} point The point, as represented by its x and y coordinates.
 *
 * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
 */
rune.geom.Rectangle.prototype.containsPoint = function(point) {
	return rune.geom.Rectangle.containsPoint(
		this['x'],
		this['y'],
		this['width'],
		this['height'],
		point['x'],
		point['y']
	);
};

/**
 * Determines whether the Rectangle object specified by the rect parameter is 
 * contained within this Rectangle object. A Rectangle object is said to contain
 * another if the second Rectangle object falls entirely within the boundaries 
 * of the first.
 *
 * @param {rune.geom.Rectangle} rect The Rectangle object being checked.
 *
 * @return {boolean} A value of true if the Rectangle object that you specify is contained by this Rectangle object; otherwise false.
 */
rune.geom.Rectangle.prototype.containsRectangle = function(rect) {
	return rune.geom.Rectangle.containsRectangle(
		this['x'],
		this['y'],
		this['width'],
		this['height'],
		rect['x'],
		rect['y'],
		rect['width'],
		rect['height']
	);
};

/**
 * If the Rectangle object specified in the toIntersect parameter intersects 
 * with this Rectangle object, returns the area of intersection as a Rectangle 
 * object. If the rectangles do not intersect, this method returns an empty 
 * Rectangle object with its properties set to 0.
 *
 * @param {rune.geom.Rectangle} toIntersect The Rectangle object to compare against to see if it intersects with this Rectangle object.
 * @param {rune.geom.Rectangle} [output] A Rectangle object to store the intersection results in.
 *
 * @return {rune.geom.Rectangle} A Rectangle object that equals the area of intersection.
 */
rune.geom.Rectangle.prototype.intersection = function(toIntersect, output) {
	return rune.geom.Rectangle.intersection(
		this['x'],
		this['y'],
		this['width'],
		this['height'],
		toIntersect['x'],
		toIntersect['y'],
		toIntersect['width'],
		toIntersect['height'],
		output
	);
};

/**
 * Determines whether the object specified in the toIntersect parameter 
 * intersects with this Rectangle object.
 *
 * @param {rune.geom.Rectangle} toIntersect The Rectangle object to compare against this Rectangle object.
 *
 * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
 */
rune.geom.Rectangle.prototype.intersects = function(toIntersect) {
	return rune.geom.Rectangle.intersects(
		this['x'],
		this['y'],
		this['width'],
		this['height'],
		toIntersect['x'],
		toIntersect['y'],
		toIntersect['width'],
		toIntersect['height']
	);
};