1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.ink.geometry
18 
19 import androidx.annotation.FloatRange
20 import androidx.annotation.RestrictTo
21 import kotlin.math.max
22 import kotlin.math.min
23 
24 /**
25  * An immutable axis-aligned rectangle. See [MutableBox] for a mutable version.
26  *
27  * Note that unlike [android.graphics.RectF], this does not express an opinion about axis direction
28  * (e.g. the positive `Y` axis being "down"), because it is intended to be used with any coordinate
29  * system rather than just Android screen/View space.
30  */
31 public class ImmutableBox internal constructor(x1: Float, y1: Float, x2: Float, y2: Float) : Box() {
32 
33     /** The lower bound in the `X` direction. */
34     override val xMin: Float = min(x1, x2)
35 
36     /** The lower bound in the `Y` direction. */
37     override val yMin: Float = min(y1, y2)
38 
39     /** The upper bound in the `X` direction. */
40     override val xMax: Float = max(x1, x2)
41 
42     /** The upper bound in the `Y` direction. */
43     override val yMax: Float = max(y1, y2)
44 
asImmutablenull45     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) override fun asImmutable(): ImmutableBox = this
46 
47     override fun equals(other: Any?): Boolean =
48         other === this || (other is Box && Box.areEquivalent(this, other))
49 
50     // NOMUTANTS -- not testing exact hashCode values, just that equality implies same hashCode
51     override fun hashCode(): Int = Box.hash(this)
52 
53     override fun toString(): String = "Immutable${Box.string(this)}"
54 
55     public companion object {
56         /** Constructs an [ImmutableBox] with a given [center], [width], and [height]. */
57         @JvmStatic
58         public fun fromCenterAndDimensions(
59             center: Vec,
60             @FloatRange(from = 0.0) width: Float,
61             @FloatRange(from = 0.0) height: Float,
62         ): ImmutableBox {
63             require(width >= 0f && height >= 0f)
64             return ImmutableBox(
65                 center.x - width / 2,
66                 center.y - height / 2,
67                 center.x + width / 2,
68                 center.y + height / 2,
69             )
70         }
71 
72         /** Constructs the smallest [ImmutableBox] containing the two given points. */
73         @JvmStatic
74         public fun fromTwoPoints(point1: Vec, point2: Vec): ImmutableBox {
75             return ImmutableBox(point1.x, point1.y, point2.x, point2.y)
76         }
77     }
78 }
79