All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.math.primitive.MutableAABB Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2014 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Chunky.  If not, see .
 */
package se.llbit.math.primitive;

import se.llbit.math.AABB;
import se.llbit.math.Ray;
import se.llbit.math.Vector3;

/**
 * Axis-Aligned Bounding Box. Does not compute intersection normals.
 *
 * @author Jesper Öqvist 
 */
public class MutableAABB implements Primitive {
  protected double xmin;
  protected double xmax;
  protected double ymin;
  protected double ymax;
  protected double zmin;
  protected double zmax;

  /**
   * Construct a new AABB with given bounds.
   */
  public MutableAABB(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) {

    this.xmin = xmin;
    this.xmax = xmax;
    this.ymin = ymin;
    this.ymax = ymax;
    this.zmin = zmin;
    this.zmax = zmax;
  }

  /**
   * Test if a ray intersects this AABB
   *
   * @return {@code true} if there is an intersection
   */
  public boolean hitTest(Ray ray) {
    double t1, t2;
    double tNear = Double.NEGATIVE_INFINITY;
    double tFar = Double.POSITIVE_INFINITY;
    Vector3 d = ray.d;
    Vector3 o = ray.o;

    if (d.x != 0) {
      double rx = 1 / d.x;
      t1 = (xmin - o.x) * rx;
      t2 = (xmax - o.x) * rx;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      tNear = t1;
      tFar = t2;
    }

    if (d.y != 0) {
      double ry = 1 / d.y;
      t1 = (ymin - o.y) * ry;
      t2 = (ymax - o.y) * ry;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      if (t1 > tNear) {
        tNear = t1;
      }
      if (t2 < tFar) {
        tFar = t2;
      }
    }

    if (d.z != 0) {
      double rz = 1 / d.z;
      t1 = (zmin - o.z) * rz;
      t2 = (zmax - o.z) * rz;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      if (t1 > tNear) {
        tNear = t1;
      }
      if (t2 < tFar) {
        tFar = t2;
      }
    }

    return tNear < tFar + Ray.EPSILON && tFar > 0;
  }

  @Override public boolean intersect(Ray ray) {
    double t1, t2;
    double tNear = Double.NEGATIVE_INFINITY;
    double tFar = Double.POSITIVE_INFINITY;
    Vector3 d = ray.d;
    Vector3 o = ray.o;

    if (d.x != 0) {
      double rx = 1 / d.x;
      t1 = (xmin - o.x) * rx;
      t2 = (xmax - o.x) * rx;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      tNear = t1;
      tFar = t2;
    }

    if (d.y != 0) {
      double ry = 1 / d.y;
      t1 = (ymin - o.y) * ry;
      t2 = (ymax - o.y) * ry;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      if (t1 > tNear) {
        tNear = t1;
      }
      if (t2 < tFar) {
        tFar = t2;
      }
    }

    if (d.z != 0) {
      double rz = 1 / d.z;
      t1 = (zmin - o.z) * rz;
      t2 = (zmax - o.z) * rz;

      if (t1 > t2) {
        double t = t1;
        t1 = t2;
        t2 = t;
      }

      if (t1 > tNear) {
        tNear = t1;
      }
      if (t2 < tFar) {
        tFar = t2;
      }
    }

    if (tNear < tFar + Ray.EPSILON && tNear >= 0 && tNear < ray.t) {
      ray.tNext = tNear;
      return true;
    } else {
      return false;
    }
  }

  /**
   * Expand this AABB to enclose the given AABB.
   */
  public void expand(AABB p) {
    if (p.xmin < xmin) {
      xmin = p.xmin;
    }
    if (p.xmax > xmax) {
      xmax = p.xmax;
    }
    if (p.ymin < ymin) {
      ymin = p.ymin;
    }
    if (p.ymax > ymax) {
      ymax = p.ymax;
    }
    if (p.zmin < zmin) {
      zmin = p.zmin;
    }
    if (p.zmax > zmax) {
      zmax = p.zmax;
    }
  }

  @Override public AABB bounds() {
    return new AABB(xmin, xmax, ymin, ymax, zmin, zmax);
  }

  @Override public String toString() {
    return String
        .format("[ %.2f, %.2f, %.2f, %.2f, %.2f, %.2f]", xmin, xmax, ymin, ymax, zmin, zmax);
  }

  /**
   * Test if point is inside the bounding box.
   *
   * @return true if p is inside this BB.
   */
  public boolean inside(Vector3 p) {
    return (p.x >= xmin && p.x <= xmax) &&
        (p.y >= ymin && p.y <= ymax) &&
        (p.z >= zmin && p.z <= zmax);
  }

  /**
   * @return surface area of the bounding box
   */
  public double surfaceArea() {
    double x = xmax - xmin;
    double y = ymax - ymin;
    double z = zmax - zmin;
    return 2 * (y * z + x * z * x * y);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy