184 lines
4.0 KiB
TypeScript
184 lines
4.0 KiB
TypeScript
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<Point>): 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)
|
|
}
|
|
};
|