1df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin/*
2df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Copyright (C) 2014 The Android Open Source Project
3df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin *
4df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
5df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * you may not use this file except in compliance with the License.
6df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * You may obtain a copy of the License at
7df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin *
8df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
9df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin *
10df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Unless required by applicable law or agreed to in writing, software
11df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
12df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * See the License for the specific language governing permissions and
14df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * limitations under the License.
15df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */
16df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
17df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinpackage android.hardware.camera2.utils;
18df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
197ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.graphics.Matrix;
20df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.graphics.Rect;
21df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.graphics.RectF;
2283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkinimport android.hardware.camera2.CaptureRequest;
233e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkinimport android.util.Rational;
24df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.util.Size;
25df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
26df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport static com.android.internal.util.Preconditions.*;
27df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
28df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin/**
29df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Various assortment of params utilities.
30df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */
31df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinpublic class ParamsUtils {
32df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
333e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin    /** Arbitrary denominator used to estimate floats as rationals */
343e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin    private static final int RATIONAL_DENOMINATOR = 1000000; // 1million
353e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
36df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    /**
37df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * Create a {@link Rect} from a {@code Size} by creating a new rectangle with
38df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * left, top = {@code (0, 0)} and right, bottom = {@code (width, height)}
39df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
40df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param size a non-{@code null} size
41df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
42df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @return a {@code non-null} rectangle
43df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
44df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @throws NullPointerException if {@code size} was {@code null}
45df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     */
46df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public static Rect createRect(Size size) {
47df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        checkNotNull(size, "size must not be null");
48df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
49df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        return new Rect(/*left*/0, /*top*/0, size.getWidth(), size.getHeight());
50df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    }
51df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
52df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    /**
53df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * Create a {@link Rect} from a {@code RectF} by creating a new rectangle with
547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * each corner (left, top, right, bottom) rounded towards the nearest integer bounding box.
557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     *
567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * <p>In particular (left, top) is floored, and (right, bottom) is ceiled.</p>
57df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
58df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param size a non-{@code null} rect
59df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
60df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @return a {@code non-null} rectangle
61df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
62df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @throws NullPointerException if {@code rect} was {@code null}
63df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     */
64df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public static Rect createRect(RectF rect) {
65df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        checkNotNull(rect, "rect must not be null");
66df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
67df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        Rect r = new Rect();
687ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        rect.roundOut(r);
69df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
70df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        return r;
71df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    }
72df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
73df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    /**
747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * Map the rectangle in {@code rect} with the transform in {@code transform} into
757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * a new rectangle, with each corner (left, top, right, bottom) rounded towards the nearest
767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * integer bounding box.
777ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     *
787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * <p>None of the arguments are mutated.</p>
797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     *
807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * @param transform a non-{@code null} transformation matrix
817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * @param rect a non-{@code null} rectangle
827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * @return a new rectangle that was transformed by {@code transform}
837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     *
847ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * @throws NullPointerException if any of the args were {@code null}
857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     */
867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin    public static Rect mapRect(Matrix transform, Rect rect) {
877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        checkNotNull(transform, "transform must not be null");
887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        checkNotNull(rect, "rect must not be null");
897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin
907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        RectF rectF = new RectF(rect);
917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        transform.mapRect(rectF);
927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin        return createRect(rectF);
937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin    }
947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin
957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin    /**
96df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * Create a {@link Size} from a {@code Rect} by creating a new size whose width
97df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * and height are the same as the rectangle's width and heights.
98df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
99df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param rect a non-{@code null} rectangle
100df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
101df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @return a {@code non-null} size
102df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
103df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @throws NullPointerException if {@code rect} was {@code null}
104df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     */
105df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public static Size createSize(Rect rect) {
106df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        checkNotNull(rect, "rect must not be null");
107df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
108df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        return new Size(rect.width(), rect.height());
109df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    }
110df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
111df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    /**
1123e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * Create a {@link Rational} value by approximating the float value as a rational.
1133e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     *
1143e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * <p>Floating points too large to be represented as an integer will be converted to
1153e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * to {@link Integer#MAX_VALUE}; floating points too small to be represented as an integer
1163e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * will be converted to {@link Integer#MIN_VALUE}.</p>
1173e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     *
1183e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * @param value a floating point value
1193e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     * @return the rational representation of the float
1203e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     */
1213e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin    public static Rational createRational(float value) {
1223e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        if (Float.isNaN(value)) {
1233e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            return Rational.NaN;
1243e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        } else if (value == Float.POSITIVE_INFINITY) {
1253e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            return Rational.POSITIVE_INFINITY;
1263e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        } else if (value == Float.NEGATIVE_INFINITY) {
1273e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            return Rational.NEGATIVE_INFINITY;
1283e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        } else if (value == 0.0f) {
1293e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            return Rational.ZERO;
1303e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        }
1313e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1323e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        // normal finite value: approximate it
1333e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1343e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        /*
1353e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         * Start out trying to approximate with denominator = 1million,
1363e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         * but if the numerator doesn't fit into an Int then keep making the denominator
1373e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         * smaller until it does.
1383e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         */
1393e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        int den = RATIONAL_DENOMINATOR;
1403e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        float numF;
1413e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        do {
1423e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            numF = value * den;
1433e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1443e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            if ((numF > Integer.MIN_VALUE && numF < Integer.MAX_VALUE) || (den == 1)) {
1453e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin                break;
1463e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            }
1473e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1483e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin            den /= 10;
1493e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        } while (true);
1503e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1513e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        /*
1523e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         *  By float -> int narrowing conversion in JLS 5.1.3, this will automatically become
1533e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         *  MIN_VALUE or MAX_VALUE if numF is too small/large to be represented by an integer
1543e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin         */
1553e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        int num = (int) numF;
1563e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1573e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin        return new Rational(num, den);
1583e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin     }
1593e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin
1603e280b4bb23be4e5e66ea6381fd63c74fdbd927eIgor Murashkin    /**
1617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * Convert an integral rectangle ({@code source}) to a floating point rectangle
162df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * ({@code destination}) in-place.
163df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
1647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin     * @param source the originating integer rectangle will be read from here
165df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param destination the resulting floating point rectangle will be written out to here
166df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     *
167df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @throws NullPointerException if {@code rect} was {@code null}
168df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     */
169df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public static void convertRectF(Rect source, RectF destination) {
170df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        checkNotNull(source, "source must not be null");
171df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        checkNotNull(destination, "destination must not be null");
172df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
173df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        destination.left = source.left;
174df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        destination.right = source.right;
175df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        destination.bottom = source.bottom;
176df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        destination.top = source.top;
177df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    }
178df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin
17983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    /**
18083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * Return the value set by the key, or the {@code defaultValue} if no value was set.
18183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     *
18283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @throws NullPointerException if any of the args were {@code null}
18383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     */
18483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    public static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
18583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        checkNotNull(r, "r must not be null");
18683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        checkNotNull(key, "key must not be null");
18783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        checkNotNull(defaultValue, "defaultValue must not be null");
18883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
18983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        T value = r.get(key);
19083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        if (value == null) {
19183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            return defaultValue;
19283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        } else {
19383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            return value;
19483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        }
19583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    }
19683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
197df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    private ParamsUtils() {
198df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin        throw new AssertionError();
199df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    }
200df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin}
201