View Javadoc

    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
    19  import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
    20  import org.apache.commons.numbers.core.Precision;
    21
    22  /** Base class representing an axis-aligned bounding box with minimum and maximum bounding points.
    23   * @param <P> Point implementation type
    24   * @param <B> Bounds implementation type
    25   */
    26  public abstract class AbstractBounds<
    27      P extends EuclideanVector<P>,
    28      B extends AbstractBounds<P, B>> {
    29
    30      /** Minimum point. */
    31      private final P min;
    32
    33      /** Maximum point. */
    34      private final P max;
    35
    36      /** Simple constructor. Callers are responsible for ensuring that all coordinate values are finite and
    37       * that all values in {@code min} are less than or equal to their corresponding values in {@code max}.
    38       * No validation is performed.
    39       * @param min minimum point
    40       * @param max maximum point
    41       */
    42      protected AbstractBounds(final P min, final P max) {
    43          this.min = min;
    44          this.max = max;
    45      }
    46
    47      /** Get the minimum point.
    48       * @return the minimum point
    49       */
    50      public P getMin() {
    51          return min;
    52      }
    53
    54      /** Get the maximum point.
    55       * @return the maximum point
    56       */
    57      public P getMax() {
    58          return max;
    59      }
    60
    61      /** Get the diagonal of the bounding box. The return value is a vector pointing from
    62       * {@code min} to {@code max} and contains the size of the box along each coordinate axis.
    63       * @return the diagonal vector of the bounding box
    64       */
    65      public P getDiagonal() {
    66          return min.vectorTo(max);
    67      }
    68
    69      /** Get the centroid, or geometric center, of the bounding box.
    70       * @return the centroid of the bounding box
    71       */
    72      public P getCentroid() {
    73          return min.lerp(max, 0.5);
    74      }
    75
    76      /** Return true if the bounding box has non-zero size along each coordinate axis, as
    77       * evaluated by the given precision context.
    78       * @param precision precision context used for floating point comparisons
    79       * @return true if the bounding box has non-zero size along each coordinate axis
    80       */
    81      public abstract boolean hasSize(Precision.DoubleEquivalence precision);
    82
    83      /** Return true if the given point is strictly within or on the boundary of the bounding box.
    84       * In other words, true if returned if <code>p<sub>t</sub> &gt;= min<sub>t</sub></code> and
    85       * <code>p<sub>t</sub> &lt;= max<sub>t</sub></code> for each coordinate value <code>t</code>.
    86       * Floating point comparisons are strict; values are considered equal only if they match exactly.
    87       * @param pt the point to check
    88       * @return true if the given point is strictly within or on the boundary of the instance
    89       * @see #contains(EuclideanVector, Precision.DoubleEquivalence)
    90       */
    91      public abstract boolean contains(P pt);
    92
    93      /** Return true if the given point is within or on the boundary of the bounding box, using the given
    94       * precision context for floating point comparisons. This is similar to {@link #contains(EuclideanVector)}
    95       * but allows points that may be strictly outside of the box due to floating point errors to be considered
    96       * inside.
    97       * @param pt the point to check
    98       * @param precision precision context used to compare floating point values
    99       * @return if the given point is within or on the boundary of the bounds, as determined
    100      *      by the given precision context
    101      * @see #contains(EuclideanVector, Precision.DoubleEquivalence)
    102      */
    103     public abstract boolean contains(P pt, Precision.DoubleEquivalence precision);
    104
    105     /** Return true if any point on the interior or boundary of this instance is also considered to be
    106      * on the interior or boundary of the argument. Specifically, true is returned if
    107      * <code>aMin<sub>t</sub> &lt;= bMax<sub>t</sub></code> and <code>aMax<sub>t</sub> &gt;= bMin<sub>t</sub></code>
    108      * for all coordinate values {@code t}, where {@code a} is the current instance and {@code b} is the argument.
    109      * Floating point comparisons are strict; values are considered equal only if they match exactly.
    110      * @param other bounding box to intersect with
    111      * @return true if the bounds intersect
    112      */
    113     public abstract boolean intersects(B other);
    114
    115     /** Return the intersection of this bounding box and the argument, or null if no intersection exists.
    116      * Floating point comparisons are strict; values are considered equal only if they match exactly. Note
    117      * this this method may return bounding boxes with zero size in one or more coordinate axes.
    118      * @param other bounding box to intersect with
    119      * @return the intersection of this instance and the argument, or null if no such intersection
    120      *      exists
    121      * @see #intersects(AbstractBounds)
    122      */
    123     public abstract B intersection(B other);
    124
    125     /** Return a hyperplane-bounded region containing the same points as this instance.
    126      * @param precision precision context used for floating point comparisons in the returned
    127      *      region instance
    128      * @return a hyperplane-bounded region containing the same points as this instance
    129      */
    130     public abstract HyperplaneBoundedRegion<P> toRegion(Precision.DoubleEquivalence precision);
    131
    132     /** Return true if the current instance and argument are considered equal as evaluated by the
    133      * given precision context. Bounds are considered equal if they contain equivalent min and max
    134      * points.
    135      * @param other bounds to compare with
    136      * @param precision precision context to compare floating point numbers
    137      * @return true if this instance is equivalent to the argument, as evaluated by the given
    138      *      precision context
    139      * @see EuclideanVector#eq(EuclideanVector, Precision.DoubleEquivalence)
    140      */
    141     public boolean eq(final B other, final Precision.DoubleEquivalence precision) {
    142         return min.eq(other.getMin(), precision) &&
    143                 max.eq(other.getMax(), precision);
    144     }
    145
    146     /** {@inheritDoc} */
    147     @Override
    148     public String toString() {
    149         final StringBuilder sb = new StringBuilder();
    150         sb.append(getClass().getSimpleName())
    151             .append("[min= ")
    152             .append(min)
    153             .append(", max= ")
    154             .append(max)
    155             .append(']');
    156
    157         return sb.toString();
    158     }
    159 }