[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17086] branches/etch-a-ton/source/blender /src: Subdivision schemes for continuous strokes:

Martin Poirier theeth at yahoo.com
Wed Oct 15 21:31:32 CEST 2008


Revision: 17086
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17086
Author:   theeth
Date:     2008-10-15 21:31:32 +0200 (Wed, 15 Oct 2008)

Log Message:
-----------
Subdivision schemes for continuous strokes:

Subdivide in equal length bones
Subdivide by correlation (linearity limits)

Code borrowed in parts from the skeleton generator. Will be eventually reuse code more efficiently.

Modified Paths:
--------------
    branches/etch-a-ton/source/blender/src/drawview.c
    branches/etch-a-ton/source/blender/src/editarmature_sketch.c

Modified: branches/etch-a-ton/source/blender/src/drawview.c
===================================================================
--- branches/etch-a-ton/source/blender/src/drawview.c	2008-10-15 17:58:03 UTC (rev 17085)
+++ branches/etch-a-ton/source/blender/src/drawview.c	2008-10-15 19:31:32 UTC (rev 17086)
@@ -2305,6 +2305,16 @@
 		uiButSetFunc(but, convert_sketch_armature, NULL, NULL);
 		but = uiDefBut(block, BUT, B_REDR, "Delete", 10,185,150,20, 0, 0, 0, 0, 0, "Delete sketch");
 		uiButSetFunc(but, delete_sketch_armature, NULL, NULL);
+		
+		uiBlockEndAlign(block);
+
+		uiBlockBeginAlign(block);
+
+		uiDefButBitS(block, TOG, SKGEN_CUT_LENGTH, B_DIFF, 		"Length",		10, 155, 60, 19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0,				"Subdivide arcs in bones of equal length");
+		uiDefButF(block, NUM, B_DIFF, 							"L:",			70, 155, 90, 19, &G.scene->toolsettings->skgen_length_limit,0.1,50.0, 10, 0,		"Maximum length of the bones when subdividing");
+
+		uiDefButBitS(block, TOG, SKGEN_CUT_CORRELATION, B_DIFF, "Correlation",	10, 135, 60, 19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0,					"Subdivide arcs based on correlation");
+		uiDefButF(block, NUM, B_DIFF, 							"T:",			70, 135, 90, 19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0,	"Specify the threshold correlation for subdivision");
 	
 		uiBlockEndAlign(block);
 		

Modified: branches/etch-a-ton/source/blender/src/editarmature_sketch.c
===================================================================
--- branches/etch-a-ton/source/blender/src/editarmature_sketch.c	2008-10-15 17:58:03 UTC (rev 17085)
+++ branches/etch-a-ton/source/blender/src/editarmature_sketch.c	2008-10-15 19:31:32 UTC (rev 17086)
@@ -21,6 +21,7 @@
  */
 
 #include <string.h>
+#include <math.h>
 
 #include "MEM_guardedalloc.h"
 
@@ -837,7 +838,7 @@
 	peelObjects(&depth_peels, dd->mval);
 	
 	
-	if (stk->nb_points > 0) // && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS)
+	if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS)
 	{
 		last_pt = stk->points + (stk->nb_points - 1);
 	}
@@ -955,12 +956,202 @@
 }
 /********************************************/
 
+float calcStrokeCorrelation(SK_Stroke *stk, int start, int end, float v0[3], float n[3])
+{
+	int len = 2 + abs(end - start);
+	
+	if (len > 2)
+	{
+		float avg_t = 0.0f;
+		float s_t = 0.0f;
+		float s_xyz = 0.0f;
+		int i;
+		
+		/* First pass, calculate average */
+		for (i = start; i <= end; i++)
+		{
+			float v[3];
+			
+			VecSubf(v, stk->points[i].p, v0);
+			avg_t += Inpf(v, n);
+		}
+		
+		avg_t /= Inpf(n, n);
+		avg_t += 1.0f; /* adding start (0) and end (1) values */
+		avg_t /= len;
+		
+		/* Second pass, calculate s_xyz and s_t */
+		for (i = start; i <= end; i++)
+		{
+			float v[3], d[3];
+			float dt;
+			
+			VecSubf(v, stk->points[i].p, v0);
+			Projf(d, v, n);
+			VecSubf(v, v, d);
+			
+			dt = VecLength(d) - avg_t;
+			
+			s_t += dt * dt;
+			s_xyz += Inpf(v, v);
+		}
+		
+		/* adding start(0) and end(1) values to s_t */
+		s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
+		
+		return 1.0f - s_xyz / s_t; 
+	}
+	else
+	{
+		return 1.0f;
+	}
+}
+
+EditBone * subdivideStrokeByCorrelation(SK_Stroke *stk, int start, int end, float invmat[][4])
+{
+	bArmature *arm= G.obedit->data;
+	EditBone *lastBone = NULL;
+	float n[3];
+	float CORRELATION_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
+	
+	if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
+	{
+		EditBone *child = NULL;
+		EditBone *parent = NULL;
+		int boneStart = start;
+		int i;
+
+		parent = addEditBone("Bone", &G.edbo, arm);
+		VECCOPY(parent->head, stk->points[start].p);
+		Mat4MulVecfl(invmat, parent->head);
+		
+		for (i = start + 1; i < end; i++)
+		{
+			/* Calculate normal */
+			VecSubf(n, stk->points[i].p, parent->head);
+
+			if (calcStrokeCorrelation(stk, boneStart, i, parent->head, n) < CORRELATION_THRESHOLD)
+			{
+				VECCOPY(parent->tail, stk->points[i - 1].p);
+
+				child = addEditBone("Bone", &G.edbo, arm);
+				VECCOPY(child->head, parent->tail);
+				Mat4MulVecfl(invmat, parent->tail);
+				child->parent = parent;
+				child->flag |= BONE_CONNECTED;
+				
+				parent = child; // new child is next parent
+				boneStart = i; // start next bone from current index
+			}
+		}
+
+		VECCOPY(parent->tail, stk->points[end].p);
+		Mat4MulVecfl(invmat, parent->tail);
+		lastBone = parent;
+	}
+	
+	return lastBone;
+}
+
+EditBone * subdivideStrokeByLength(SK_Stroke *stk, int start, int end, float invmat[][4])
+{
+	bArmature *arm= G.obedit->data;
+	EditBone *lastBone = NULL;
+	
+	if (G.scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH)
+	{
+		EditBone *child = NULL;
+		EditBone *parent = NULL;
+		float lengthLimit = G.scene->toolsettings->skgen_length_limit;
+		int i;
+		int same = 0;
+		
+		parent = addEditBone("Bone", &G.edbo, arm);
+		VECCOPY(parent->head, stk->points[start].p);
+
+		i = start + 1;
+		while (i < end)
+		{
+			float *vec0 = stk->points[i - 1].p;
+			float *vec1 = stk->points[i].p;
+
+			/* If lengthLimit hits the current segment */
+			if (VecLenf(vec1, parent->head) > lengthLimit)
+			{
+				if (same == 0)
+				{
+					float dv[3], off[3];
+					float a, b, c, f;
+					
+					/* Solve quadratic distance equation */
+					VecSubf(dv, vec1, vec0);
+					a = Inpf(dv, dv);
+					
+					VecSubf(off, vec0, parent->head);
+					b = 2 * Inpf(dv, off);
+					
+					c = Inpf(off, off) - (lengthLimit * lengthLimit);
+					
+					f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
+					
+					//printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
+					
+					if (isnan(f) == 0 && f < 1.0f)
+					{
+						VECCOPY(parent->tail, dv);
+						VecMulf(parent->tail, f);
+						VecAddf(parent->tail, parent->tail, vec0);
+					}
+					else
+					{
+						VECCOPY(parent->tail, vec1);
+					}
+				}
+				else
+				{
+					float dv[3];
+					
+					VecSubf(dv, vec1, vec0);
+					Normalize(dv);
+					 
+					VECCOPY(parent->tail, dv);
+					VecMulf(parent->tail, lengthLimit);
+					VecAddf(parent->tail, parent->tail, parent->head);
+				}
+				
+				/* put head in correct space */
+				Mat4MulVecfl(invmat, parent->head);
+				
+				child = addEditBone("Bone", &G.edbo, arm);
+				VECCOPY(child->head, parent->tail);
+				child->parent = parent;
+				child->flag |= BONE_CONNECTED;
+				
+				parent = child; // new child is next parent
+				
+				same = 1; // mark as same
+			}
+			else
+			{
+				i++;
+				same = 0; // Reset same
+			}
+		}
+		VECCOPY(parent->tail, stk->points[end].p);
+		Mat4MulVecfl(invmat, parent->tail);
+		lastBone = parent;
+	}
+	
+	return lastBone;
+}
+
 void sk_convertStroke(SK_Stroke *stk)
 {
 	bArmature *arm= G.obedit->data;
 	SK_Point *head;
 	EditBone *parent = NULL;
 	float invmat[4][4]; /* move in caller function */
+	int head_index = 0;
 	int i;
 	
 	head = NULL;
@@ -975,27 +1166,53 @@
 		{
 			if (head == NULL)
 			{
+				head_index = i;
 				head = pt;
 			}
 			else
 			{
-				EditBone *bone;
+				EditBone *bone = NULL;
+				EditBone *new_parent;
 				
-				bone = addEditBone("Bone", &G.edbo, arm);
+				if (i - head_index > 1)
+				{
+					bone = subdivideStrokeByCorrelation(stk, head_index, i, invmat);
+					
+					if (bone == NULL)
+					{
+						bone = subdivideStrokeByLength(stk, head_index, i, invmat);
+					}
+				}
 				
-				VECCOPY(bone->head, head->p);
-				VECCOPY(bone->tail, pt->p);
+				if (bone == NULL)
+				{
+					bone = addEditBone("Bone", &G.edbo, arm);
+					
+					VECCOPY(bone->head, head->p);
+					VECCOPY(bone->tail, pt->p);
+					
+					Mat4MulVecfl(invmat, bone->head);
+					Mat4MulVecfl(invmat, bone->tail);
+				}
 				
-				Mat4MulVecfl(invmat, bone->head);
-				Mat4MulVecfl(invmat, bone->tail);
+				new_parent = bone;
+				bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
 				
+				/* move to end of chain */
+				while (bone->parent != NULL)
+				{
+					bone = bone->parent;
+					bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+				}
+
 				if (parent != NULL)
 				{
 					bone->parent = parent;
 					bone->flag |= BONE_CONNECTED;					
 				}
 				
-				parent = bone;
+				parent = new_parent;
+				head_index = i;
 				head = pt;
 			}
 		}





More information about the Bf-blender-cvs mailing list