mineshcvit.opendocscanner.CroppingTrapezoid.java Source code

Java tutorial

Introduction

Here is the source code for mineshcvit.opendocscanner.CroppingTrapezoid.java

Source

/*
 * Copyright (C) 2012,2013,2014,2015 Renard Wellnitz.
 *
 * 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 mineshcvit.opendocscanner;

import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.Log;

import org.opencv.core.Point;

import java.util.ArrayList;

//import android.graphics.Point;

/**
 * Created by renard on 26/02/15.
 */
public class CroppingTrapezoid {

    private final static String LOG_TAG = CroppingTrapezoid.class.getSimpleName();
    private final float[] mPoints = new float[8];
    private final float[] mMappedPoints = new float[8];
    private final Rect mImageRect;

    public CroppingTrapezoid(ArrayList<Point> cropRect, Rect imageRect) {

        Log.w("myApp", "from inside CroppingTrapezoid ");
        /*
        mImageRect = new Rect(imageRect);
        mPoints[0] = cropRect.left;
        mPoints[1] = cropRect.top;
        mPoints[2] = cropRect.right;
        mPoints[3] = cropRect.top;
        mPoints[4] = cropRect.right;
        mPoints[5] = cropRect.bottom;
        mPoints[6] = cropRect.left;
        mPoints[7] = cropRect.bottom;
            
        */

        // below part added by minesh, on 17/03/2016
        mImageRect = new Rect(imageRect);
        mPoints[0] = (float) cropRect.get(0).x;
        mPoints[1] = (float) cropRect.get(0).y;
        mPoints[2] = (float) cropRect.get(3).x;
        mPoints[3] = (float) cropRect.get(3).y;
        mPoints[4] = (float) cropRect.get(2).x;
        mPoints[5] = (float) cropRect.get(2).y;
        mPoints[6] = (float) cropRect.get(1).x;
        mPoints[7] = (float) cropRect.get(1).y;

        Log.w("myApp", "mPoints from constr of trpzd points are");
        Log.w("myApp", "p0 " + mPoints[0]);
        Log.w("myApp", "p1 " + mPoints[1]);
        Log.w("myApp", "p2 " + mPoints[2]);
        Log.w("myApp", "p3 " + mPoints[3]);
        Log.w("myApp", "p4 " + mPoints[4]);
        Log.w("myApp", "p5 " + mPoints[5]);
        Log.w("myApp", "p6 " + mPoints[6]);
        Log.w("myApp", "p7 " + mPoints[7]);

    }

    public Rect getBoundingRect() {

        Log.w("myApp", "inside cropTrp.getBoundingrect");
        return getBoundingRect(mPoints);

    }

    private float[] getBoundingPoints(Matrix matrix) {

        Log.w("myApp", "inside cropTrp.getBoundingpoints");
        final Rect boundingRect = getBoundingRect(mPoints);
        float[] points = new float[4];
        points[0] = boundingRect.left;
        points[1] = boundingRect.top;
        points[2] = boundingRect.right;
        points[3] = boundingRect.bottom;
        matrix.mapPoints(points);
        return points;
    }

    public Rect getPerspectiveCorrectedBoundingRect() {
        float[] p = mMappedPoints;
        System.arraycopy(mPoints, 0, p, 0, 8);
        float w1 = p[2] - p[0];
        float w2 = p[4] - p[6];
        float h1 = p[7] - p[1];
        float h2 = p[5] - p[3];
        float diffH = w1 - w2;
        float diffV = h1 - h2;
        if (diffH < 0) {
            float scale = (Math.abs(diffH) + w2) / w2;
            h1 *= (scale);
            h2 *= (scale);
            //move top up
            p[1] = p[7] - h1;
            p[3] = p[5] - h2;
        } else {
            float scale = (diffH + w1) / w1;
            h1 *= scale;
            h2 *= scale;
            //move bottom down
            p[7] = p[1] + h1;
            p[5] = p[3] + h2;
        }
        if (diffV < 0) {
            float scale = (Math.abs(diffV) + h2) / h2;
            w1 *= scale;
            w2 *= scale;
            //move left to left
            p[0] = p[2] - w1;
            p[6] = p[4] - w2;
        } else {
            float scale = (diffV + h1) / h1;
            w1 *= scale;
            w2 *= scale;
            //move right to right
            p[2] = p[0] + w1;
            p[4] = p[6] + w2;
        }
        return getBoundingRect(mMappedPoints);
    }

    public Rect getBoundingRect(Matrix matrix) {
        float[] points = getBoundingPoints(matrix);
        int left = (int) Math.min(points[0], points[2]);
        int right = (int) Math.max(points[0], points[2]);
        int top = (int) Math.min(points[1], points[3]);
        int bottom = (int) Math.max(points[1], points[3]);

        return new Rect(left, top, right, bottom);
    }

    public float[] getScreenPoints(Matrix matrix) {

        Log.w("myApp", "mPoints insode getscreen  points are");
        Log.w("myApp", "p0 " + mPoints[0]);
        Log.w("myApp", "p1 " + mPoints[1]);
        Log.w("myApp", "p2 " + mPoints[2]);
        Log.w("myApp", "p3 " + mPoints[3]);
        Log.w("myApp", "p4 " + mPoints[4]);
        Log.w("myApp", "p5 " + mPoints[5]);
        Log.w("myApp", "p6 " + mPoints[6]);
        Log.w("myApp", "p7 " + mPoints[7]);

        matrix.mapPoints(mMappedPoints, mPoints);

        //mappedpoints hold the screepoints based on which the trapezoid can be drawn
        return mMappedPoints;
    }

    public float[] getPoints() {
        return mPoints;
    }

    public Point getTopLeft() {
        return new Point((int) mPoints[0], (int) mPoints[1]);
    }

    public Point getTopRight() {
        return new Point((int) mPoints[2], (int) mPoints[3]);
    }

    public Point getBottomRight() {
        return new Point((int) mPoints[4], (int) mPoints[5]);
    }

    public Point getBottomLeft() {
        return new Point((int) mPoints[6], (int) mPoints[7]);
    }

    // moves the cropping trapezoid by (dx, dy) in image space.
    public void moveBy(float dx, float dy) {
        final Rect boundingRect = getBoundingRect();
        dx = capDx(dx, boundingRect);
        dy = capDy(dy, boundingRect);

        for (int i = 0; i < 8; i += 2) {
            mPoints[i] += dx;
            mPoints[i + 1] += dy;
        }
        capPoints(HighlightView.GROW_NONE);
    }

    private float capDy(float dy, Rect boundingRect) {
        if ((boundingRect.bottom + dy) >= mImageRect.bottom) {
            dy = mImageRect.bottom - boundingRect.bottom;
        } else if ((boundingRect.top + dy) <= mImageRect.top) {
            dy = mImageRect.top - boundingRect.top;
        }
        return dy;
    }

    private float capDx(float dx, Rect boundingRect) {
        if ((boundingRect.right + dx) >= mImageRect.right) {
            dx = mImageRect.right - boundingRect.right;
        } else if (mImageRect.left >= (boundingRect.left + dx)) {
            dx = mImageRect.left - boundingRect.left;
        }
        return dx;
    }

    // Grows the cropping trapezoid by (dx, dy) in image space.
    public void growBy(int edge, float dx, float dy) {
        //        final Rect boundingRect = getBoundingRect();
        //        dx = capDx(dx, boundingRect);
        //        dy = capDy(dy, boundingRect);

        if ((HighlightView.GROW_LEFT_EDGE | HighlightView.GROW_TOP_EDGE) == edge) {
            mPoints[0] += dx;
            mPoints[1] += dy;
            capPoints(edge);
            return;
        }
        if ((HighlightView.GROW_RIGHT_EDGE | HighlightView.GROW_TOP_EDGE) == edge) {
            mPoints[2] += dx;
            mPoints[3] += dy;
            capPoints(edge);
            return;
        }
        if ((HighlightView.GROW_RIGHT_EDGE | HighlightView.GROW_BOTTOM_EDGE) == edge) {
            mPoints[4] += dx;
            mPoints[5] += dy;
            capPoints(edge);
            return;
        }
        if ((HighlightView.GROW_LEFT_EDGE | HighlightView.GROW_BOTTOM_EDGE) == edge) {
            mPoints[6] += dx;
            mPoints[7] += dy;
            capPoints(edge);
            return;
        }
        if ((HighlightView.GROW_LEFT_EDGE) == edge) {
            mPoints[0] += dx;
            mPoints[1] += dy;
            mPoints[6] += dx;
            mPoints[7] += dy;
        }
        if ((HighlightView.GROW_RIGHT_EDGE) == edge) {
            mPoints[2] += dx;
            mPoints[3] += dy;
            mPoints[4] += dx;
            mPoints[5] += dy;
        }
        if ((HighlightView.GROW_TOP_EDGE) == edge) {
            mPoints[0] += dx;
            mPoints[1] += dy;
            mPoints[2] += dx;
            mPoints[3] += dy;
        }
        if ((HighlightView.GROW_BOTTOM_EDGE) == edge) {
            mPoints[4] += dx;
            mPoints[5] += dy;
            mPoints[6] += dx;
            mPoints[7] += dy;
        }

        capPoints(edge);
    }

    public int getHit(float x, float y, float hysteresis) {
        int retval = HighlightView.GROW_NONE;

        final boolean touchesTopLeft = calculateDistanceToPoint(mPoints[0], mPoints[1], x, y) <= hysteresis;
        if (touchesTopLeft) {
            Log.i(LOG_TAG, "top left");
            return HighlightView.GROW_LEFT_EDGE | HighlightView.GROW_TOP_EDGE;
        }
        final boolean touchesTopRight = calculateDistanceToPoint(mPoints[2], mPoints[3], x, y) <= hysteresis;
        if (touchesTopRight) {
            Log.i(LOG_TAG, "top right");
            return HighlightView.GROW_RIGHT_EDGE | HighlightView.GROW_TOP_EDGE;
        }
        final boolean touchesBottomRight = calculateDistanceToPoint(mPoints[4], mPoints[5], x, y) <= hysteresis;
        if (touchesBottomRight) {
            Log.i(LOG_TAG, "bottom right");
            return HighlightView.GROW_RIGHT_EDGE | HighlightView.GROW_BOTTOM_EDGE;
        }
        final boolean touchesBottomLeft = calculateDistanceToPoint(mPoints[6], mPoints[7], x, y) <= hysteresis;
        if (touchesBottomLeft) {
            Log.i(LOG_TAG, "bottom left");
            return HighlightView.GROW_LEFT_EDGE | HighlightView.GROW_BOTTOM_EDGE;
        }

        final double topDistance = calculateDistanceToLine(mPoints[0], mPoints[1], mPoints[2], mPoints[3], x, y);
        if (topDistance <= hysteresis) {
            Log.i(LOG_TAG, "top");
            retval |= HighlightView.GROW_TOP_EDGE;
        }
        final double rightDistance = calculateDistanceToLine(mPoints[2], mPoints[3], mPoints[4], mPoints[5], x, y);
        if (rightDistance <= hysteresis) {
            Log.i(LOG_TAG, "right");
            retval |= HighlightView.GROW_RIGHT_EDGE;
        }
        final double bottomDistance = calculateDistanceToLine(mPoints[6], mPoints[7], mPoints[4], mPoints[5], x, y);
        if (bottomDistance <= hysteresis) {
            Log.i(LOG_TAG, "bottom");
            retval |= HighlightView.GROW_BOTTOM_EDGE;
        }
        final double leftDistance = calculateDistanceToLine(mPoints[0], mPoints[1], mPoints[6], mPoints[7], x, y);
        if (leftDistance <= hysteresis) {
            Log.i(LOG_TAG, "left");
            retval |= HighlightView.GROW_LEFT_EDGE;
        }

        // Not near any edge but maybe inside the trapezoid
        if (retval == HighlightView.GROW_NONE) {
            //check if it is inside the trapezoid
            float xCross = calculateXCrossing(mPoints[2], mPoints[3], mPoints[4], mPoints[5], x, y);
            if (xCross < (x - hysteresis)) {
                //point is outside to right of trapezoid
                return retval;
            }
            xCross = calculateXCrossing(mPoints[0], mPoints[1], mPoints[6], mPoints[7], x, y);
            if (xCross > (x + hysteresis)) {
                //point is outside to left of trapezoid
                return retval;
            }
            float yCross = calculateYCrossing(mPoints[0], mPoints[1], mPoints[2], mPoints[3], x, y);
            if (yCross > (y + hysteresis)) {
                //point is outside to the top of trapezoid
                return retval;
            }
            yCross = calculateYCrossing(mPoints[4], mPoints[5], mPoints[6], mPoints[7], x, y);
            if (yCross < (y - hysteresis)) {
                //point is outside to the bottom of trapezoid
                return retval;
            }
            Log.i(LOG_TAG, "move");
            retval = HighlightView.MOVE;
        }

        return retval;
    }

    private Rect getBoundingRect(float[] p) {
        //return new Rect(Math.round(r.left), Math.round(r.top), Math.round(r.right), Math.round(r.bottom));

        int left = (int) Math.min(p[0], p[6]);
        int right = (int) Math.max(p[2], p[4]);
        int top = (int) Math.min(p[1], p[3]);
        int bottom = (int) Math.max(p[5], p[7]);

        return new Rect(left, top, right, bottom);
    }

    private void capPoints(final int edge) {
        mPoints[0] = Math.max(0, mPoints[0]); //left
        mPoints[1] = Math.max(0, mPoints[1]); //top
        mPoints[2] = Math.min(mImageRect.right, mPoints[2]); //right
        mPoints[3] = Math.max(0, mPoints[3]); //top
        mPoints[4] = Math.min(mImageRect.right, mPoints[4]); //right
        mPoints[5] = Math.min(mImageRect.bottom, mPoints[5]); //bottom
        mPoints[6] = Math.max(0, mPoints[6]); //left
        mPoints[7] = Math.min(mImageRect.bottom, mPoints[7]); //bottom
        //lef top always to left of right top
        final float cap = 50f;
        final float leftBound = Math.max(mPoints[0], mPoints[6]) + cap;
        final float rightBound = Math.min(mPoints[2], mPoints[4]) - cap;
        final float topBound = Math.max(mPoints[1], mPoints[3]) + cap;
        final float bottomBound = Math.min(mPoints[7], mPoints[5]) - cap;

        if ((HighlightView.GROW_LEFT_EDGE & edge) > 0) {
            mPoints[0] = Math.min(mPoints[0], rightBound);
            mPoints[6] = Math.min(mPoints[6], rightBound);
        }
        if ((HighlightView.GROW_RIGHT_EDGE & edge) > 0) {
            mPoints[2] = Math.max(mPoints[2], leftBound);
            mPoints[4] = Math.max(mPoints[4], leftBound);
        }
        if ((HighlightView.GROW_TOP_EDGE & edge) > 0) {
            mPoints[1] = Math.min(mPoints[1], bottomBound);
            mPoints[3] = Math.min(mPoints[3], bottomBound);
        }
        if ((HighlightView.GROW_BOTTOM_EDGE & edge) > 0) {
            mPoints[7] = Math.max(mPoints[7], topBound);
            mPoints[5] = Math.max(mPoints[5], topBound);
        }

    }

    private double calculateDistanceToLine(float x1, float y1, float x2, float y2, float x, float y) {
        if ((x > x1 && x < x2) || (y > y1 && y < y2)) {
            if (x1 == x2) {
                return Math.abs(x1 - x);
            }
            float mTop = getRiseOfLine(x1, y1, x2, y2);
            float nTop = getYCrossingOfLine(x1, y1, mTop);
            if (mTop == 0) {
                return Math.abs(nTop - y);
            }
            float mCross = -1 / mTop;
            float nCross = getYCrossingOfLine(x, y, mCross);
            float xCross = (nTop - nCross) / (mCross - mTop);
            float yCross = mCross * xCross + nCross;
            return calculateDistanceToPoint(xCross, yCross, x, y);
        } else {
            return Double.MAX_VALUE;
        }
    }

    private double calculateDistanceToPoint(float x1, float y1, float x, float y) {
        return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
    }

    private float calculateXCrossing(float x1, float y1, float x2, float y2, float x, float y) {
        if (x1 == x2) {
            return x1;
        }
        float mTop = getRiseOfLine(x1, y1, x2, y2);
        float nTop = getYCrossingOfLine(x1, y1, mTop);
        float xCross = getXOnLine(y, mTop, nTop);
        return xCross;
    }

    private float getXOnLine(float y, float mTop, float nTop) {
        return (y - nTop) / mTop;
    }

    private float calculateYCrossing(float x1, float y1, float x2, float y2, float x, float y) {
        if (y1 == y2) {
            return y1;
        }
        float mTop = getRiseOfLine(x1, y1, x2, y2);
        float nTop = getYCrossingOfLine(x1, y1, mTop);
        float xCross = getXOnLine(y, mTop, nTop);
        return mTop * xCross + nTop;
    }

    private float getYCrossingOfLine(float x1, float y1, float mTop) {
        return y1 - mTop * x1;
    }

    private float getRiseOfLine(float x1, float y1, float x2, float y2) {
        return (y1 - y2) / (x1 - x2);
    }

}