mr-crocs-adventures/js/geometry/GeometryRect.js
2020-01-25 13:11:25 +01:00

268 lines
7.3 KiB
JavaScript

import GeometryPoint from "./GeometryPoint.js";
import GeometryStroke from "./GeometryStroke.js";
import GeometryPointCollection from "./GeometryPointCollection.js";
export default class GeometryRect
{
/**
* @param x: float
* @param y: float
* @param width: float
* @param height: float
*/
constructor(x, y, width, height)
{
this.position = new GeometryPoint(x, y);
this.width = width;
this.height = height;
}
/**
* Returns if the given point is inside this rect.
*
* @param geometryPoint
* @returns {boolean|boolean}
*/
isContainingPoint(geometryPoint)
{
let containsHorizontally = geometryPoint.x >= this.position.x && geometryPoint.x < this.position.x + this.width;
let containsVertically = geometryPoint.y >= this.position.y && geometryPoint.y < this.position.y + this.height;
return containsHorizontally && containsVertically;
}
isEqual(rect)
{
return rect.x === this.x && rect.y === this.y && rect.width === this.width && rect.height === this.height;
}
hasIntersectionWithRect(rect)
{
return this.getBorderIntersectonsWithRect(rect).getLength() > 0;
}
getBorderTop()
{
return new GeometryStroke(
new GeometryPoint(this.position.x, this.position.y),
new GeometryPoint(this.position.x + this.width, this.position.y)
);
}
getBorderLeft()
{
return new GeometryStroke(
new GeometryPoint(this.position.x, this.position.y),
new GeometryPoint(this.position.x, this.position.y + this.height)
);
}
getBorderRight()
{
return new GeometryStroke(
new GeometryPoint(this.position.x + this.width, this.position.y),
new GeometryPoint(this.position.x + this.width, this.position.y + this.height)
);
}
getBorderBottom() {
return new GeometryStroke(
new GeometryPoint(this.position.x, this.position.y + this.height),
new GeometryPoint(this.position.x + this.width, this.position.y + this.height)
);
}
/**
* Returns all intersection points between this rect and a line.
*
* @param geometryLine
* @returns {GeometryPointCollection}
*/
getBorderIntersectionsWithLine(geometryLine)
{
let borders = [
this.getBorderTop(),
this.getBorderLeft(),
this.getBorderRight(),
this.getBorderBottom()
];
let intersections = new GeometryPointCollection();
borders.forEach(
(border) => {
let intersection = border.getIntersectionWithLine(geometryLine);
if (intersection !== null && this.isContainingPoint(intersection)) {
intersections.addGeometryPoint(intersection);
}
}
);
return intersections;
}
/**
* Returns the intersection points between the border lines and the given stroke.
*
* @param stroke
* @returns {GeometryPointCollection}
*/
getBorderIntersectionsWithStroke(stroke)
{
let borders = [
this.getBorderTop(),
this.getBorderLeft(),
this.getBorderRight(),
this.getBorderBottom()
];
let intersections = new GeometryPointCollection();
borders.forEach(
(border) => {
let intersection = border.getIntersectionWithStroke(stroke);
if (intersection !== null && this.isContainingPoint(intersection)) {
intersections.addGeometryPoint(intersection);
}
}
);
return intersections;
}
/**
* Get all intersections between this and another rect as point collection.
*
* @param rect GeometryRect
* @returns {GeometryPointCollection}
*/
getBorderIntersectonsWithRect(rect)
{
let intersections = new GeometryPointCollection();
let strokes = [
rect.getBorderTop(),
rect.getBorderLeft(),
rect.getBorderRight(),
rect.getBorderBottom(),
];
strokes.forEach(
(stroke) => {
this.getBorderIntersectionsWithStroke(stroke).forEach(
(point) => {
intersections.addGeometryPoint(point);
}
)
}
);
return intersections;
}
/**
* Returns the four points that define the edges of this rect.
*
* @returns {GeometryPointCollection}
*/
getRectanglePoints()
{
let collection = new GeometryPointCollection();
collection.addGeometryPoint(this.position);
collection.addGeometryPoint(new GeometryPoint(this.position.x + this.width, this.position.y));
collection.addGeometryPoint(new GeometryPoint(this.position.x, this.position.y + this.height - 1));
collection.addGeometryPoint(new GeometryPoint(this.position.x + this.width, this.position.y + this.height - 1));
return collection;
}
/**
* Returns the intersection area between this and another rect as new rect or null.
*
* @param rect GeometryRect
* @returns {null|GeometryRect}
*/
getRectIntersection(rect)
{
let distanceToOrigin = this.getCenter().getDistanceToPoint(rect.getCenter());
if (distanceToOrigin > this.getDiagonal() * 0.5 + rect.getDiagonal() * 0.5) {
return null;
}
let intersectionPoints = new GeometryPointCollection();
this.getRectanglePoints().forEach(
(point) => {
if (rect.isContainingPoint(point)) {
intersectionPoints.addGeometryPoint(point);
}
}
);
if (intersectionPoints.getLength() >= 4) {
return intersectionPoints.getRect();
}
rect.getRectanglePoints().forEach(
(point) => {
if (this.isContainingPoint(point)) {
intersectionPoints.addGeometryPoint(point);
}
}
);
if (intersectionPoints.getLength() >= 4) {
return intersectionPoints.getRect();
}
this.getBorderIntersectonsWithRect(rect).forEach(
(point) => {
intersectionPoints.addGeometryPoint(point);
}
);
if (intersectionPoints.getLength() >= 2) {
return intersectionPoints.getRect();
}
return null;
}
getCenter()
{
return new GeometryPoint(
this.position.x + this.width * 0.5,
this.position.y + this.height * 0.5
);
}
getDiagonal()
{
return new GeometryStroke(
this.position,
new GeometryPoint(this.position.x + this.width, this.position.y + this.height)
);
}
/**
* Visualizes the rect.
*
* @param context Context
* @param color string
*/
draw(context, color = 'red')
{
context.fillStyle = color;
context.fillRect(this.position.x, this.position.y, this.width, this.height);
this.getBorderTop().draw(context);
this.getBorderLeft().draw(context);
this.getBorderRight().draw(context);
this.getBorderBottom().draw(context);
}
}