[Bf-blender-cvs] [5f7fd04] master: BMesh: improve BM_face_splits_check_legal

Campbell Barton noreply at git.blender.org
Wed Jul 20 01:56:43 CEST 2016


Commit: 5f7fd0444dfded5a7fddd4fd9de30076b3a6bfeb
Author: Campbell Barton
Date:   Wed Jul 20 07:48:36 2016 +1000
Branches: master
https://developer.blender.org/rB5f7fd0444dfded5a7fddd4fd9de30076b3a6bfeb

BMesh: improve BM_face_splits_check_legal

- remove edge scaling, instead avoid checking intersections with connected edges.
- replace local line intersection functions with BLI_math
- center the projection for more precise calculation.

===================================================================

M	source/blender/bmesh/intern/bmesh_polygon.c

===================================================================

diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 08e9704..fa46c56 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -48,30 +48,6 @@
 #include "intern/bmesh_private.h"
 
 /**
- * \brief TEST EDGE SIDE and POINT IN TRIANGLE
- *
- * Point in triangle tests stolen from scanfill.c.
- * Used for tessellator
- */
-
-static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2])
-{
-	/* is v3 to the right of v1 - v2 ? With exception: v3 == v1 || v3 == v2 */
-	const float inp =
-	        ((v2[0] - v1[0]) * (v1[1] - v3[1])) +
-	        ((v1[1] - v2[1]) * (v1[0] - v3[0]));
-
-	if (inp < 0.0) {
-		return false;
-	}
-	else if (inp == 0) {
-		if (v1[0] == v3[0] && v1[1] == v3[1]) return false;
-		if (v2[0] == v3[0] && v2[1] == v3[1]) return false;
-	}
-	return true;
-}
-
-/**
  * \brief COMPUTE POLY NORMAL (BMFace)
  *
  * Same as #normal_poly_v3 but operates directly on a bmesh face.
@@ -602,29 +578,6 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
 }
 
 /**
- * \brief BM LEGAL EDGES
- *
- * takes in a face and a list of edges, and sets to NULL any edge in
- * the list that bridges a concave region of the face or intersects
- * any of the faces's edges.
- */
-static void scale_edge_v2f(float v1[2], float v2[2], const float fac)
-{
-	float mid[2];
-
-	mid_v2_v2v2(mid, v1, v2);
-
-	sub_v2_v2v2(v1, v1, mid);
-	sub_v2_v2v2(v2, v2, mid);
-
-	mul_v2_fl(v1, fac);
-	mul_v2_fl(v2, fac);
-
-	add_v2_v2v2(v1, v1, mid);
-	add_v2_v2v2(v2, v2, mid);
-}
-
-/**
  * \brief POLY ROTATE PLANE
  *
  * Rotates a polygon so that it's
@@ -909,67 +862,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
 	BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
 }
 
-/* detects if two line segments cross each other (intersects).
- * note, there could be more winding cases then there needs to be. */
-static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
-{
-
-#define GETMIN2_AXIS(a, b, ma, mb, axis)   \
-	{                                      \
-		ma[axis] = min_ff(a[axis], b[axis]); \
-		mb[axis] = max_ff(a[axis], b[axis]); \
-	} (void)0
-
-#define GETMIN2(a, b, ma, mb)          \
-	{                                  \
-		GETMIN2_AXIS(a, b, ma, mb, 0); \
-		GETMIN2_AXIS(a, b, ma, mb, 1); \
-	} (void)0
-
-#define EPS (FLT_EPSILON * 15)
-
-	int w1, w2, w3, w4, w5 /*, re */;
-	float mv1[2], mv2[2], mv3[2], mv4[2];
-	
-	/* now test winding */
-	w1 = testedgesidef(v1, v3, v2);
-	w2 = testedgesidef(v2, v4, v1);
-	w3 = !testedgesidef(v1, v2, v3);
-	w4 = testedgesidef(v3, v2, v4);
-	w5 = !testedgesidef(v3, v1, v4);
-	
-	if (w1 == w2 && w2 == w3 && w3 == w4 && w4 == w5) {
-		return true;
-	}
-	
-	GETMIN2(v1, v2, mv1, mv2);
-	GETMIN2(v3, v4, mv3, mv4);
-	
-	/* do an interval test on the x and y axes */
-	/* first do x axis */
-	if (fabsf(v1[1] - v2[1]) < EPS &&
-	    fabsf(v3[1] - v4[1]) < EPS &&
-	    fabsf(v1[1] - v3[1]) < EPS)
-	{
-		return (mv4[0] >= mv1[0] && mv3[0] <= mv2[0]);
-	}
-
-	/* now do y axis */
-	if (fabsf(v1[0] - v2[0]) < EPS &&
-	    fabsf(v3[0] - v4[0]) < EPS &&
-	    fabsf(v1[0] - v3[0]) < EPS)
-	{
-		return (mv4[1] >= mv1[1] && mv3[1] <= mv2[1]);
-	}
-
-	return false;
-
-#undef GETMIN2_AXIS
-#undef GETMIN2
-#undef EPS
-
-}
-
 /**
  *  BM POINT IN FACE
  *
@@ -1267,121 +1159,103 @@ void BM_face_triangulate(
  */
 void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
 {
-	const int len2 = len * 2;
-	BMLoop *l;
-	float v1[2], v2[2], v3[2], mid[2], *p1, *p2, *p3, *p4;
 	float out[2] = {-FLT_MAX, -FLT_MAX};
+	float center[2] = {0.0f, 0.0f};
 	float axis_mat[3][3];
 	float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
-	float (*edgeverts)[2] = BLI_array_alloca(edgeverts, len2);
-	float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
-	int i, j, a = 0, clen;
+	const float *(*edgeverts)[2] = BLI_array_alloca(edgeverts, len);
+	BMLoop *l;
+	int i, i_prev, j;
 
 	BLI_assert(BM_face_is_normal_valid(f));
 
 	axis_dominant_v3_to_m3(axis_mat, f->no);
 
 	for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
-		BM_elem_index_set(l, i);  /* set_dirty */
 		mul_v2_m3v3(projverts[i], axis_mat, l->v->co);
+		add_v2_v2(center, projverts[i]);
 	}
-	bm->elem_index_dirty |= BM_LOOP;
 
 	/* first test for completely convex face */
 	if (is_poly_convex_v2((const float (*)[2])projverts, f->len)) {
 		return;
 	}
 
+	mul_v2_fl(center, 1.0f / f->len);
+
 	for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
+		BM_elem_index_set(l, i);  /* set_dirty */
+
+		/* center the projection for maximum accuracy */
+		sub_v2_v2(projverts[i], center);
+
 		out[0] = max_ff(out[0], projverts[i][0]);
 		out[1] = max_ff(out[1], projverts[i][1]);
 	}
+	bm->elem_index_dirty |= BM_LOOP;
 	
 	/* ensure we are well outside the face bounds (value is arbitrary) */
 	add_v2_fl(out, 1.0f);
 
 	for (i = 0; i < len; i++) {
-		copy_v2_v2(edgeverts[a + 0], projverts[BM_elem_index_get(loops[i][0])]);
-		copy_v2_v2(edgeverts[a + 1], projverts[BM_elem_index_get(loops[i][1])]);
-		scale_edge_v2f(edgeverts[a + 0], edgeverts[a + 1], fac2);
-		a += 2;
+		edgeverts[i][0] = projverts[BM_elem_index_get(loops[i][0])];
+		edgeverts[i][1] = projverts[BM_elem_index_get(loops[i][1])];
 	}
 
 	/* do convexity test */
 	for (i = 0; i < len; i++) {
-		copy_v2_v2(v2, edgeverts[i * 2 + 0]);
-		copy_v2_v2(v3, edgeverts[i * 2 + 1]);
-
-		mid_v2_v2v2(mid, v2, v3);
+		float mid[2];
+		mid_v2_v2v2(mid, edgeverts[i][0], edgeverts[i][1]);
 		
-		clen = 0;
-		for (j = 0; j < f->len; j++) {
-			p1 = projverts[j];
-			p2 = projverts[(j + 1) % f->len];
-			
-#if 0
-			copy_v2_v2(v1, p1);
-			copy_v2_v2(v2, p2);
-
-			scale_edge_v2f(v1, v2, fac1);
-			if (line_crosses_v2f(v1, v2, mid, out)) {
-				clen++;
-			}
-#else
-			if (line_crosses_v2f(p1, p2, mid, out)) {
-				clen++;
+		int isect = 0;
+		int j_prev;
+		for (j = 0, j_prev = f->len - 1; j < f->len; j_prev = j++) {
+			const float *f_edge[2] = {projverts[j_prev], projverts[j]};
+			if (isect_seg_seg_v2(UNPACK2(f_edge), mid, out) == ISECT_LINE_LINE_CROSS) {
+				isect++;
 			}
-#endif
 		}
 
-		if (clen % 2 == 0) {
+		if (isect % 2 == 0) {
 			loops[i][0] = NULL;
 		}
 	}
 
-	/* do line crossing tests */
-	for (i = 0; i < f->len; i++) {
-		p1 = projverts[i];
-		p2 = projverts[(i + 1) % f->len];
-		
-		copy_v2_v2(v1, p1);
-		copy_v2_v2(v2, p2);
-
-		scale_edge_v2f(v1, v2, fac1);
+#define EDGE_SHARE_VERT(e1, e2) \
+	((ELEM((e1)[0], (e2)[0], (e2)[1])) || \
+	 (ELEM((e2)[0], (e1)[0], (e1)[1])))
 
+	/* do line crossing tests */
+	for (i = 0, i_prev = f->len - 1; i < f->len; i_prev = i++) {
+		const float *f_edge[2] = {projverts[i_prev], projverts[i]};
 		for (j = 0; j < len; j++) {
-			if (!loops[j][0]) {
-				continue;
-			}
-
-			p3 = edgeverts[j * 2];
-			p4 = edgeverts[j * 2 + 1];
-
-			if (line_crosses_v2f(v1, v2, p3, p4)) {
-				loops[j][0] = NULL;
+			if ((loops[j][0] != NULL) &&
+			    !EDGE_SHARE_VERT(f_edge, edgeverts[j]))
+			{
+				if (isect_seg_seg_v2(UNPACK2(f_edge), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+					loops[j][0] = NULL;
+				}
 			}
 		}
 	}
 
+	/* self intersect tests */
 	for (i = 0; i < len; i++) {
-		for (j = 0; j < len; j++) {
-			if (j != i && loops[i][0] && loops[j][0]) {
-				p1 = edgeverts[i * 2];
-				p2 = edgeverts[i * 2 + 1];
-				p3 = edgeverts[j * 2];
-				p4 = edgeverts[j * 2 + 1];
-
-				copy_v2_v2(v1, p1);
-				copy_v2_v2(v2, p2);
-
-				scale_edge_v2f(v1, v2, fac1);
-
-				if (line_crosses_v2f(v1, v2, p3, p4)) {
-					loops[i][0] = NULL;
+		if (loops[i][0]) {
+			for (j = i + 1; j < len; j++) {
+				if ((loops[j][0] != NULL) &&
+				    !EDGE_SHARE_VERT(edgeverts[i], edgeverts[j]))
+				{
+					if (isect_seg_seg_v2(UNPACK2(edgeverts[i]), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+						loops[i][0] = NULL;
+						break;
+					}
 				}
 			}
 		}
 	}
+
+#undef EDGE_SHARE_VERT
 }
 
 /**




More information about the Bf-blender-cvs mailing list