AbstractBounds.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.geometry.euclidean;

  18. import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
  19. import org.apache.commons.numbers.core.Precision;

  20. /** Base class representing an axis-aligned bounding box with minimum and maximum bounding points.
  21.  * @param <P> Point implementation type
  22.  * @param <B> Bounds implementation type
  23.  */
  24. public abstract class AbstractBounds<
  25.     P extends EuclideanVector<P>,
  26.     B extends AbstractBounds<P, B>> {

  27.     /** Minimum point. */
  28.     private final P min;

  29.     /** Maximum point. */
  30.     private final P max;

  31.     /** Simple constructor. Callers are responsible for ensuring that all coordinate values are finite and
  32.      * that all values in {@code min} are less than or equal to their corresponding values in {@code max}.
  33.      * No validation is performed.
  34.      * @param min minimum point
  35.      * @param max maximum point
  36.      */
  37.     protected AbstractBounds(final P min, final P max) {
  38.         this.min = min;
  39.         this.max = max;
  40.     }

  41.     /** Get the minimum point.
  42.      * @return the minimum point
  43.      */
  44.     public P getMin() {
  45.         return min;
  46.     }

  47.     /** Get the maximum point.
  48.      * @return the maximum point
  49.      */
  50.     public P getMax() {
  51.         return max;
  52.     }

  53.     /** Get the diagonal of the bounding box. The return value is a vector pointing from
  54.      * {@code min} to {@code max} and contains the size of the box along each coordinate axis.
  55.      * @return the diagonal vector of the bounding box
  56.      */
  57.     public P getDiagonal() {
  58.         return min.vectorTo(max);
  59.     }

  60.     /** Get the centroid, or geometric center, of the bounding box.
  61.      * @return the centroid of the bounding box
  62.      */
  63.     public P getCentroid() {
  64.         return min.lerp(max, 0.5);
  65.     }

  66.     /** Return true if the bounding box has non-zero size along each coordinate axis, as
  67.      * evaluated by the given precision context.
  68.      * @param precision precision context used for floating point comparisons
  69.      * @return true if the bounding box has non-zero size along each coordinate axis
  70.      */
  71.     public abstract boolean hasSize(Precision.DoubleEquivalence precision);

  72.     /** Return true if the given point is strictly within or on the boundary of the bounding box.
  73.      * In other words, true if returned if <code>p<sub>t</sub> &gt;= min<sub>t</sub></code> and
  74.      * <code>p<sub>t</sub> &lt;= max<sub>t</sub></code> for each coordinate value <code>t</code>.
  75.      * Floating point comparisons are strict; values are considered equal only if they match exactly.
  76.      * @param pt the point to check
  77.      * @return true if the given point is strictly within or on the boundary of the instance
  78.      * @see #contains(EuclideanVector, Precision.DoubleEquivalence)
  79.      */
  80.     public abstract boolean contains(P pt);

  81.     /** Return true if the given point is within or on the boundary of the bounding box, using the given
  82.      * precision context for floating point comparisons. This is similar to {@link #contains(EuclideanVector)}
  83.      * but allows points that may be strictly outside of the box due to floating point errors to be considered
  84.      * inside.
  85.      * @param pt the point to check
  86.      * @param precision precision context used to compare floating point values
  87.      * @return if the given point is within or on the boundary of the bounds, as determined
  88.      *      by the given precision context
  89.      * @see #contains(EuclideanVector, Precision.DoubleEquivalence)
  90.      */
  91.     public abstract boolean contains(P pt, Precision.DoubleEquivalence precision);

  92.     /** Return true if any point on the interior or boundary of this instance is also considered to be
  93.      * on the interior or boundary of the argument. Specifically, true is returned if
  94.      * <code>aMin<sub>t</sub> &lt;= bMax<sub>t</sub></code> and <code>aMax<sub>t</sub> &gt;= bMin<sub>t</sub></code>
  95.      * for all coordinate values {@code t}, where {@code a} is the current instance and {@code b} is the argument.
  96.      * Floating point comparisons are strict; values are considered equal only if they match exactly.
  97.      * @param other bounding box to intersect with
  98.      * @return true if the bounds intersect
  99.      */
  100.     public abstract boolean intersects(B other);

  101.     /** Return the intersection of this bounding box and the argument, or null if no intersection exists.
  102.      * Floating point comparisons are strict; values are considered equal only if they match exactly. Note
  103.      * this this method may return bounding boxes with zero size in one or more coordinate axes.
  104.      * @param other bounding box to intersect with
  105.      * @return the intersection of this instance and the argument, or null if no such intersection
  106.      *      exists
  107.      * @see #intersects(AbstractBounds)
  108.      */
  109.     public abstract B intersection(B other);

  110.     /** Return a hyperplane-bounded region containing the same points as this instance.
  111.      * @param precision precision context used for floating point comparisons in the returned
  112.      *      region instance
  113.      * @return a hyperplane-bounded region containing the same points as this instance
  114.      */
  115.     public abstract HyperplaneBoundedRegion<P> toRegion(Precision.DoubleEquivalence precision);

  116.     /** Return true if the current instance and argument are considered equal as evaluated by the
  117.      * given precision context. Bounds are considered equal if they contain equivalent min and max
  118.      * points.
  119.      * @param other bounds to compare with
  120.      * @param precision precision context to compare floating point numbers
  121.      * @return true if this instance is equivalent to the argument, as evaluated by the given
  122.      *      precision context
  123.      * @see EuclideanVector#eq(EuclideanVector, Precision.DoubleEquivalence)
  124.      */
  125.     public boolean eq(final B other, final Precision.DoubleEquivalence precision) {
  126.         return min.eq(other.getMin(), precision) &&
  127.                 max.eq(other.getMax(), precision);
  128.     }

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     public String toString() {
  132.         final StringBuilder sb = new StringBuilder();
  133.         sb.append(getClass().getSimpleName())
  134.             .append("[min= ")
  135.             .append(min)
  136.             .append(", max= ")
  137.             .append(max)
  138.             .append(']');

  139.         return sb.toString();
  140.     }
  141. }