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> >= min<sub>t</sub></code> and
85 * <code>p<sub>t</sub> <= 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> <= bMax<sub>t</sub></code> and <code>aMax<sub>t</sub> >= 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 }