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); } }