[Bf-committers] Updated: Knife subdivide patch

Matthew H. Plough mplough at Princeton.EDU
Fri Mar 4 23:54:35 CET 2005


Skipped content of type multipart/alternative-------------- next part --------------
Index: source/blender/src/editmesh_loop.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/src/editmesh_loop.c,v
retrieving revision 1.11
diff -u -r1.11 editmesh_loop.c
--- source/blender/src/editmesh_loop.c	28 Dec 2004 05:38:56 -0000	1.11
+++ source/blender/src/editmesh_loop.c	4 Mar 2005 22:45:29 -0000
@@ -400,6 +400,10 @@
 	short  y;
 } CutCurve;
 
+typedef struct CutFloat {
+	float co[3];
+} CutFloat;
+
 CutCurve *get_mouse_trail(int *len, char mode){
 
 	CutCurve *curve,*temp;
@@ -540,15 +544,19 @@
 
 /* prototype */
 short seg_intersect(struct EditEdge * e, CutCurve *c, int len);
+CutFloat *persp_cut_init(CutCurve *c, int len);
+short persp_intersect(EditEdge *e, CutFloat *c, int len);
+float line_band_intersect(float p0[3], float p1[3], float r0[3], float r1[3], float r2[3]);
 
 void KnifeSubdivide(char mode)
 {
 	EditMesh *em = G.editMesh;
 	int oldcursor, len=0;
 	short isect=0;
-	CutCurve *curve;		
-	EditEdge *eed; 
-	Window *win;	
+	CutCurve *curve;
+	CutFloat *curve_f = 1;
+	EditEdge *eed;
+	Window *win;
 	
 	if (G.obedit==0) return;
 
@@ -560,7 +568,7 @@
 	if (mode==KNIFE_PROMPT) {
 		short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2");
 		if(val<1) return;
-		mode= val;	// warning, mode is char, pupmenu returns -1 with ESC
+		mode= val;	/* warning, mode is char, pupmenu returns -1 with ESC */
 	}
 
 	calc_meshverts_ext();  /*Update screen coords for current window */
@@ -573,16 +581,19 @@
 	SetBlenderCursor(BC_KNIFECURSOR);
 	
 	curve=get_mouse_trail(&len, TRAIL_MIXED);
+
+	if(G.vd->persp) curve_f = persp_cut_init(curve, len);
 	
-	if (curve && len && mode){
-		eed= em->edges.first;		
-		while(eed) {	
+	if (curve && curve_f && len && mode){
+		eed= em->edges.first;
+		while(eed) {
 			if( eed->f & SELECT ){
-				isect=seg_intersect(eed, curve, len);
+				if(!G.vd->persp) isect=seg_intersect(eed, curve, len);
+				else isect= persp_intersect(eed, curve_f, len+1);
 				if (isect) eed->f2= 1;
 				else eed->f2=0;
 				eed->f1= isect;
-				//printf("isect=%i\n", isect);
+				/*printf("isect=%i\n", isect);*/
 			}
 			else {
 				eed->f2=0;
@@ -606,6 +617,7 @@
 	addqueue(curarea->win,  REDRAW, 0);
 	window_set_cursor(win, oldcursor);
 	if (curve) MEM_freeN(curve);
+	if (curve_f && G.vd->persp) MEM_freeN(curve_f);
 
 	BIF_undo_push("Knife");
 }
@@ -717,6 +729,131 @@
 	}
 	return(isect);
 } 
+
+/**
+ * persp_cut_init
+ *
+ * Factored out transformations of CutCurve to improve performance
+ * The eye is placed as the first coordinate in the CutFloat
+ * to eliminate multiple matrix inversions
+*/
+
+CutFloat *persp_cut_init(CutCurve *c, int len) {
+	int i;
+	CutFloat *curve;
+	float mat[3][3], imat[3][3], vec[4], vec_s[2];
+	
+	curve=(CutFloat *)MEM_callocN((len+1)*sizeof(CutFloat), "PerspCut");
+
+	if (!curve) {
+		printf("failed to allocate memory in get_mouse_trail()\n");
+		return(NULL);
+	}
+	
+	initgrabz(0,0,0);
+	
+	/* all points need to be transformed to object space */
+	Mat3CpyMat4(mat, G.obedit->obmat);
+	Mat3Inv(imat, mat);
+	
+	VecCopyf(curve[0].co, G.vd->viewinv[3]);
+	VecSubf(curve[0].co, curve[0].co, G.obedit->obmat[3]);
+	Mat3MulVecfl(imat, curve[0].co);
+	
+	vec[0]=vec[1]=vec[2]=0.0;
+	vec[3]=1.0;
+	project_float(vec, vec_s);
+
+	for(i=1; i<len+1; i++) {
+		window_to_3d(curve[i].co, c[i].x - vec_s[0], c[i].y - vec_s[1]);
+		VecSubf(curve[i].co, curve[i].co, G.obedit->obmat[3]);
+		Mat3MulVecfl(imat, curve[i].co);
+	}
+	
+	return curve;
+}
+
+/**
+ * persp_intersect
+ *
+ * Performs the function of seg_intersect when the view is in perspective mode
+*/
+
+short persp_intersect(EditEdge *e, CutFloat *c, int len) {
+	int i;
+	float perc;
+	
+	for(i=2; i<len; i++) {
+		perc = line_band_intersect(e->v1->co, e->v2->co, c[0].co, c[i-1].co, c[i].co);
+		if(perc >= 0)
+			return (short)(32768.0*(perc+0.0000153)); /* Percentage in 1/32768ths */
+	}
+	return 0;
+}
+
+
+#define EPSILON (1e-6)
+
+/**
+ * line_band_intersect
+ *
+ * A modified line-plane intersect.  Checks to see if line intersects plane
+ * and checks if the intersection point lies between two rays in the plane.
+ *
+ * p0, p1 -- points on line
+ * r0 -- origin of two rays that define the plane
+ * r1, r2 -- points along the two rays
+ *
+ * Returns negative if intersect does not occur.
+ * Else returns the percentage of the way from p0 to p1 where intersection occurs
+**/
+
+
+float line_band_intersect(float p0[3], float p1[3], float r0[3], float r1[3], float r2[3]) {
+	float ray1[3], ray2[3], pnor[3], linedir[3], v[3], pI[3];
+	float t; /* 0 <= t <= 1 for intersection to occur on segment */
+	float res1, res2, cross1[3], cross2[3], in1[3], in2[3];
+
+	/* calculate plane normal of unit length */
+	VecSubf(ray1, r1, r0);
+	VecSubf(ray2, r2, r0);
+	Crossf(pnor, ray1, ray2);
+	Normalise(pnor);
+	
+	/* http://softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm 
+		describes a nice algorithm that uses only dot products. */
+	
+	VecSubf(linedir, p1, p0); /* don't normalize! */
+	t = Inpf(pnor, linedir);
+	
+	/* t could be negative -- careful! */
+	if(fabs(t) <= EPSILON) /* plane and line are parallel */
+		return -1.0f;
+	
+	VecSubf(v, r0, p0);
+	t = Inpf(pnor, v) / t;
+
+	if(t <= 0.0 || t >= 1.0) /* not in the segment */
+		return -1.0f;
+
+	VecMulf(linedir, t);
+	VecAddf(pI, p0, linedir);
+	
+	VecSubf(cross1, r1, r0);
+	VecSubf(cross2, pI, r1);
+	Crossf(in1, cross1, cross2);
+	res1 = Inpf(pnor, in1);
+	
+	VecSubf(cross1, r2, r0);
+	VecSubf(cross2, pI, r2);
+	Crossf(in2, cross1, cross2);
+	res2 = Inpf(pnor, in2);
+	
+	if((res1 > 0 && res2 < 0) || (res1 < 0 && res2 > 0))
+		return t;
+	return -1.0f;
+}
+#undef EPSILON
 
 /* ******************** LOOP ******************************************* */
 


More information about the Bf-committers mailing list