判断点在任意矩形内

最近写蒙版工具的时候,需要将蒙版中心点限制在视频可视区域内,可是视频又可以旋转缩放和平移,因此就转换成判断中心点在任意矩形内,研究了几种方案,仅供参考。

通过Path构建Region判断

首先根据提供的矩形的四个顶点生成Path:

public void setBounds(List<PointF> points) {
    mPath.moveTo(points.get(0).x, points.get(0).y);
    mPath.lineTo(points.get(1).x, points.get(1).y);
    mPath.lineTo(points.get(2).x, points.get(2).y);
    mPath.lineTo(points.get(3).x, points.get(3).y);
    mPath.close();
}

然后根据Path构建对应的Region对象:

mRegion = new Region();
RectF rect = new RectF();
mPath.computeBounds(rect, true);
this.mRegion.setPath(mPath, new Region((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom));

最后判断点是否包含在区域中:

 @Override
 public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        mTouchX = event.getX();
        mTouchY = event.getY();
    } else if (action == MotionEvent.ACTION_MOVE) {
        float x = event.getX();
        float y = event.getY();
        float dx = x - mTouchX;
        float dy = y - mTouchY;
        mTouchX = x;
        mTouchY = y;
        if (mRegion.contains((int) (mCenterPoint.x + dx), (int) (mCenterPoint.y + dy))) {
            mCenterPoint.offset(dx, dy);
            invalidate();
        }
    }
    return true;
}

反旋转

将点反向旋转矩形的旋转角度,然后与未旋转的矩形进行判断。
下面的方法是一个点绕另一个点旋转以后得到新的点:

private PointF rotateByAngle(PointF point, PointF center, float angle) {
    PointF rotatedPoint = new PointF();
    double radians = Math.toRadians(angle);
    double cos = Math.cos(radians);
    double sin = Math.sin(radians);
    rotatedPoint.x = (float) ((point.x - center.x) * cos - (point.y - center.y) * sin + center.x);
    rotatedPoint.y = (float) ((point.x - center.x) * sin + (point.y - center.y) * cos + center.y);
    return rotatedPoint;
}

首先将矩形的四个点进行反转:

public void setBounds(List<PointF> points, float rotation) {
    mRotation = rotation;
    mPivot.set((points.get(0).x + points.get(2).x) / 2f, (points.get(0).y + points.get(2).y) / 2f);
    mCenterPoint.set(mPivot);
    PointF leftTop = rotateByAngle(points.get(0), mPivot, -rotation);
    PointF leftBottom = rotateByAngle(points.get(1), mPivot, -rotation);
    PointF rightBottom = rotateByAngle(points.get(2), mPivot, -rotation);
    PointF rightTop = rotateByAngle(points.get(3), mPivot, -rotation);
    mRotatedRect = new RectF();
    mRotatedRect.left = (leftTop.x + leftBottom.x) / 2f;
    mRotatedRect.top = (leftTop.y + rightTop.y) / 2f;
    mRotatedRect.right = (rightTop.x + rightBottom.x) / 2f;
    mRotatedRect.bottom = (leftBottom.y + rightBottom.y) / 2f;
    mBoundSize = new SizeF(rightBottom.x - leftTop.x, rightBottom.y - leftTop.y);
}

然后判断点是否在区域内:

@Override
public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        mTouchX = event.getX();
        mTouchY = event.getY();
    } else if (action == MotionEvent.ACTION_MOVE) {
        float x = event.getX();
        float y = event.getY();
        float dx = x - mTouchX;
        float dy = y - mTouchY;
        mTouchX = x;
        mTouchY = y;
        mCenterPoint.offset(dx, dy);
        PointF rc = rotateByAngle(mCenterPoint, mPivot, -mRotation);
        if (rc.x < mRotatedRect.left) {
            rc.x = mRotatedRect.left;
        } else if (rc.x > mRotatedRect.right) {
            rc.x = mRotatedRect.right;
        }

        if (rc.y < mRotatedRect.top) {
            rc.y = mRotatedRect.top;
        } else if (rc.y > mRotatedRect.bottom) {
            rc.y = mRotatedRect.bottom;
        }

        PointF point = rotateByAngle(rc, mPivot, mRotation);
        mCenterPoint.set(point);
        invalidate();
    }
    return true;
}

向量

只需要判断该点是否在四条边之间就行。利用向量叉乘的方向性,来判断两叉乘向量是否同向,效率更高。
判断两叉乘向量是否同向可以用点乘实现,如果点乘大于0,则两向量同向,如果点乘小于0,则两向量反向,如果点乘等于0,则有一叉乘向量为0向量。

( p 1 p 2 ⃗ \vec{p1p2} p1p2 X p 1 p ⃗ \vec{p1p} p1p ) * ( p 3 p 4 ⃗ \vec{p3p4} p3p4 X p 3 p ⃗ \vec{p3p} p3p ) >= 0
说明p在p1p2,p3p4中间夹着, 同理计算另两边
( p 1 p 2 ⃗ \vec{p1p2} p1p2 X p 1 p ⃗ \vec{p1p} p1p ) * ( p 3 p 4 ⃗ \vec{p3p4} p3p4 X p 3 p ⃗ \vec{p3p} p3p ) >= 0 && ( p 2 p 3 ⃗ \vec{p2p3} p2p3 X p 2 p ⃗ \vec{p2p} p2p ) * ( p 4 p 1 ⃗ \vec{p4p1} p4p1 X p 4 p ⃗ \vec{p4p} p4p ) >= 0

	public class Point  {
        public int x;
        public int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    public static double getCross(Point p, Point p1, Point p2) {
        return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y);
    }

    public static boolean isPointInMatrix(Point p, Point p1, Point p2, Point p3, Point p4) {
        boolean h = getCross(p, p1, p2) * getCross(p, p3, p4) >= 0;
        boolean v = getCross(p, p2, p3) * getCross(p, p4, p1) >= 0;
        return h && v;
    }

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值