summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/crop/CropObject.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/crop/CropObject.java')
-rw-r--r--src/com/android/camera/crop/CropObject.java328
1 files changed, 328 insertions, 0 deletions
diff --git a/src/com/android/camera/crop/CropObject.java b/src/com/android/camera/crop/CropObject.java
new file mode 100644
index 000000000..4a566b3ef
--- /dev/null
+++ b/src/com/android/camera/crop/CropObject.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2013 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.camera.crop;
+
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+public class CropObject {
+ private BoundedRect mBoundedRect;
+ private float mAspectWidth = 1;
+ private float mAspectHeight = 1;
+ private boolean mFixAspectRatio = false;
+ private float mRotation = 0;
+ private float mTouchTolerance = 45;
+ private float mMinSideSize = 20;
+
+ public static final int MOVE_NONE = 0;
+ // Sides
+ public static final int MOVE_LEFT = 1;
+ public static final int MOVE_TOP = 2;
+ public static final int MOVE_RIGHT = 4;
+ public static final int MOVE_BOTTOM = 8;
+ public static final int MOVE_BLOCK = 16;
+
+ // Corners
+ public static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT;
+ public static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT;
+ public static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT;
+ public static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT;
+
+ private int mMovingEdges = MOVE_NONE;
+
+ public CropObject(Rect outerBound, Rect innerBound, int outerAngle) {
+ mBoundedRect = new BoundedRect(outerAngle % 360, outerBound, innerBound);
+ }
+
+ public CropObject(RectF outerBound, RectF innerBound, int outerAngle) {
+ mBoundedRect = new BoundedRect(outerAngle % 360, outerBound, innerBound);
+ }
+
+ public void resetBoundsTo(RectF inner, RectF outer) {
+ mBoundedRect.resetTo(0, outer, inner);
+ }
+
+ public void getInnerBounds(RectF r) {
+ mBoundedRect.setToInner(r);
+ }
+
+ public void getOuterBounds(RectF r) {
+ mBoundedRect.setToOuter(r);
+ }
+
+ public RectF getInnerBounds() {
+ return mBoundedRect.getInner();
+ }
+
+ public RectF getOuterBounds() {
+ return mBoundedRect.getOuter();
+ }
+
+ public int getSelectState() {
+ return mMovingEdges;
+ }
+
+ public boolean isFixedAspect() {
+ return mFixAspectRatio;
+ }
+
+ public void rotateOuter(int angle) {
+ mRotation = angle % 360;
+ mBoundedRect.setRotation(mRotation);
+ clearSelectState();
+ }
+
+ public boolean setInnerAspectRatio(float width, float height) {
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("Width and Height must be greater than zero");
+ }
+ RectF inner = mBoundedRect.getInner();
+ CropMath.fixAspectRatioContained(inner, width, height);
+ if (inner.width() < mMinSideSize || inner.height() < mMinSideSize) {
+ return false;
+ }
+ mAspectWidth = width;
+ mAspectHeight = height;
+ mFixAspectRatio = true;
+ mBoundedRect.setInner(inner);
+ clearSelectState();
+ return true;
+ }
+
+ public void setTouchTolerance(float tolerance) {
+ if (tolerance <= 0) {
+ throw new IllegalArgumentException("Tolerance must be greater than zero");
+ }
+ mTouchTolerance = tolerance;
+ }
+
+ public void setMinInnerSideSize(float minSide) {
+ if (minSide <= 0) {
+ throw new IllegalArgumentException("Min dide must be greater than zero");
+ }
+ mMinSideSize = minSide;
+ }
+
+ public void unsetAspectRatio() {
+ mFixAspectRatio = false;
+ clearSelectState();
+ }
+
+ public boolean hasSelectedEdge() {
+ return mMovingEdges != MOVE_NONE;
+ }
+
+ public static boolean checkCorner(int selected) {
+ return selected == TOP_LEFT || selected == TOP_RIGHT || selected == BOTTOM_RIGHT
+ || selected == BOTTOM_LEFT;
+ }
+
+ public static boolean checkEdge(int selected) {
+ return selected == MOVE_LEFT || selected == MOVE_TOP || selected == MOVE_RIGHT
+ || selected == MOVE_BOTTOM;
+ }
+
+ public static boolean checkBlock(int selected) {
+ return selected == MOVE_BLOCK;
+ }
+
+ public static boolean checkValid(int selected) {
+ return selected == MOVE_NONE || checkBlock(selected) || checkEdge(selected)
+ || checkCorner(selected);
+ }
+
+ public void clearSelectState() {
+ mMovingEdges = MOVE_NONE;
+ }
+
+ public int wouldSelectEdge(float x, float y) {
+ int edgeSelected = calculateSelectedEdge(x, y);
+ if (edgeSelected != MOVE_NONE && edgeSelected != MOVE_BLOCK) {
+ return edgeSelected;
+ }
+ return MOVE_NONE;
+ }
+
+ public boolean selectEdge(int edge) {
+ if (!checkValid(edge)) {
+ // temporary
+ throw new IllegalArgumentException("bad edge selected");
+ // return false;
+ }
+ if ((mFixAspectRatio && !checkCorner(edge)) && !checkBlock(edge) && edge != MOVE_NONE) {
+ // temporary
+ throw new IllegalArgumentException("bad corner selected");
+ // return false;
+ }
+ mMovingEdges = edge;
+ return true;
+ }
+
+ public boolean selectEdge(float x, float y) {
+ int edgeSelected = calculateSelectedEdge(x, y);
+ if (mFixAspectRatio) {
+ edgeSelected = fixEdgeToCorner(edgeSelected);
+ }
+ if (edgeSelected == MOVE_NONE) {
+ return false;
+ }
+ return selectEdge(edgeSelected);
+ }
+
+ public boolean moveCurrentSelection(float dX, float dY) {
+ if (mMovingEdges == MOVE_NONE) {
+ return false;
+ }
+ RectF crop = mBoundedRect.getInner();
+
+ float minWidthHeight = mMinSideSize;
+
+ int movingEdges = mMovingEdges;
+ if (movingEdges == MOVE_BLOCK) {
+ mBoundedRect.moveInner(dX, dY);
+ return true;
+ } else {
+ float dx = 0;
+ float dy = 0;
+
+ if ((movingEdges & MOVE_LEFT) != 0) {
+ dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left;
+ }
+ if ((movingEdges & MOVE_TOP) != 0) {
+ dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top;
+ }
+ if ((movingEdges & MOVE_RIGHT) != 0) {
+ dx = Math.max(crop.right + dX, crop.left + minWidthHeight)
+ - crop.right;
+ }
+ if ((movingEdges & MOVE_BOTTOM) != 0) {
+ dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight)
+ - crop.bottom;
+ }
+
+ if (mFixAspectRatio) {
+ float[] l1 = {
+ crop.left, crop.bottom
+ };
+ float[] l2 = {
+ crop.right, crop.top
+ };
+ if (movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT) {
+ l1[1] = crop.top;
+ l2[1] = crop.bottom;
+ }
+ float[] b = {
+ l1[0] - l2[0], l1[1] - l2[1]
+ };
+ float[] disp = {
+ dx, dy
+ };
+ float[] bUnit = GeometryMathUtils.normalize(b);
+ float sp = GeometryMathUtils.scalarProjection(disp, bUnit);
+ dx = sp * bUnit[0];
+ dy = sp * bUnit[1];
+ RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
+
+ mBoundedRect.fixedAspectResizeInner(newCrop);
+ } else {
+ if ((movingEdges & MOVE_LEFT) != 0) {
+ crop.left += dx;
+ }
+ if ((movingEdges & MOVE_TOP) != 0) {
+ crop.top += dy;
+ }
+ if ((movingEdges & MOVE_RIGHT) != 0) {
+ crop.right += dx;
+ }
+ if ((movingEdges & MOVE_BOTTOM) != 0) {
+ crop.bottom += dy;
+ }
+ mBoundedRect.resizeInner(crop);
+ }
+ }
+ return true;
+ }
+
+ // Helper methods
+
+ private int calculateSelectedEdge(float x, float y) {
+ RectF cropped = mBoundedRect.getInner();
+
+ float left = Math.abs(x - cropped.left);
+ float right = Math.abs(x - cropped.right);
+ float top = Math.abs(y - cropped.top);
+ float bottom = Math.abs(y - cropped.bottom);
+
+ int edgeSelected = MOVE_NONE;
+ // Check left or right.
+ if ((left <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
+ && ((y - mTouchTolerance) <= cropped.bottom) && (left < right)) {
+ edgeSelected |= MOVE_LEFT;
+ }
+ else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
+ && ((y - mTouchTolerance) <= cropped.bottom)) {
+ edgeSelected |= MOVE_RIGHT;
+ }
+
+ // Check top or bottom.
+ if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
+ && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) {
+ edgeSelected |= MOVE_TOP;
+ }
+ else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
+ && ((x - mTouchTolerance) <= cropped.right)) {
+ edgeSelected |= MOVE_BOTTOM;
+ }
+ return edgeSelected;
+ }
+
+ private static RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) {
+ RectF newCrop = null;
+ // Fix opposite corner in place and move sides
+ if (moving_corner == BOTTOM_RIGHT) {
+ newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height()
+ + dy);
+ } else if (moving_corner == BOTTOM_LEFT) {
+ newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height()
+ + dy);
+ } else if (moving_corner == TOP_LEFT) {
+ newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy,
+ r.right, r.bottom);
+ } else if (moving_corner == TOP_RIGHT) {
+ newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left
+ + r.width() + dx, r.bottom);
+ }
+ return newCrop;
+ }
+
+ private static int fixEdgeToCorner(int moving_edges) {
+ if (moving_edges == MOVE_LEFT) {
+ moving_edges |= MOVE_TOP;
+ }
+ if (moving_edges == MOVE_TOP) {
+ moving_edges |= MOVE_LEFT;
+ }
+ if (moving_edges == MOVE_RIGHT) {
+ moving_edges |= MOVE_BOTTOM;
+ }
+ if (moving_edges == MOVE_BOTTOM) {
+ moving_edges |= MOVE_RIGHT;
+ }
+ return moving_edges;
+ }
+
+}