16fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk/*
26fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * Copyright (C) 2013 The Android Open Source Project
36fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk *
46fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
56fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * you may not use this file except in compliance with the License.
66fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * You may obtain a copy of the License at
76fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk *
86fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
96fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk *
106fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * Unless required by applicable law or agreed to in writing, software
116fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
126fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * See the License for the specific language governing permissions and
146fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk * limitations under the License.
156fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk */
166fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
176fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkpackage com.android.gallery3d.filtershow.crop;
186fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
196fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkimport android.graphics.Rect;
206fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkimport android.graphics.RectF;
216fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
22b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
236fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
246fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkpublic class CropObject {
256fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private BoundedRect mBoundedRect;
266fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private float mAspectWidth = 1;
276fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private float mAspectHeight = 1;
286fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private boolean mFixAspectRatio = false;
296fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private float mRotation = 0;
306fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private float mTouchTolerance = 45;
316fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private float mMinSideSize = 20;
326fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
336fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_NONE = 0;
346fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    // Sides
356fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_LEFT = 1;
366fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_TOP = 2;
376fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_RIGHT = 4;
386fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_BOTTOM = 8;
396fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int MOVE_BLOCK = 16;
406fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
416fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    // Corners
426fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT;
436fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT;
446fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT;
456fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT;
466fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
476fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private int mMovingEdges = MOVE_NONE;
486fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
496fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public CropObject(Rect outerBound, Rect innerBound, int outerAngle) {
506fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect = new BoundedRect(outerAngle % 360, outerBound, innerBound);
516fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
526fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
536fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public CropObject(RectF outerBound, RectF innerBound, int outerAngle) {
546fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect = new BoundedRect(outerAngle % 360, outerBound, innerBound);
556fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
566fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
57ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk    public void resetBoundsTo(RectF inner, RectF outer) {
58ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk        mBoundedRect.resetTo(0, outer, inner);
59ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk    }
60ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk
61ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk    public void getInnerBounds(RectF r) {
626fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect.setToInner(r);
636fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
646fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
65ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk    public void getOuterBounds(RectF r) {
666fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect.setToOuter(r);
676fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
686fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
696fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public RectF getInnerBounds() {
706fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return mBoundedRect.getInner();
716fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
726fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
736fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public RectF getOuterBounds() {
746fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return mBoundedRect.getOuter();
756fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
766fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
776fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public int getSelectState() {
786fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return mMovingEdges;
796fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
806fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
816fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public boolean isFixedAspect() {
826fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return mFixAspectRatio;
836fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
846fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
856fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public void rotateOuter(int angle) {
866fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mRotation = angle % 360;
876fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect.setRotation(mRotation);
886fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        clearSelectState();
896fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
906fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
9188cd551c2f42061ca7482b884c0c5bb686ec7eb2Ruben Brunk    public boolean setInnerAspectRatio(float width, float height) {
926fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (width <= 0 || height <= 0) {
936fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            throw new IllegalArgumentException("Width and Height must be greater than zero");
946fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
956fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        RectF inner = mBoundedRect.getInner();
966fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        CropMath.fixAspectRatioContained(inner, width, height);
976fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (inner.width() < mMinSideSize || inner.height() < mMinSideSize) {
986fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            return false;
996fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1006fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mAspectWidth = width;
1016fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mAspectHeight = height;
1026fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mFixAspectRatio = true;
1036fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mBoundedRect.setInner(inner);
1046fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        clearSelectState();
1056fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return true;
1066fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1076fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1086fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public void setTouchTolerance(float tolerance) {
1096fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (tolerance <= 0) {
1106fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            throw new IllegalArgumentException("Tolerance must be greater than zero");
1116fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1126fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mTouchTolerance = tolerance;
1136fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1146fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1156fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public void setMinInnerSideSize(float minSide) {
1166fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (minSide <= 0) {
1176fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            throw new IllegalArgumentException("Min dide must be greater than zero");
1186fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1196fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mMinSideSize = minSide;
1206fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1216fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1226fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public void unsetAspectRatio() {
1236fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mFixAspectRatio = false;
1246fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        clearSelectState();
1256fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1266fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1276fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public boolean hasSelectedEdge() {
1286fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return mMovingEdges != MOVE_NONE;
1296fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1306fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1316fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static boolean checkCorner(int selected) {
1326fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return selected == TOP_LEFT || selected == TOP_RIGHT || selected == BOTTOM_RIGHT
1336fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                || selected == BOTTOM_LEFT;
1346fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1356fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1366fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static boolean checkEdge(int selected) {
1376fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return selected == MOVE_LEFT || selected == MOVE_TOP || selected == MOVE_RIGHT
1386fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                || selected == MOVE_BOTTOM;
1396fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1406fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1416fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static boolean checkBlock(int selected) {
1426fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return selected == MOVE_BLOCK;
1436fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1446fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1456fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public static boolean checkValid(int selected) {
1466fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return selected == MOVE_NONE || checkBlock(selected) || checkEdge(selected)
1476fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                || checkCorner(selected);
1486fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1496fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1506fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public void clearSelectState() {
1516fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mMovingEdges = MOVE_NONE;
1526fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1536fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1546fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public int wouldSelectEdge(float x, float y) {
1556fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        int edgeSelected = calculateSelectedEdge(x, y);
1566fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (edgeSelected != MOVE_NONE && edgeSelected != MOVE_BLOCK) {
1576fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            return edgeSelected;
1586fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1596fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return MOVE_NONE;
1606fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1616fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1626fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public boolean selectEdge(int edge) {
1636fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (!checkValid(edge)) {
1646fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            // temporary
1656fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            throw new IllegalArgumentException("bad edge selected");
1666fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            // return false;
1676fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1686cfb081cdf5acf454ecb05c50c575bcb3ce74cf0Ruben Brunk        if ((mFixAspectRatio && !checkCorner(edge)) && !checkBlock(edge) && edge != MOVE_NONE) {
1696fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            // temporary
1706fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            throw new IllegalArgumentException("bad corner selected");
1716fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            // return false;
1726fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1736fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        mMovingEdges = edge;
1746fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return true;
1756fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1766fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1776fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public boolean selectEdge(float x, float y) {
1786fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        int edgeSelected = calculateSelectedEdge(x, y);
1796fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (mFixAspectRatio) {
1806fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            edgeSelected = fixEdgeToCorner(edgeSelected);
1816fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1826fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (edgeSelected == MOVE_NONE) {
1836fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            return false;
1846fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1856fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return selectEdge(edgeSelected);
1866fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
1876fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1886fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    public boolean moveCurrentSelection(float dX, float dY) {
1896fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (mMovingEdges == MOVE_NONE) {
1906fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            return false;
1916fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
1926fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        RectF crop = mBoundedRect.getInner();
1936fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1946fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        float minWidthHeight = mMinSideSize;
1956fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
1966fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        int movingEdges = mMovingEdges;
1976fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (movingEdges == MOVE_BLOCK) {
1986fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            mBoundedRect.moveInner(dX, dY);
1996fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            return true;
2006fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        } else {
2016fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            float dx = 0;
2026fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            float dy = 0;
2036fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2046fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            if ((movingEdges & MOVE_LEFT) != 0) {
2056fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left;
2066fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            }
2076fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            if ((movingEdges & MOVE_TOP) != 0) {
2086fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top;
2096fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            }
2106fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            if ((movingEdges & MOVE_RIGHT) != 0) {
2116fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dx = Math.max(crop.right + dX, crop.left + minWidthHeight)
2126fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        - crop.right;
2136fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            }
2146fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            if ((movingEdges & MOVE_BOTTOM) != 0) {
2156fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight)
2166fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        - crop.bottom;
2176fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            }
2186fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2196fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            if (mFixAspectRatio) {
2206fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                float[] l1 = {
2216fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        crop.left, crop.bottom
2226fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                };
2236fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                float[] l2 = {
2246fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        crop.right, crop.top
2256fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                };
2266fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                if (movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT) {
2276fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    l1[1] = crop.top;
2286fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    l2[1] = crop.bottom;
2296fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                }
2306fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                float[] b = {
2316fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        l1[0] - l2[0], l1[1] - l2[1]
2326fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                };
2336fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                float[] disp = {
2346fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                        dx, dy
2356fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                };
236b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                float[] bUnit = GeometryMathUtils.normalize(b);
237b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                float sp = GeometryMathUtils.scalarProjection(disp, bUnit);
2386fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dx = sp * bUnit[0];
2396fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                dy = sp * bUnit[1];
2406fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
2416fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2426fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                mBoundedRect.fixedAspectResizeInner(newCrop);
2436fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            } else {
2446fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                if ((movingEdges & MOVE_LEFT) != 0) {
2456fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    crop.left += dx;
2466fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                }
2476fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                if ((movingEdges & MOVE_TOP) != 0) {
2486fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    crop.top += dy;
2496fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                }
2506fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                if ((movingEdges & MOVE_RIGHT) != 0) {
2516fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    crop.right += dx;
2526fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                }
2536fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                if ((movingEdges & MOVE_BOTTOM) != 0) {
2546fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    crop.bottom += dy;
2556fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                }
2566fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                mBoundedRect.resizeInner(crop);
2576fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            }
2586fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
2596fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return true;
2606fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
2616fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2626fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    // Helper methods
2636fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2646fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private int calculateSelectedEdge(float x, float y) {
2656fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        RectF cropped = mBoundedRect.getInner();
2666fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2676fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        float left = Math.abs(x - cropped.left);
2686fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        float right = Math.abs(x - cropped.right);
2696fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        float top = Math.abs(y - cropped.top);
2706fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        float bottom = Math.abs(y - cropped.bottom);
2716fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2726fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        int edgeSelected = MOVE_NONE;
2736fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        // Check left or right.
2746fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if ((left <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
2756fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                && ((y - mTouchTolerance) <= cropped.bottom) && (left < right)) {
2766fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            edgeSelected |= MOVE_LEFT;
2776fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
2786fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
2796fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                && ((y - mTouchTolerance) <= cropped.bottom)) {
2806fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            edgeSelected |= MOVE_RIGHT;
2816fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
2826fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2836fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        // Check top or bottom.
2846fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
2856fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) {
2866fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            edgeSelected |= MOVE_TOP;
2876fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
2886fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
2896fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                && ((x - mTouchTolerance) <= cropped.right)) {
2906fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            edgeSelected |= MOVE_BOTTOM;
2916fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
2926fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return edgeSelected;
2936fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
2946fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
2956fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private static RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) {
2966fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        RectF newCrop = null;
2976fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        // Fix opposite corner in place and move sides
2986fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (moving_corner == BOTTOM_RIGHT) {
2996fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height()
3006fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    + dy);
3016fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        } else if (moving_corner == BOTTOM_LEFT) {
3026fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height()
3036fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    + dy);
3046fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        } else if (moving_corner == TOP_LEFT) {
3056fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy,
3066fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    r.right, r.bottom);
3076fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        } else if (moving_corner == TOP_RIGHT) {
3086fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left
3096fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk                    + r.width() + dx, r.bottom);
3106fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
3116fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return newCrop;
3126fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
3136fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
3146fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    private static int fixEdgeToCorner(int moving_edges) {
3156fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (moving_edges == MOVE_LEFT) {
3166fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            moving_edges |= MOVE_TOP;
3176fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
3186fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (moving_edges == MOVE_TOP) {
3196fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            moving_edges |= MOVE_LEFT;
3206fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
3216fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (moving_edges == MOVE_RIGHT) {
3226fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            moving_edges |= MOVE_BOTTOM;
3236fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
3246fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        if (moving_edges == MOVE_BOTTOM) {
3256fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk            moving_edges |= MOVE_RIGHT;
3266fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        }
3276fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk        return moving_edges;
3286fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk    }
3296fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk
3306fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk}
331