| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.gallery3d.filtershow.imageshow; |
| |
| import android.graphics.Matrix; |
| import android.graphics.RectF; |
| |
| import java.util.Arrays; |
| |
| public class CropMath { |
| |
| /** |
| * Gets a float array of the 2D coordinates representing a rectangles |
| * corners. |
| * The order of the corners in the float array is: |
| * 0------->1 |
| * ^ | |
| * | v |
| * 3<-------2 |
| * |
| * @param r the rectangle to get the corners of |
| * @return the float array of corners (8 floats) |
| */ |
| |
| public static float[] getCornersFromRect(RectF r) { |
| float[] corners = { |
| r.left, r.top, |
| r.right, r.top, |
| r.right, r.bottom, |
| r.left, r.bottom |
| }; |
| return corners; |
| } |
| |
| /** |
| * Returns true iff point (x, y) is within or on the rectangle's bounds. |
| * RectF's "contains" function treats points on the bottom and right bound |
| * as not being contained. |
| * |
| * @param r the rectangle |
| * @param x the x value of the point |
| * @param y the y value of the point |
| * @return |
| */ |
| public static boolean inclusiveContains(RectF r, float x, float y) { |
| return !(x > r.right || x < r.left || y > r.bottom || y < r.top); |
| } |
| |
| /** |
| * Takes an array of 2D coordinates representing corners and returns the |
| * smallest rectangle containing those coordinates. |
| * |
| * @param array array of 2D coordinates |
| * @return smallest rectangle containing coordinates |
| */ |
| public static RectF trapToRect(float[] array) { |
| RectF r = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, |
| Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); |
| for (int i = 1; i < array.length; i += 2) { |
| float x = array[i - 1]; |
| float y = array[i]; |
| r.left = (x < r.left) ? x : r.left; |
| r.top = (y < r.top) ? y : r.top; |
| r.right = (x > r.right) ? x : r.right; |
| r.bottom = (y > r.bottom) ? y : r.bottom; |
| } |
| r.sort(); |
| return r; |
| } |
| |
| /** |
| * If edge point [x, y] in array [x0, y0, x1, y1, ...] is outside of the |
| * image bound rectangle, clamps it to the edge of the rectangle. |
| * |
| * @param imageBound the rectangle to clamp edge points to. |
| * @param array an array of points to clamp to the rectangle, gets set to |
| * the clamped values. |
| */ |
| public static void getEdgePoints(RectF imageBound, float[] array) { |
| if (array.length < 2) |
| return; |
| for (int x = 0; x < array.length; x += 2) { |
| array[x] = GeometryMath.clamp(array[x], imageBound.left, imageBound.right); |
| array[x + 1] = GeometryMath.clamp(array[x + 1], imageBound.top, imageBound.bottom); |
| } |
| } |
| |
| /** |
| * Takes a point and the corners of a rectangle and returns the two corners |
| * representing the side of the rectangle closest to the point. |
| * |
| * @param point the point which is being checked |
| * @param corners the corners of the rectangle |
| * @return two corners representing the side of the rectangle |
| */ |
| public static float[] closestSide(float[] point, float[] corners) { |
| int len = corners.length; |
| float oldMag = Float.POSITIVE_INFINITY; |
| float[] bestLine = null; |
| for (int i = 0; i < len; i += 2) { |
| float[] line = { |
| corners[i], corners[(i + 1) % len], |
| corners[(i + 2) % len], corners[(i + 3) % len] |
| }; |
| float mag = GeometryMath.vectorLength( |
| GeometryMath.shortestVectorFromPointToLine(point, line)); |
| if (mag < oldMag) { |
| oldMag = mag; |
| bestLine = line; |
| } |
| } |
| return bestLine; |
| } |
| |
| /** |
| * Checks if a given point is within a rotated rectangle. |
| * |
| * @param point 2D point to check |
| * @param bound rectangle to rotate |
| * @param rot angle of rotation about rectangle center |
| * @return true if point is within rotated rectangle |
| */ |
| public static boolean pointInRotatedRect(float[] point, RectF bound, float rot) { |
| Matrix m = new Matrix(); |
| float[] p = Arrays.copyOf(point, 2); |
| m.setRotate(rot, bound.centerX(), bound.centerY()); |
| Matrix m0 = new Matrix(); |
| if (!m.invert(m0)) |
| return false; |
| m0.mapPoints(p); |
| return inclusiveContains(bound, p[0], p[1]); |
| } |
| |
| /** |
| * Checks if a given point is within a rotated rectangle. |
| * |
| * @param point 2D point to check |
| * @param rotatedRect corners of a rotated rectangle |
| * @param center center of the rotated rectangle |
| * @return true if point is within rotated rectangle |
| */ |
| public static boolean pointInRotatedRect(float[] point, float[] rotatedRect, float[] center) { |
| RectF unrotated = new RectF(); |
| float angle = getUnrotated(rotatedRect, center, unrotated); |
| return pointInRotatedRect(point, unrotated, angle); |
| } |
| |
| /** |
| * Resizes rectangle to have a certain aspect ratio (center remains |
| * stationary). |
| * |
| * @param r rectangle to resize |
| * @param w new width aspect |
| * @param h new height aspect |
| */ |
| public static void fixAspectRatio(RectF r, float w, float h) { |
| float scale = Math.min(r.width() / w, r.height() / h); |
| float centX = r.centerX(); |
| float centY = r.centerY(); |
| float hw = scale * w / 2; |
| float hh = scale * h / 2; |
| r.set(centX - hw, centY - hh, centX + hw, centY + hh); |
| } |
| |
| private static float getUnrotated(float[] rotatedRect, float[] center, RectF unrotated) { |
| float dy = rotatedRect[1] - rotatedRect[3]; |
| float dx = rotatedRect[0] - rotatedRect[2]; |
| float angle = (float) (Math.atan(dy / dx) * 180 / Math.PI); |
| Matrix m = new Matrix(); |
| m.setRotate(-angle, center[0], center[1]); |
| float[] unrotatedRect = new float[rotatedRect.length]; |
| m.mapPoints(unrotatedRect, rotatedRect); |
| unrotated.set(trapToRect(unrotatedRect)); |
| return angle; |
| } |
| |
| } |