Source: tiny/core/display/Bounds.js

import { Rectangle } from '../math';

/**
 * 'Builder' pattern for bounds rectangles Axis-Aligned Bounding Box (AABB)
 * It is not a shape! Its mutable thing, no 'EMPTY' or that kind of problems
 *
 * ![](https://gw.alipayobjects.com/zos/rmsportal/ucuoeWFkoIIcBWmZzPdB.png) ![](https://gw.alipayobjects.com/zos/rmsportal/BzkyQOytsRkOsAWgXIXx.png) ![](https://gw.alipayobjects.com/zos/rmsportal/xcTgDmINQgnQgPPlUweI.png)
 *
 * @class
 * @memberof Tiny
 */
export default class Bounds {
  /**
   *
   */
  constructor() {
    /**
     * @member {number}
     * @default 0
     */
    this.minX = Infinity;

    /**
     * @member {number}
     * @default 0
     */
    this.minY = Infinity;

    /**
     * @member {number}
     * @default 0
     */
    this.maxX = -Infinity;

    /**
     * @member {number}
     * @default 0
     */
    this.maxY = -Infinity;

    this.rect = null;

    /**
     * It is updated to _boundsID of corresponding object to keep bounds in sync with content.
     * Updated from outside, thus public modifier.
     *
     * @member {number}
     * @public
     */
    this.updateID = -1;
  }

  /**
   * Checks if bounds are empty.
   *
   * @return {boolean} True if empty.
   */
  isEmpty() {
    return this.minX > this.maxX || this.minY > this.maxY;
  }

  /**
   * Clears the bounds and resets.
   *
   */
  clear() {
    this.minX = Infinity;
    this.minY = Infinity;
    this.maxX = -Infinity;
    this.maxY = -Infinity;
  }

  /**
   * Can return Rectangle.EMPTY constant, either construct new rectangle, either use your rectangle
   * It is not guaranteed that it will return tempRect
   *
   * @param {Tiny.Rectangle} rect - temporary object will be used if AABB is not empty
   * @return {Tiny.Rectangle} A rectangle of the bounds
   */
  getRectangle(rect) {
    if (this.minX > this.maxX || this.minY > this.maxY) {
      return Rectangle.EMPTY;
    }

    rect = rect || new Rectangle(0, 0, 1, 1);

    rect.x = this.minX;
    rect.y = this.minY;
    rect.width = this.maxX - this.minX;
    rect.height = this.maxY - this.minY;

    return rect;
  }

  /**
   * This function should be inlined when its possible.
   *
   * @param {Tiny.Point} point - The point to add.
   */
  addPoint(point) {
    this.minX = Math.min(this.minX, point.x);
    this.maxX = Math.max(this.maxX, point.x);
    this.minY = Math.min(this.minY, point.y);
    this.maxY = Math.max(this.maxY, point.y);
  }

  /**
   * Adds a quad, not transformed
   *
   * @param {Float32Array} vertices - The verts to add.
   */
  addQuad(vertices) {
    let minX = this.minX;
    let minY = this.minY;
    let maxX = this.maxX;
    let maxY = this.maxY;

    let x = vertices[0];
    let y = vertices[1];

    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = vertices[2];
    y = vertices[3];
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = vertices[4];
    y = vertices[5];
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = vertices[6];
    y = vertices[7];
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    this.minX = minX;
    this.minY = minY;
    this.maxX = maxX;
    this.maxY = maxY;
  }

  /**
   * Adds sprite frame, transformed.
   *
   * @param {Tiny.TransformBase} transform - TODO
   * @param {number} x0 - TODO
   * @param {number} y0 - TODO
   * @param {number} x1 - TODO
   * @param {number} y1 - TODO
   */
  addFrame(transform, x0, y0, x1, y1) {
    const matrix = transform.worldTransform;
    const a = matrix.a;
    const b = matrix.b;
    const c = matrix.c;
    const d = matrix.d;
    const tx = matrix.tx;
    const ty = matrix.ty;

    let minX = this.minX;
    let minY = this.minY;
    let maxX = this.maxX;
    let maxY = this.maxY;

    let x = (a * x0) + (c * y0) + tx;
    let y = (b * x0) + (d * y0) + ty;

    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = (a * x1) + (c * y0) + tx;
    y = (b * x1) + (d * y0) + ty;
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = (a * x0) + (c * y1) + tx;
    y = (b * x0) + (d * y1) + ty;
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    x = (a * x1) + (c * y1) + tx;
    y = (b * x1) + (d * y1) + ty;
    minX = x < minX ? x : minX;
    minY = y < minY ? y : minY;
    maxX = x > maxX ? x : maxX;
    maxY = y > maxY ? y : maxY;

    this.minX = minX;
    this.minY = minY;
    this.maxX = maxX;
    this.maxY = maxY;
  }

  /**
   * Add an array of vertices
   *
   * @param {Tiny.TransformBase} transform - TODO
   * @param {Float32Array} vertices - TODO
   * @param {number} beginOffset - TODO
   * @param {number} endOffset - TODO
   */
  addVertices(transform, vertices, beginOffset, endOffset) {
    const matrix = transform.worldTransform;
    const a = matrix.a;
    const b = matrix.b;
    const c = matrix.c;
    const d = matrix.d;
    const tx = matrix.tx;
    const ty = matrix.ty;

    let minX = this.minX;
    let minY = this.minY;
    let maxX = this.maxX;
    let maxY = this.maxY;

    for (let i = beginOffset; i < endOffset; i += 2) {
      const rawX = vertices[i];
      const rawY = vertices[i + 1];
      const x = (a * rawX) + (c * rawY) + tx;
      const y = (d * rawY) + (b * rawX) + ty;

      minX = x < minX ? x : minX;
      minY = y < minY ? y : minY;
      maxX = x > maxX ? x : maxX;
      maxY = y > maxY ? y : maxY;
    }

    this.minX = minX;
    this.minY = minY;
    this.maxX = maxX;
    this.maxY = maxY;
  }

  /**
   * Adds other Bounds
   *
   * @param {Tiny.Bounds} bounds - TODO
   */
  addBounds(bounds) {
    const minX = this.minX;
    const minY = this.minY;
    const maxX = this.maxX;
    const maxY = this.maxY;

    this.minX = bounds.minX < minX ? bounds.minX : minX;
    this.minY = bounds.minY < minY ? bounds.minY : minY;
    this.maxX = bounds.maxX > maxX ? bounds.maxX : maxX;
    this.maxY = bounds.maxY > maxY ? bounds.maxY : maxY;
  }

  /**
   * Adds other Bounds, masked with Bounds
   *
   * @param {Tiny.Bounds} bounds - TODO
   * @param {Tiny.Bounds} mask - TODO
   */
  addBoundsMask(bounds, mask) {
    const _minX = bounds.minX > mask.minX ? bounds.minX : mask.minX;
    const _minY = bounds.minY > mask.minY ? bounds.minY : mask.minY;
    const _maxX = bounds.maxX < mask.maxX ? bounds.maxX : mask.maxX;
    const _maxY = bounds.maxY < mask.maxY ? bounds.maxY : mask.maxY;

    if (_minX <= _maxX && _minY <= _maxY) {
      const minX = this.minX;
      const minY = this.minY;
      const maxX = this.maxX;
      const maxY = this.maxY;

      this.minX = _minX < minX ? _minX : minX;
      this.minY = _minY < minY ? _minY : minY;
      this.maxX = _maxX > maxX ? _maxX : maxX;
      this.maxY = _maxY > maxY ? _maxY : maxY;
    }
  }

  /**
   * Adds other Bounds, masked with Rectangle
   *
   * @param {Tiny.Bounds} bounds - TODO
   * @param {Tiny.Rectangle} area - TODO
   */
  addBoundsArea(bounds, area) {
    const _minX = bounds.minX > area.x ? bounds.minX : area.x;
    const _minY = bounds.minY > area.y ? bounds.minY : area.y;
    const _maxX = bounds.maxX < area.x + area.width ? bounds.maxX : (area.x + area.width);
    const _maxY = bounds.maxY < area.y + area.height ? bounds.maxY : (area.y + area.height);

    if (_minX <= _maxX && _minY <= _maxY) {
      const minX = this.minX;
      const minY = this.minY;
      const maxX = this.maxX;
      const maxY = this.maxY;

      this.minX = _minX < minX ? _minX : minX;
      this.minY = _minY < minY ? _minY : minY;
      this.maxX = _maxX > maxX ? _maxX : maxX;
      this.maxY = _maxY > maxY ? _maxY : maxY;
    }
  }
}
Documentation generated by JSDoc 3.4.3 on Fri Jul 09 2021 19:32:25 GMT+0800 (CST)