[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