16e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk/* 26e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Copyright (C) 2012 The Android Open Source Project 36e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * 46e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License"); 56e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * you may not use this file except in compliance with the License. 66e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * You may obtain a copy of the License at 76e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * 86e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * http://www.apache.org/licenses/LICENSE-2.0 96e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * 106e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Unless required by applicable law or agreed to in writing, software 116e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS, 126e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * See the License for the specific language governing permissions and 146e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * limitations under the License. 156e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 166fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkpackage com.android.gallery3d.filtershow.crop; 176e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 186e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunkimport android.graphics.Matrix; 196fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunkimport android.graphics.Rect; 206e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunkimport android.graphics.RectF; 216e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 22b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; 236fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk 246e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunkimport java.util.Arrays; 256e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 266e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk/** 276e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Maintains invariant that inner rectangle is constrained to be within the 286e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * outer, rotated rectangle. 296e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 306e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunkpublic class BoundedRect { 316e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private float rot; 326e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private RectF outer; 336e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private RectF inner; 346e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private float[] innerRotated; 356e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 366fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk public BoundedRect(float rotation, Rect outerRect, Rect innerRect) { 376fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk rot = rotation; 386fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk outer = new RectF(outerRect); 396fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk inner = new RectF(innerRect); 406fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk innerRotated = CropMath.getCornersFromRect(inner); 416fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk rotateInner(); 426fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk if (!isConstrained()) 436fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk reconstrain(); 446e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 456e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 466e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public BoundedRect(float rotation, RectF outerRect, RectF innerRect) { 476e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk rot = rotation; 486e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk outer = new RectF(outerRect); 496e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk inner = new RectF(innerRect); 506e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = CropMath.getCornersFromRect(inner); 516e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk rotateInner(); 526e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!isConstrained()) 536e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 546e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 556e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 56ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk public void resetTo(float rotation, RectF outerRect, RectF innerRect) { 57ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk rot = rotation; 58ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk outer.set(outerRect); 59ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk inner.set(innerRect); 60ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk innerRotated = CropMath.getCornersFromRect(inner); 61ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk rotateInner(); 62ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk if (!isConstrained()) 63ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk reconstrain(); 64ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk } 65ea2fa83c2dd2b59b8a67ec363e4ac431748f997bRuben Brunk 666e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk /** 676e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Sets inner, and re-constrains it to fit within the rotated bounding rect. 686e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 696e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public void setInner(RectF newInner) { 706e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (inner.equals(newInner)) 716e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return; 726e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk inner = newInner; 736e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = CropMath.getCornersFromRect(inner); 746e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk rotateInner(); 756e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!isConstrained()) 766e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 776e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 786e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 796e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk /** 806e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Sets rotation, and re-constrains inner to fit within the rotated bounding rect. 816e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 826e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public void setRotation(float rotation) { 836e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (rotation == rot) 846e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return; 856e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk rot = rotation; 866e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = CropMath.getCornersFromRect(inner); 876e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk rotateInner(); 886e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!isConstrained()) 896e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 906e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 916e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 926fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk public void setToInner(RectF r) { 936fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk r.set(inner); 946fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk } 956fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk 966fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk public void setToOuter(RectF r) { 976fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk r.set(outer); 986fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk } 996fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk 1006e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public RectF getInner() { 1016e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return new RectF(inner); 1026e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1036e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1046fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk public RectF getOuter() { 1056fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk return new RectF(outer); 1066fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk } 1076fe165b7d28299d5b2f97deb135b233d84eb300fRuben Brunk 1086e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk /** 1096e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Tries to move the inner rectangle by (dx, dy). If this would cause it to leave 1106e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * the bounding rectangle, snaps the inner rectangle to the edge of the bounding 1116e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * rectangle. 1126e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 1136e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public void moveInner(float dx, float dy) { 1146e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m0 = getInverseRotMatrix(); 1156e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1166e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk RectF translatedInner = new RectF(inner); 1176e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk translatedInner.offset(dx, dy); 1186e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1196e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] translatedInnerCorners = CropMath.getCornersFromRect(translatedInner); 1206e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] outerCorners = CropMath.getCornersFromRect(outer); 1216e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1226e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m0.mapPoints(translatedInnerCorners); 1236e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] correction = { 1246e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 0, 0 1256e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 1266e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1276e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // find correction vectors for corners that have moved out of bounds 1286e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < translatedInnerCorners.length; i += 2) { 1296e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerX = translatedInnerCorners[i] + correction[0]; 1306e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerY = translatedInnerCorners[i + 1] + correction[1]; 1316e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) { 1326e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] badCorner = { 1336e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correctedInnerX, correctedInnerY 1346e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 1356e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] nearestSide = CropMath.closestSide(badCorner, outerCorners); 1366e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] correctionVec = 137b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk GeometryMathUtils.shortestVectorFromPointToLine(badCorner, nearestSide); 1386e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correction[0] += correctionVec[0]; 1396e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correction[1] += correctionVec[1]; 1406e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1416e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1426e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1436e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < translatedInnerCorners.length; i += 2) { 1446e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerX = translatedInnerCorners[i] + correction[0]; 1456e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerY = translatedInnerCorners[i + 1] + correction[1]; 1466e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!CropMath.inclusiveContains(outer, correctedInnerX, correctedInnerY)) { 1476e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] correctionVec = { 1486e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correctedInnerX, correctedInnerY 1496e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 1506e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk CropMath.getEdgePoints(outer, correctionVec); 1516e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correctionVec[0] -= correctedInnerX; 1526e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correctionVec[1] -= correctedInnerY; 1536e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correction[0] += correctionVec[0]; 1546e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk correction[1] += correctionVec[1]; 1556e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1566e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1576e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1586e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // Set correction 1596e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < translatedInnerCorners.length; i += 2) { 1606e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerX = translatedInnerCorners[i] + correction[0]; 1616e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float correctedInnerY = translatedInnerCorners[i + 1] + correction[1]; 1626e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // update translated corners with correction vectors 1636e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk translatedInnerCorners[i] = correctedInnerX; 1646e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk translatedInnerCorners[i + 1] = correctedInnerY; 1656e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1666e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1676e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = translatedInnerCorners; 1686e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // reconstrain to update inner 1696e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 1706e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 1716e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1726e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk /** 1736e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Attempts to resize the inner rectangle. If this would cause it to leave 1746e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * the bounding rect, clips the inner rectangle to fit. 1756e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 1766e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public void resizeInner(RectF newInner) { 1776e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = getRotMatrix(); 1786e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m0 = getInverseRotMatrix(); 1796e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1806e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] outerCorners = CropMath.getCornersFromRect(outer); 1816e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.mapPoints(outerCorners); 1826e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] oldInnerCorners = CropMath.getCornersFromRect(inner); 1836e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] newInnerCorners = CropMath.getCornersFromRect(newInner); 1846e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk RectF ret = new RectF(newInner); 1856e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 1866e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < newInnerCorners.length; i += 2) { 1876e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] c = { 1886e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk newInnerCorners[i], newInnerCorners[i + 1] 1896e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 1906e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] c0 = Arrays.copyOf(c, 2); 1916e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m0.mapPoints(c0); 1926e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) { 1936e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] outerSide = CropMath.closestSide(c, outerCorners); 1946e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] pathOfCorner = { 1956e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk newInnerCorners[i], newInnerCorners[i + 1], 1966e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk oldInnerCorners[i], oldInnerCorners[i + 1] 1976e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 198b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk float[] p = GeometryMathUtils.lineIntersect(pathOfCorner, outerSide); 1996e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (p == null) { 2006e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // lines are parallel or not well defined, so don't resize 2016e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p = new float[2]; 2026e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p[0] = oldInnerCorners[i]; 2036e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p[1] = oldInnerCorners[i + 1]; 2046e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2056e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // relies on corners being in same order as method 2066e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // getCornersFromRect 2076e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk switch (i) { 2086e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 0: 2096e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 1: 2106e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.left = (p[0] > ret.left) ? p[0] : ret.left; 2116e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.top = (p[1] > ret.top) ? p[1] : ret.top; 2126e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk break; 2136e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 2: 2146e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 3: 2156e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.right = (p[0] < ret.right) ? p[0] : ret.right; 2166e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.top = (p[1] > ret.top) ? p[1] : ret.top; 2176e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk break; 2186e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 4: 2196e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 5: 2206e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.right = (p[0] < ret.right) ? p[0] : ret.right; 2216e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom; 2226e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk break; 2236e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 6: 2246e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk case 7: 2256e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.left = (p[0] > ret.left) ? p[0] : ret.left; 2266e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.bottom = (p[1] < ret.bottom) ? p[1] : ret.bottom; 2276e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk break; 2286e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk default: 2296e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk break; 2306e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2316e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2326e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2336e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] retCorners = CropMath.getCornersFromRect(ret); 2346e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m0.mapPoints(retCorners); 2356e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = retCorners; 2366e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // reconstrain to update inner 2376e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 2386e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2396e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 2406e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk /** 2416e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * Attempts to resize the inner rectangle. If this would cause it to leave 2426e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * the bounding rect, clips the inner rectangle to fit while maintaining 2436e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk * aspect ratio. 2446e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk */ 2456e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk public void fixedAspectResizeInner(RectF newInner) { 2466e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = getRotMatrix(); 2476e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m0 = getInverseRotMatrix(); 2486e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 2496e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float aspectW = inner.width(); 2506e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float aspectH = inner.height(); 2516e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float aspRatio = aspectW / aspectH; 2526e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] corners = CropMath.getCornersFromRect(outer); 2536e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 2546e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.mapPoints(corners); 2556e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] oldInnerCorners = CropMath.getCornersFromRect(inner); 2566e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] newInnerCorners = CropMath.getCornersFromRect(newInner); 2576e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 2586e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // find fixed corner 2596e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk int fixed = -1; 2606e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (inner.top == newInner.top) { 2616e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (inner.left == newInner.left) 2626e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk fixed = 0; // top left 2636e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk else if (inner.right == newInner.right) 2646e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk fixed = 2; // top right 2656e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } else if (inner.bottom == newInner.bottom) { 2666e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (inner.right == newInner.right) 2676e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk fixed = 4; // bottom right 2686e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk else if (inner.left == newInner.left) 2696e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk fixed = 6; // bottom left 2706e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2716e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // no fixed corner, return without update 2726e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (fixed == -1) 2736e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return; 2746e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float widthSoFar = newInner.width(); 2756e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk int moved = -1; 2766e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < newInnerCorners.length; i += 2) { 2776e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] c = { 2786e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk newInnerCorners[i], newInnerCorners[i + 1] 2796e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 2806e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] c0 = Arrays.copyOf(c, 2); 2816e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m0.mapPoints(c0); 2826e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!CropMath.inclusiveContains(outer, c0[0], c0[1])) { 2836e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk moved = i; 2846e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (moved == fixed) 2856e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk continue; 2866e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] l2 = CropMath.closestSide(c, corners); 2876e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] l1 = { 2886e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk newInnerCorners[i], newInnerCorners[i + 1], 2896e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk oldInnerCorners[i], oldInnerCorners[i + 1] 2906e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk }; 291b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk float[] p = GeometryMathUtils.lineIntersect(l1, l2); 2926e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (p == null) { 2936e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // lines are parallel or not well defined, so set to old 2946e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // corner 2956e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p = new float[2]; 2966e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p[0] = oldInnerCorners[i]; 2976e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk p[1] = oldInnerCorners[i + 1]; 2986e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 2996e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // relies on corners being in same order as method 3006e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // getCornersFromRect 3016e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float fixed_x = oldInnerCorners[fixed]; 3026e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float fixed_y = oldInnerCorners[fixed + 1]; 3036e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float newWidth = Math.abs(fixed_x - p[0]); 3046e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float newHeight = Math.abs(fixed_y - p[1]); 3056e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk newWidth = Math.max(newWidth, aspRatio * newHeight); 3066e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (newWidth < widthSoFar) 3076e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk widthSoFar = newWidth; 3086e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3096e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3106e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3116e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float heightSoFar = widthSoFar / aspRatio; 3126e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk RectF ret = new RectF(inner); 3136e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (fixed == 0) { 3146e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.right = ret.left + widthSoFar; 3156e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.bottom = ret.top + heightSoFar; 3166e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } else if (fixed == 2) { 3176e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.left = ret.right - widthSoFar; 3186e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.bottom = ret.top + heightSoFar; 3196e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } else if (fixed == 4) { 3206e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.left = ret.right - widthSoFar; 3216e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.top = ret.bottom - heightSoFar; 3226e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } else if (fixed == 6) { 3236e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.right = ret.left + widthSoFar; 3246e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk ret.top = ret.bottom - heightSoFar; 3256e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3266e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] retCorners = CropMath.getCornersFromRect(ret); 3276e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m0.mapPoints(retCorners); 3286e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk innerRotated = retCorners; 3296e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // reconstrain to update inner 3306e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk reconstrain(); 3316e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3326e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3336e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // internal methods 3346e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3356e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private boolean isConstrained() { 3366e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk for (int i = 0; i < 8; i += 2) { 3376e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk if (!CropMath.inclusiveContains(outer, innerRotated[i], innerRotated[i + 1])) 3386e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return false; 3396e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3406e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return true; 3416e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3426e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3436e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private void reconstrain() { 3446e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk // innerRotated has been changed to have incorrect values 3456e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk CropMath.getEdgePoints(outer, innerRotated); 3466e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = getRotMatrix(); 3476e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk float[] unrotated = Arrays.copyOf(innerRotated, 8); 3486e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.mapPoints(unrotated); 3496e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk inner = CropMath.trapToRect(unrotated); 3506e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3516e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3526e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private void rotateInner() { 3536e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = getInverseRotMatrix(); 3546e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.mapPoints(innerRotated); 3556e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3566e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3576e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private Matrix getRotMatrix() { 3586e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = new Matrix(); 3596e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.setRotate(rot, outer.centerX(), outer.centerY()); 3606e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return m; 3616e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3626e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk 3636e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk private Matrix getInverseRotMatrix() { 3646e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk Matrix m = new Matrix(); 3656e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk m.setRotate(-rot, outer.centerX(), outer.centerY()); 3666e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk return m; 3676e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk } 3686e2dd284681a716c55e0937ef2e15a1c7507a1b2Ruben Brunk} 369