import { Vector2 } from './Vector2.js' import type { Point } from './Point.js' export class Box2 { min: Vector2 max: Vector2 constructor(min = new Vector2(+Number.POSITIVE_INFINITY, +Number.POSITIVE_INFINITY), max = new Vector2(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)) { this.min = min this.max = max } /** 获取面积 */ get area(): number { return (this.max.x - this.min.x) * (this.max.y - this.min.y) } /** */ set(min: Vector2, max: Vector2): Box2 { this.min.copy(min) this.max.copy(max) return this } setFromPoints(points: Iterable): Box2 { this.makeEmpty() for (let p of points) { this.expandByPoint(p) } return this } private static _setFromCenterAndSize_v1 = new Vector2() setFromCenterAndSize(center: Vector2, size: Vector2): Box2 { const v1 = Box2._setFromCenterAndSize_v1 const halfSize = v1.copy(size).multiplyScalar(0.5) this.min.copy(center).sub(halfSize) this.max.copy(center).add(halfSize) return this } clone(): Box2 { return new (this.constructor as any)().copy(this) } copy(box: Box2): Box2 { this.min.copy(box.min) this.max.copy(box.max) return this } makeEmpty(): Box2 { this.min.x = this.min.y = +Number.POSITIVE_INFINITY this.max.x = this.max.y = Number.NEGATIVE_INFINITY return this } isEmpty(): boolean { // this is a more robust check for empty than (volume <= 0) because volume can get positive with two negative axes return (this.max.x < this.min.x) || (this.max.y < this.min.y) } getCenter(result: Vector2 = new Vector2()): Vector2 { return this.isEmpty() ? result.set(0, 0) : result.addVectors(this.min, this.max).multiplyScalar(0.5) } getSize(result: Vector2 = new Vector2()): Vector2 { return this.isEmpty() ? result.set(0, 0) : result.subVectors(this.max, this.min) } expandByPoint(point: Point): Box2 { this.min.min(point) this.max.max(point) return this } expandByVector(vector: Vector2): Box2 { this.min.sub(vector) this.max.add(vector) return this } expandByScalar(scalar: number): Box2 { this.min.addScalar(-scalar) this.max.addScalar(scalar) return this } containsPoint(point: Vector2): boolean { if (point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y) { return false } return true } containsBox(box: Box2): boolean { if ((this.min.x <= box.min.x) && (box.max.x <= this.max.x) && (this.min.y <= box.min.y) && (box.max.y <= this.max.y)) { return true } return false } getParameter(point: Vector2, result: Vector2 = new Vector2()): Vector2 { // This can potentially have a divide by zero if the box // has a size dimension of 0. return result.set( (point.x - this.min.x) / (this.max.x - this.min.x), (point.y - this.min.y) / (this.max.y - this.min.y), ) } intersectsBox(box: Box2): boolean { // using 6 splitting planes to rule out intersections. if (box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y) { return false } return true } clampPoint(point: Vector2, result: Vector2 = new Vector2()): Vector2 { return result.copy(point).clamp(this.min, this.max) } private static _distanceToPoint_v1 = new Vector2() distanceToPoint(point: Vector2): number { const v1 = Box2._distanceToPoint_v1 const clampedPoint = v1.copy(point).clamp(this.min, this.max) return clampedPoint.sub(point).length() } intersect(box: Box2): Box2 { this.min.max(box.min) this.max.min(box.max) return this } union(box: Box2): Box2 { this.min.min(box.min) this.max.max(box.max) return this } translate(offset: Point): Box2 { this.min.add(offset) this.max.add(offset) return this } equals(box: Box2): boolean { return box.min.equals(this.min) && box.max.equals(this.max) } };