Android 自定義view中如何判斷一個點是否在 經過旋轉的 RectF 內?

最近在做相冊的圖片編輯功能,遇到一個bug,插入文字後旋轉文字區域,點擊文字區域無法觸發,分析原因是判斷時認定爲點沒在RectF內。如圖:

在這裏插入圖片描述

如果只是通過rect.contains(x, y)來判斷,那麼實際區域則是綠色區域的部分,則有部分無法點擊,如下圖:
在這裏插入圖片描述
因此需要將矩形框旋轉。

如果通過matrix.mapRect(rect)來獲取轉換後的區域,再通過rect.contains(x, y)來判斷是否落在區域內,那麼實際區域如下圖綠色區域,則點擊非區域內的位置仍會觸發文字區域的點擊,如下圖:

Matrix matrix = new Matrix();
matrix.setRotate(roatetAngle, mHelpBoxRect.centerX(), mHelpBoxRect.centerY());
matrix.mapRect(mHelpBoxRect);

在這裏插入圖片描述
因此,無法通過rect.contains(x, y)來判斷點是否落在區域內。需要將原矩形四個頂點旋轉,將轉換後的矩形四個頂點重新構成四邊形,再判斷點是否落在該四邊形內。

public boolean clickHelpBoxRect(float x, float y) {
		if (mHelpBoxRect == null || mHelpBoxRect.isEmpty()) {
			return false;
		}
		boolean isClickHelpBoxRect;
		if (roatetAngle != 0) {
			// 旋轉後判斷點是否在四邊形內
			Matrix matrix = new Matrix();
			matrix.setRotate(roatetAngle, mHelpBoxRect.centerX(), mHelpBoxRect.centerY());

			PointF curPoint = new PointF(x, y);

			PointF pointLT = getMapPoints(matrix, mHelpBoxRect.left, mHelpBoxRect.top);
			PointF pointRT = getMapPoints(matrix, mHelpBoxRect.right, mHelpBoxRect.top);
			PointF pointLB = getMapPoints(matrix, mHelpBoxRect.left, mHelpBoxRect.bottom);
			PointF pointRB = getMapPoints(matrix, mHelpBoxRect.right, mHelpBoxRect.bottom);
			isClickHelpBoxRect = pointInRect(curPoint, pointLT, pointRT, pointLB, pointRB);
		} else {
			isClickHelpBoxRect = mHelpBoxRect.contains(x, y);
		}
		return isClickHelpBoxRect;
	}

	/**
	 * 獲取旋轉後的座標點
	 *
	 * @param matrix 轉換矩陣
	 * @param x      左座標
	 * @param y      右座標
	 * @return
	 */
	private PointF getMapPoints(Matrix matrix, float x, float y) {
		float[] floats = new float[]{x, y};
		matrix.mapPoints(floats);
		return new PointF(floats[0], floats[1]);
	}

	/**
	 * 點是否落在四邊形內
	 *
	 * @param curPoint 點擊位置
	 * @param pointLT  左上頂點
	 * @param pointRT  右上頂點
	 * @param pointLB  左下頂點
	 * @param pointRB  右下頂點
	 * @return true 在四邊形內;false 不在四邊形內
	 */
	private boolean pointInRect(PointF curPoint, PointF pointLT, PointF pointRT, PointF pointLB, PointF pointRB) {
		int nCount = 4;
		PointF[] rectPoints = new PointF[]{pointLT, pointLB, pointRB, pointRT};
		int nCross = 0;
		for (int i = 0; i < nCount; i++) {
			//依次取相鄰的兩個點
			PointF pStart = rectPoints[i];
			PointF pEnd = rectPoints[(i + 1) % nCount];

			//相鄰的兩個點是平行於x軸的,肯定不相交,忽略
			if (pStart.y == pEnd.y)
				continue;

			//交點在pStart,pEnd的延長線上,pCur肯定不會與pStart.pEnd相交,忽略
			if (curPoint.y < Math.min(pStart.y, pEnd.y) || curPoint.y > Math.max(pStart.y, pEnd.y))
				continue;

			//求當前點和x軸的平行線與pStart,pEnd直線的交點的x座標
			double x = (double) (curPoint.y - pStart.y) * (double) (pEnd.x - pStart.x) / (double) (pEnd.y - pStart.y) + pStart.x;

			//若x座標大於當前點的座標,則有交點
			if (x > curPoint.x)
				nCross++;
		}

		// 單邊交點爲偶數,點在多邊形之外
		return (nCross % 2 == 1);
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章