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 }