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 * A mutable axis-aligned rectangle. See [ImmutableBox] for an immutable 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 MutableBox private constructor(x1: Float, y1: Float, x2: Float, y2: Float) : Box() { 32 33 /** The lower bound in the `X` direction. */ 34 override var xMin: Float = min(x1, x2) 35 private set 36 37 /** The lower bound in the `Y` direction. */ 38 override var yMin: Float = min(y1, y2) 39 private set 40 41 /** The upper bound in the `X` direction. */ 42 override var xMax: Float = max(x1, x2) 43 private set 44 45 /** The upper bound in the `Y` direction. */ 46 override var yMax: Float = max(y1, y2) 47 private set 48 49 /** 50 * Sets the lower and upper bounds in the `X` direction to new values. The minimum value becomes 51 * `xMin`, and the maximum value becomes `xMax`. Returns the same instance to chain function 52 * calls. 53 */ setXBoundsnull54 public fun setXBounds(x1: Float, x2: Float): MutableBox { 55 xMin = min(x1, x2) 56 xMax = max(x1, x2) 57 return this 58 } 59 60 /** 61 * Sets the lower and upper bounds in the `Y` direction to new values. The minimum value becomes 62 * `yMin`, and the maximum value becomes `yMax`. Returns the same instance to chain function 63 * calls. 64 */ setYBoundsnull65 public fun setYBounds(y1: Float, y2: Float): MutableBox { 66 yMin = min(y1, y2) 67 yMax = max(y1, y2) 68 return this 69 } 70 71 /** 72 * Constructs a [MutableBox] without any initial data. Fill with the appropriate setters or 73 * factory functions. 74 */ 75 public constructor() : this(0f, 0f, 0f, 0f) 76 77 /** Constructs the smallest [MutableBox] containing the two given points. */ populateFromTwoPointsnull78 public fun populateFromTwoPoints(point1: Vec, point2: Vec): MutableBox { 79 setXBounds(point1.x, point2.x) 80 setYBounds(point1.y, point2.y) 81 return this 82 } 83 84 /** 85 * Constructs a [MutableBox] with a given [center], [width], and [height]. [width] and [height] 86 * must be non-negative numbers. 87 */ populateFromCenterAndDimensionsnull88 public fun populateFromCenterAndDimensions( 89 center: Vec, 90 @FloatRange(from = 0.0) width: Float, 91 @FloatRange(from = 0.0) height: Float, 92 ): MutableBox { 93 require(width >= 0f && height >= 0f) 94 setXBounds(center.x - width / 2, center.x + width / 2) 95 setYBounds(center.y - height / 2, center.y + height / 2) 96 return this 97 } 98 99 /** Fills this [MutableBox] with the same values contained in [input]. */ populateFromnull100 public fun populateFrom(input: Box): MutableBox { 101 xMin = input.xMin 102 yMin = input.yMin 103 xMax = input.xMax 104 yMax = input.yMax 105 return this 106 } 107 108 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) asImmutablenull109 override fun asImmutable(): ImmutableBox = 110 ImmutableBox(x1 = xMin, y1 = yMin, x2 = xMax, y2 = yMax) 111 112 override fun equals(other: Any?): Boolean = 113 other === this || (other is Box && Box.areEquivalent(this, other)) 114 115 // NOMUTANTS -- not testing exact hashCode values, just that equality implies same hashCode 116 override fun hashCode(): Int = Box.hash(this) 117 118 override fun toString(): String = "Mutable${Box.string(this)}" 119 } 120