Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2017 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 @file:Suppress("NOTHING_TO_INLINE")
     18 
     19 package androidx.core.graphics
     20 
     21 import android.annotation.SuppressLint
     22 import android.graphics.Matrix
     23 import android.graphics.Point
     24 import android.graphics.PointF
     25 import android.graphics.Rect
     26 import android.graphics.RectF
     27 import android.graphics.Region
     28 
     29 /**
     30  * Returns "left", the first component of the rectangle.
     31  *
     32  * This method allows to use destructuring declarations when working with rectangles,
     33  * for example:
     34  * ```
     35  * val (left, top, right, bottom) = myRectangle
     36  * ```
     37  */
     38 inline operator fun Rect.component1() = this.left
     39 
     40 /**
     41  * Returns "top", the second component of the rectangle.
     42  *
     43  * This method allows to use destructuring declarations when working with rectangles,
     44  * for example:
     45  * ```
     46  * val (left, top, right, bottom) = myRectangle
     47  * ```
     48  */
     49 inline operator fun Rect.component2() = this.top
     50 
     51 /**
     52  * Returns "right", the third component of the rectangle.
     53  *
     54  * This method allows to use destructuring declarations when working with rectangles,
     55  * for example:
     56  * ```
     57  * val (left, top, right, bottom) = myRectangle
     58  * ```
     59  */
     60 inline operator fun Rect.component3() = this.right
     61 
     62 /**
     63  * Returns "bottom", the fourth component of the rectangle.
     64  *
     65  * This method allows to use destructuring declarations when working with rectangles,
     66  * for example:
     67  * ```
     68  * val (left, top, right, bottom) = myRectangle
     69  * ```
     70  */
     71 inline operator fun Rect.component4() = this.bottom
     72 
     73 /**
     74  * Returns "left", the first component of the rectangle.
     75  *
     76  * This method allows to use destructuring declarations when working with rectangles,
     77  * for example:
     78  * ```
     79  * val (left, top, right, bottom) = myRectangle
     80  * ```
     81  */
     82 inline operator fun RectF.component1() = this.left
     83 
     84 /**
     85  * Returns "top", the second component of the rectangle.
     86  *
     87  * This method allows to use destructuring declarations when working with rectangles,
     88  * for example:
     89  * ```
     90  * val (left, top, right, bottom) = myRectangle
     91  * ```
     92  */
     93 inline operator fun RectF.component2() = this.top
     94 
     95 /**
     96  * Returns "right", the third component of the rectangle.
     97  *
     98  * This method allows to use destructuring declarations when working with rectangles,
     99  * for example:
    100  * ```
    101  * val (left, top, right, bottom) = myRectangle
    102  * ```
    103  */
    104 inline operator fun RectF.component3() = this.right
    105 
    106 /**
    107  * Returns "bottom", the fourth component of the rectangle.
    108  *
    109  * This method allows to use destructuring declarations when working with rectangles,
    110  * for example:
    111  * ```
    112  * val (left, top, right, bottom) = myRectangle
    113  * ```
    114  */
    115 inline operator fun RectF.component4() = this.bottom
    116 
    117 /**
    118  * Performs the union of this rectangle and the specified rectangle and returns
    119  * the result as a new rectangle.
    120  */
    121 inline operator fun Rect.plus(r: Rect): Rect {
    122     return Rect(this).apply {
    123         union(r)
    124     }
    125 }
    126 
    127 /**
    128  * Performs the union of this rectangle and the specified rectangle and returns
    129  * the result as a new rectangle.
    130  */
    131 inline operator fun RectF.plus(r: RectF): RectF {
    132     return RectF(this).apply {
    133         union(r)
    134     }
    135 }
    136 
    137 /**
    138  * Returns a new rectangle representing this rectangle offset by the specified
    139  * amount on both X and Y axis.
    140  */
    141 inline operator fun Rect.plus(xy: Int): Rect {
    142     return Rect(this).apply {
    143         offset(xy, xy)
    144     }
    145 }
    146 
    147 /**
    148  * Returns a new rectangle representing this rectangle offset by the specified
    149  * amount on both X and Y axis.
    150  */
    151 inline operator fun RectF.plus(xy: Float): RectF {
    152     return RectF(this).apply {
    153         offset(xy, xy)
    154     }
    155 }
    156 
    157 /**
    158  * Returns a new rectangle representing this rectangle offset by the specified
    159  * point.
    160  */
    161 inline operator fun Rect.plus(xy: Point): Rect {
    162     return Rect(this).apply {
    163         offset(xy.x, xy.y)
    164     }
    165 }
    166 
    167 /**
    168  * Returns a new rectangle representing this rectangle offset by the specified
    169  * point.
    170  */
    171 inline operator fun RectF.plus(xy: PointF): RectF {
    172     return RectF(this).apply {
    173         offset(xy.x, xy.y)
    174     }
    175 }
    176 
    177 /**
    178  * Returns the difference of this rectangle and the specified rectangle as a new region.
    179  */
    180 inline operator fun Rect.minus(r: Rect): Region {
    181     return Region(this).apply {
    182         op(r, Region.Op.DIFFERENCE)
    183     }
    184 }
    185 
    186 /**
    187  * Returns the difference of this rectangle and the specified rectangle as a new region.
    188  * This rectangle is first converted to a [Rect] using [RectF.toRect].
    189  */
    190 inline operator fun RectF.minus(r: RectF): Region {
    191     return Region(this.toRect()).apply {
    192         op(r.toRect(), Region.Op.DIFFERENCE)
    193     }
    194 }
    195 
    196 /**
    197  * Returns a new rectangle representing this rectangle offset by the negation
    198  * of the specified amount on both X and Y axis.
    199  */
    200 inline operator fun Rect.minus(xy: Int): Rect {
    201     return Rect(this).apply {
    202         offset(-xy, -xy)
    203     }
    204 }
    205 
    206 /**
    207  * Returns a new rectangle representing this rectangle offset by the negation
    208  * of the specified amount on both X and Y axis.
    209  */
    210 inline operator fun RectF.minus(xy: Float): RectF {
    211     return RectF(this).apply {
    212         offset(-xy, -xy)
    213     }
    214 }
    215 
    216 /**
    217  * Returns a new rectangle representing this rectangle offset by the negation of
    218  * the specified point.
    219  */
    220 inline operator fun Rect.minus(xy: Point): Rect {
    221     return Rect(this).apply {
    222         offset(-xy.x, -xy.y)
    223     }
    224 }
    225 
    226 /**
    227  * Returns a new rectangle representing this rectangle offset by the negation of
    228  * the specified point.
    229  */
    230 inline operator fun RectF.minus(xy: PointF): RectF {
    231     return RectF(this).apply {
    232         offset(-xy.x, -xy.y)
    233     }
    234 }
    235 
    236 /**
    237  * Returns the union of two rectangles as a new rectangle.
    238  */
    239 inline infix fun Rect.and(r: Rect) = this + r
    240 
    241 /**
    242  * Returns the union of two rectangles as a new rectangle.
    243  */
    244 inline infix fun RectF.and(r: RectF) = this + r
    245 
    246 /**
    247  * Returns the intersection of two rectangles as a new rectangle.
    248  * If the rectangles do not intersect, returns a copy of the left hand side
    249  * rectangle.
    250  */
    251 @SuppressLint("CheckResult")
    252 inline infix fun Rect.or(r: Rect): Rect {
    253     return Rect(this).apply {
    254         intersect(r)
    255     }
    256 }
    257 
    258 /**
    259  * Returns the intersection of two rectangles as a new rectangle.
    260  * If the rectangles do not intersect, returns a copy of the left hand side
    261  * rectangle.
    262  */
    263 @SuppressLint("CheckResult")
    264 inline infix fun RectF.or(r: RectF): RectF {
    265     return RectF(this).apply {
    266         intersect(r)
    267     }
    268 }
    269 
    270 /**
    271  * Returns the union minus the intersection of two rectangles as a new region.
    272  */
    273 inline infix fun Rect.xor(r: Rect): Region {
    274     return Region(this).apply {
    275         op(r, Region.Op.XOR)
    276     }
    277 }
    278 
    279 /**
    280  * Returns the union minus the intersection of two rectangles as a new region.
    281  * The two rectangles are first converted to [Rect] using [RectF.toRect].
    282  */
    283 inline infix fun RectF.xor(r: RectF): Region {
    284     return Region(this.toRect()).apply {
    285         op(r.toRect(), Region.Op.XOR)
    286     }
    287 }
    288 
    289 /**
    290  * Returns true if the specified point is inside the rectangle.
    291  * The left and top are considered to be inside, while the right and bottom are not.
    292  * This means that for a point to be contained: left <= x < right and top <= y < bottom.
    293  * An empty rectangle never contains any point.
    294  */
    295 inline operator fun Rect.contains(p: Point) = contains(p.x, p.y)
    296 
    297 /**
    298  * Returns true if the specified point is inside the rectangle.
    299  * The left and top are considered to be inside, while the right and bottom are not.
    300  * This means that for a point to be contained: left <= x < right and top <= y < bottom.
    301  * An empty rectangle never contains any point.
    302  */
    303 inline operator fun RectF.contains(p: PointF) = contains(p.x, p.y)
    304 
    305 /**
    306  * Returns a [RectF] representation of this rectangle.
    307  */
    308 inline fun Rect.toRectF(): RectF = RectF(this)
    309 
    310 /**
    311  * Returns a [Rect] representation of this rectangle. The resulting rect will be sized such
    312  * that this rect can fit within it.
    313  */
    314 inline fun RectF.toRect(): Rect {
    315     val r = Rect()
    316     roundOut(r)
    317     return r
    318 }
    319 
    320 /**
    321  * Returns a [Region] representation of this rectangle.
    322  */
    323 inline fun Rect.toRegion() = Region(this)
    324 
    325 /**
    326  * Returns a [Region] representation of this rectangle. The resulting rect will be sized such
    327  * that this rect can fit within it.
    328  */
    329 inline fun RectF.toRegion() = Region(this.toRect())
    330 
    331 /**
    332  * Transform this rectangle in place using the supplied [Matrix] and returns
    333  * this rectangle.
    334  */
    335 inline fun RectF.transform(m: Matrix) = apply { m.mapRect(this@transform) }
    336