Step 3/3, merging subdivision/bone creation methods using iterators
authorMartin Poirier <theeth@yahoo.com>
Sat, 29 Nov 2008 20:37:10 +0000 (20:37 +0000)
committerMartin Poirier <theeth@yahoo.com>
Sat, 29 Nov 2008 20:37:10 +0000 (20:37 +0000)
This also adds a special Embedding option called "Peel Objects". This option makes the embedding snap consider objects as whole, taking the first and last hit of each of them to calculate the embedding point (instead of peeling with first/second, third/fourth and so on). This option is useful if you have mecanical pieces with lots of details (as single objects) and want to put bones in the middle (think of adding bones to a mecha, for example).

source/blender/blenlib/BLI_graph.h
source/blender/blenlib/intern/graph.c
source/blender/include/BIF_generate.h [new file with mode: 0644]
source/blender/include/reeb.h
source/blender/makesdna/DNA_scene_types.h
source/blender/src/drawview.c
source/blender/src/editarmature.c
source/blender/src/editarmature_generate.c [new file with mode: 0644]
source/blender/src/editarmature_retarget.c
source/blender/src/editarmature_sketch.c
source/blender/src/reeb.c

index 7629dbf6ba8b6bda6cd876584885810af2dd2236..f4fccfcbb2c8d1a6eb386c18288564ea9f1a6a43 100644 (file)
@@ -62,13 +62,25 @@ typedef struct BArc {
 
 struct BArcIterator;
 
+void* IT_head(void* iter);
+void* IT_tail(void* iter);
+void* IT_peek(void* iter, int n);
+void* IT_next(void* iter);
+void* IT_nextN(void* iter, int n);
+void* IT_previous(void* iter);
+int   IT_stopped(void* iter);
+
+typedef void* (*HeadFct)(void* iter);
+typedef void* (*TailFct)(void* iter);
 typedef void* (*PeekFct)(void* iter, int n);
 typedef void* (*NextFct)(void* iter);
 typedef void* (*NextNFct)(void* iter, int n);
 typedef void* (*PreviousFct)(void* iter);
-typedef int    (*StoppedFct)(void* iter);
+typedef int   (*StoppedFct)(void* iter);
 
 typedef struct BArcIterator {
+       HeadFct         head;
+       TailFct         tail;
        PeekFct         peek;
        NextFct         next;
        NextNFct        nextN;
index e2ed8f11ee289ac56d76dcd4dd2dbcd5f8b29e25..ca82fcac84489d8609bfbb32805a68411e071747 100644 (file)
@@ -465,8 +465,6 @@ int subtreeShape(BNode *node, BArc *rootArc, int include_root)
 
 int BLI_subtreeShape(BGraph *graph, BNode *node, BArc *rootArc, int include_root)
 {
-       BNode *test_node;
-       
        BLI_flagNodes(graph, 0);
        return subtreeShape(node, rootArc, include_root);
 }
@@ -1090,3 +1088,56 @@ void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit)
        }
 }
 
+void* IT_head(void* arg)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->head(iter);
+}
+
+void* IT_tail(void* arg)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->tail(iter); 
+}
+
+void* IT_peek(void* arg, int n)
+{
+       BArcIterator *iter = (BArcIterator*)arg;
+       
+       if (iter->index + n < 0)
+       {
+               return iter->head(iter);
+       }
+       else if (iter->index + n >= iter->length)
+       {
+               return iter->tail(iter);
+       }
+       else
+       {
+               return iter->peek(iter, n);
+       }
+}
+
+void* IT_next(void* arg)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->next(iter);
+}
+
+void* IT_nextN(void* arg, int n)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->nextN(iter, n);
+}
+
+void* IT_previous(void* arg)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->previous(iter);
+}
+
+int   IT_stopped(void* arg)
+{
+       BArcIterator *iter = (BArcIterator*)arg; 
+       return iter->stopped(iter);
+}
diff --git a/source/blender/include/BIF_generate.h b/source/blender/include/BIF_generate.h
new file mode 100644 (file)
index 0000000..32d89d3
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * $Id:  $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BIF_GENERATE_H
+#define BIF_GENERATE_H
+
+struct EditBone;
+struct BArcIterator;
+struct bArmature;
+struct ListBase;
+
+typedef int(NextSubdivisionFunc)(struct BArcIterator*, int, int, float[3], float[3]);
+float calcArcCorrelation(struct BArcIterator *iter, int start, int end, float v0[3], float n[3]);
+
+int nextFixedSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+int nextLengthSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+int nextCorrelationSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+
+struct EditBone * subdivideArcBy(struct bArmature *arm, ListBase *editbones, struct BArcIterator *iter, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion);
+
+void setBoneRollFromNormal(struct EditBone *bone, float *no, float invmat[][4], float tmat[][3]);
+
+#endif /* BIF_GENERATE_H */
index 21c57495fb040b0e4a3fbe70dcc194139129f92d..2f463d6194bf607cdd6f3793eeb32e74c33e4a4a 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef REEB_H_
 #define REEB_H_
 
-#define WITH_BF_REEB
+//#define WITH_BF_REEB
 
 #include "DNA_listBase.h"
 
@@ -120,6 +120,8 @@ typedef struct ReebArc {
 } ReebArc;
 
 typedef struct ReebArcIterator {
+       HeadFct         head;
+       TailFct         tail;
        PeekFct         peek;
        NextFct         next;
        NextNFct        nextN;
@@ -151,9 +153,9 @@ void renormalizeWeight(struct EditMesh *em, float newmax);
 ReebGraph * generateReebGraph(struct EditMesh *me, int subdivisions);
 ReebGraph * newReebGraph();
 
-void initArcIterator(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
-void initArcIterator2(struct ReebArcIterator *iter, struct ReebArc *arc, int start, int end);
-void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start);
+void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
+void initArcIterator2(BArcIterator *iter, struct ReebArc *arc, int start, int end);
+void initArcIteratorStart(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start);
 
 /* Filtering */
 void filterNullReebGraph(ReebGraph *rg);
index 10e8c534ab2e31d7dfc288fc635f1a64c58fa28a..a5491578115c8691db4954f2c904358ab26ed0dd 100644 (file)
@@ -728,6 +728,7 @@ typedef struct Scene {
 /* scene->snap_flag */
 #define SCE_SNAP                               1
 #define SCE_SNAP_ROTATE                        2
+#define SCE_SNAP_PEEL_OBJECT   4
 /* scene->snap_target */
 #define SCE_SNAP_TARGET_CLOSEST        0
 #define SCE_SNAP_TARGET_CENTER 1
index e652ea989d107db83f5bb913487e617d8fe8393f..3dfec925474a1ae7651767be363dec8468a741d9 100644 (file)
@@ -2294,7 +2294,7 @@ static void view3d_panel_bonesketch_spaces(short cntrl)
        static char joint_label[32];
        uiBlock *block;
        uiBut *but;
-       int yco = 70, height = 140;
+       int yco = 130, height = 140;
        int nb_joints;
 
        /* replace with check call to sketching lib */
@@ -2382,7 +2382,9 @@ static void view3d_panel_bonesketch_spaces(short cntrl)
                BLI_snprintf(joint_label, 32, "%i joints", nb_joints);
                
                uiDefBut(block, LABEL, 1, joint_label,                                  10, yco, 200, 20, NULL, 0.0, 0.0, 0, 0, "");
+               yco -= 20;
                
+               uiDefButBitS(block, TOG, SCE_SNAP_PEEL_OBJECT, B_DIFF, "Peel Objects", 10, yco, 200, 20, &G.scene->snap_flag, 0, 0, 0, 0, "Peel whole objects as one");
 
                if(yco < 0) uiNewPanelHeight(block, height-yco);
        }
index bae6fc5a0af3686940afb7538c137d03115d4a6e..4521c9a83127b834b46cd1868bfa0f5536afb0df 100644 (file)
@@ -93,6 +93,7 @@
 #include "BIF_space.h"
 #include "BIF_toolbox.h"
 #include "BIF_transform.h"
+#include "BIF_generate.h"
 
 #include "BDR_editobject.h"
 #include "BDR_drawobject.h"
@@ -4655,7 +4656,8 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
        EditBone *lastBone = NULL;
        if (G.scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE)
        {
-               ReebArcIterator iter;
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
                float *previous = NULL, *current = NULL;
                EditBone *child = NULL;
                EditBone *parent = NULL;
@@ -4668,18 +4670,18 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
                
                root = parent;
                
-               initArcIterator(&iter, arc, head);
-               iter.next(&iter);
-               previous = iter.p;
+               initArcIterator(iter, arc, head);
+               IT_next(iter);
+               previous = iter->p;
                
-               for (iter.next(&iter);
-                       iter.stopped(&iter) == 0;
-                       previous = iter.p, iter.next(&iter))
+               for (IT_next(iter);
+                       IT_stopped(iter) == 0;
+                       previous = iter->p, IT_next(iter))
                {
                        float vec1[3], vec2[3];
                        float len1, len2;
                        
-                       current = iter.p;
+                       current = iter->p;
 
                        VecSubf(vec1, previous, parent->head);
                        VecSubf(vec2, current, previous);
@@ -4716,173 +4718,26 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
        return lastBone;
 }
 
-float calcVariance(ReebArc *arc, int start, int end, float v0[3], float n[3])
+EditBone * test_subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
 {
-       int len = 2 + abs(end - start);
-       
-       if (len > 2)
-       {
-               ReebArcIterator iter;
-               float avg_t = 0.0f;
-               float s_t = 0.0f;
-               float s_xyz = 0.0f;
-               
-               /* First pass, calculate average */
-               for (initArcIterator2(&iter, arc, start, end), iter.next(&iter);
-                       iter.stopped(&iter) == 0;
-                       iter.next(&iter))
-               {
-                       float v[3];
-                       
-                       VecSubf(v, iter.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 (initArcIterator2(&iter, arc, start, end), iter.next(&iter);
-                       iter.stopped(&iter) == 0;
-                       iter.next(&iter))
-               {
-                       float v[3], d[3];
-                       float dt;
-                       
-                       VecSubf(v, iter.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 s_xyz / s_t; 
-       }
-       else
-       {
-               return 0;
-       }
-}
-
-float calcDistance(ReebArc *arc, int start, int end, float head[3], float tail[3])
-{
-       ReebArcIterator iter;
-       float max_dist = 0;
-       
-       /* calculate maximum distance */
-       for (initArcIterator2(&iter, arc, start, end), iter.next(&iter);
-               iter.stopped(&iter) == 0;
-               iter.next(&iter))
-       {
-               float v1[3], v2[3], c[3];
-               float dist;
-               
-               VecSubf(v1, head, tail);
-               VecSubf(v2, iter.p, tail);
-
-               Crossf(c, v1, v2);
-               
-               dist = Inpf(c, c) / Inpf(v1, v1);
-               
-               max_dist = dist > max_dist ? dist : max_dist;
-       }
-       
-       
-       return max_dist; 
-}
-
-EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
-       ReebArcIterator iter;
-       float n[3];
-       float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
        EditBone *lastBone = NULL;
-       
-       /* init iterator to get start and end from head */
-       initArcIterator(&iter, arc, head);
-       
-       /* Calculate overall */
-       VecSubf(n, arc->buckets[iter.end].p, head->p);
-       
+
        if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
        {
-               EditBone *child = NULL;
-               EditBone *parent = NULL;
-               float normal[3] = {0, 0, 0};
-               float avg_normal[3];
-               int total = 0;
-               int boneStart = iter.start;
-               
-               parent = add_editbone("Bone");
-               parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-               VECCOPY(parent->head, head->p);
+               float invmat[4][4] = {  {1, 0, 0, 0},
+                                                               {0, 1, 0, 0},
+                                                               {0, 0, 1, 0},
+                                                               {0, 0, 0, 1}};
+               float tmat[3][3] = {    {1, 0, 0},
+                                                               {0, 1, 0},
+                                                               {0, 0, 1}};
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
+               bArmature *arm= G.obedit->data;
                
-               while(iter.next(&iter))
-               {
-                       float btail[3];
-                       float value = 0;
-
-                       if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
-                       {
-                               VECCOPY(btail, iter.p);
-                       }
-                       else
-                       {
-                               float length;
-                               
-                               /* Calculate normal */
-                               VecSubf(n, iter.p, parent->head);
-                               length = Normalize(n);
-                               
-                               total += 1;
-                               VecAddf(normal, normal, n);
-                               VECCOPY(avg_normal, normal);
-                               VecMulf(avg_normal, 1.0f / total);
-                                
-                               VECCOPY(btail, avg_normal);
-                               VecMulf(btail, length);
-                               VecAddf(btail, btail, parent->head);
-                       }
-
-                       if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
-                       {
-                               value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
-                       }
-                       else
-                       {
-                               float n[3];
-                               
-                               VecSubf(n, btail, parent->head);
-                               value = calcVariance(arc, boneStart, iter.index, parent->head, n);
-                       }
-
-                       if (value > ADAPTIVE_THRESHOLD)
-                       {
-                               VECCOPY(parent->tail, btail);
-
-                               child = add_editbone("Bone");
-                               VECCOPY(child->head, parent->tail);
-                               child->parent = parent;
-                               child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                               
-                               parent = child; // new child is next parent
-                               boneStart = iter.index; // start from end
-                               
-                               normal[0] = normal[1] = normal[2] = 0;
-                               total = 0;
-                       }
-               }
-
-               VECCOPY(parent->tail, tail->p);
+               initArcIterator(iter, arc, head);
                
-               lastBone = parent; /* set last bone in the chain */
+               lastBone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextCorrelationSubdivision);
        }
        
        return lastBone;
@@ -4915,106 +4770,26 @@ float arcLengthRatio(ReebArc *arc)
        return embedLength / arcLength; 
 }
 
-EditBone * subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
+EditBone * test_subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
 {
        EditBone *lastBone = NULL;
        if ((G.scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
                arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
        {
-               ReebArcIterator iter;
-               float *previous = NULL;
-               EditBone *child = NULL;
-               EditBone *parent = NULL;
-               float lengthLimit = G.scene->toolsettings->skgen_length_limit;
-               int same = 0;
-               
-               parent = add_editbone("Bone");
-               parent->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-               VECCOPY(parent->head, head->p);
-
-               initArcIterator(&iter, arc, head);
-
-               iter.next(&iter);
+               float invmat[4][4] = {  {1, 0, 0, 0},
+                                                               {0, 1, 0, 0},
+                                                               {0, 0, 1, 0},
+                                                               {0, 0, 0, 1}};
+               float tmat[3][3] = {    {1, 0, 0},
+                                                               {0, 1, 0},
+                                                               {0, 0, 1}};
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
+               bArmature *arm= G.obedit->data;
                
-               while (iter.stopped(&iter) == 0)
-               {
-                       float *vec0 = NULL;
-                       float *vec1 = iter.p;
-
-                       /* first bucket. Previous is head */
-                       if (previous == NULL)
-                       {
-                               vec0 = head->p;
-                       }
-                       /* Previous is a valid bucket */
-                       else
-                       {
-                               vec0 = previous;
-                       }
-                       
-                       /* 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);
-                               }
-                               
-                               child = add_editbone("Bone");
-                               VECCOPY(child->head, parent->tail);
-                               child->parent = parent;
-                               child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                               
-                               parent = child; // new child is next parent
-                               
-                               same = 1; // mark as same
-                       }
-                       else
-                       {
-                               previous = iter.p;
-                               iter.next(&iter);
-                               same = 0; // Reset same
-                       }
-               }
-               VECCOPY(parent->tail, tail->p);
+               initArcIterator(iter, arc, head);
                
-               lastBone = parent; /* set last bone in the chain */
+               lastBone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextLengthSubdivision);
        }
        
        return lastBone;
@@ -5107,13 +4882,13 @@ void generateSkeletonFromReebGraph(ReebGraph *rg)
                        switch(G.scene->toolsettings->skgen_subdivisions[i])
                        {
                                case SKGEN_SUB_LENGTH:
-                                       lastBone = subdivideByLength(arc, head, tail);
+                                       lastBone = test_subdivideByLength(arc, head, tail);
                                        break;
                                case SKGEN_SUB_ANGLE:
                                        lastBone = subdivideByAngle(arc, head, tail);
                                        break;
                                case SKGEN_SUB_CORRELATION:
-                                       lastBone = subdivideByCorrelation(arc, head, tail);
+                                       lastBone = test_subdivideByCorrelation(arc, head, tail);
                                        break;
                        }
                }
diff --git a/source/blender/src/editarmature_generate.c b/source/blender/src/editarmature_generate.c
new file mode 100644 (file)
index 0000000..c6e7748
--- /dev/null
@@ -0,0 +1,327 @@
+/**
+ * $Id: editarmature_generate.c  $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * editarmature.c: Interface for creating and posing armature objects
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_armature_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_graph.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_generate.h"
+
+void setBoneRollFromNormal(EditBone *bone, float *no, float invmat[][4], float tmat[][3])
+{
+       if (no != NULL && !VecIsNull(no))
+       {
+               float tangent[3], cotangent[3], normal[3];
+
+               VECCOPY(normal, no);    
+               Mat3MulVecfl(tmat, normal);
+
+               VecSubf(tangent, bone->tail, bone->head);
+               Crossf(cotangent, tangent, normal);
+               Crossf(normal, cotangent, tangent);
+               
+               Normalize(normal);
+               
+               bone->roll = rollBoneToVector(bone, normal);
+       }
+}
+
+float calcArcCorrelation(BArcIterator *iter, 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];
+                       
+                       IT_peek(iter, i);
+                       VecSubf(v, iter->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;
+                       
+                       IT_peek(iter, i);
+                       VecSubf(v, iter->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;
+       }
+}
+
+int nextFixedSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+       static float stroke_length = 0;
+       static float current_length;
+       static char n;
+       float *v1, *v2;
+       float length_threshold;
+       int i;
+       
+       if (stroke_length == 0)
+       {
+               current_length = 0;
+
+               IT_peek(iter, start);
+               v1 = iter->p;
+               
+               for (i = start + 1; i <= end; i++)
+               {
+                       IT_peek(iter, i);
+                       v2 = iter->p;
+
+                       stroke_length += VecLenf(v1, v2);
+                       
+                       v1 = v2;
+               }
+               
+               n = 0;
+               current_length = 0;
+       }
+       
+       n++;
+       
+       length_threshold = n * stroke_length / G.scene->toolsettings->skgen_subdivision_number;
+       
+       IT_peek(iter, start);
+       v1 = iter->p;
+
+       /* < and not <= because we don't care about end, it is P_EXACT anyway */
+       for (i = start + 1; i < end; i++)
+       {
+               IT_peek(iter, i);
+               v2 = iter->p;
+
+               current_length += VecLenf(v1, v2);
+
+               if (current_length >= length_threshold)
+               {
+                       VECCOPY(p, v2);
+                       return i;
+               }
+               
+               v1 = v2;
+       }
+       
+       stroke_length = 0;
+       
+       return -1;
+}
+int nextCorrelationSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+       float correlation_threshold = G.scene->toolsettings->skgen_correlation_limit;
+       float *start_p;
+       float n[3];
+       int i;
+       
+       IT_peek(iter, start);
+       start_p = iter->p;
+
+       for (i = start + 2; i <= end; i++)
+       {
+               /* Calculate normal */
+               IT_peek(iter, i);
+               VecSubf(n, iter->p, head);
+
+               if (calcArcCorrelation(iter, start, i, start_p, n) < correlation_threshold)
+               {
+                       IT_peek(iter, i - 1);
+                       VECCOPY(p, iter->p);
+                       return i - 1;
+               }
+       }
+       
+       return -1;
+}
+
+int nextLengthSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+       float lengthLimit = G.scene->toolsettings->skgen_length_limit;
+       int same = 1;
+       int i;
+       
+       i = start + 1;
+       while (i <= end)
+       {
+               float *vec0;
+               float *vec1;
+               
+               IT_peek(iter, i - 1);
+               vec0 = iter->p;
+
+               IT_peek(iter, i);
+               vec1 = iter->p;
+               
+               /* If lengthLimit hits the current segment */
+               if (VecLenf(vec1, 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, 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(p, dv);
+                                       VecMulf(p, f);
+                                       VecAddf(p, p, vec0);
+                               }
+                               else
+                               {
+                                       VECCOPY(p, vec1);
+                               }
+                       }
+                       else
+                       {
+                               float dv[3];
+                               
+                               VecSubf(dv, vec1, vec0);
+                               Normalize(dv);
+                                
+                               VECCOPY(p, dv);
+                               VecMulf(p, lengthLimit);
+                               VecAddf(p, p, head);
+                       }
+                       
+                       return i - 1; /* restart at lower bound */
+               }
+               else
+               {
+                       i++;
+                       same = 0; // Reset same
+               }
+       }
+       
+       return -1;
+}
+
+EditBone * subdivideArcBy(bArmature *arm, ListBase *editbones, BArcIterator *iter, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion)
+{
+       EditBone *lastBone = NULL;
+       EditBone *child = NULL;
+       EditBone *parent = NULL;
+       int bone_start = 0;
+       int end = iter->length;
+       int index;
+       
+       IT_head(iter);
+       
+       parent = addEditBone("Bone", editbones, arm);
+       VECCOPY(parent->head, iter->p);
+       
+       index = next_subdividion(iter, bone_start, end, parent->head, parent->tail);
+       while (index != -1)
+       {
+               IT_peek(iter, index);
+
+               child = addEditBone("Bone", editbones, arm);
+               VECCOPY(child->head, parent->tail);
+               child->parent = parent;
+               child->flag |= BONE_CONNECTED;
+               
+               /* going to next bone, fix parent */
+               Mat4MulVecfl(invmat, parent->tail);
+               Mat4MulVecfl(invmat, parent->head);
+               setBoneRollFromNormal(parent, iter->no, invmat, tmat);
+
+               parent = child; // new child is next parent
+               bone_start = index; // start next bone from current index
+
+               index = next_subdividion(iter, bone_start, end, parent->head, parent->tail);
+       }
+       
+       iter->tail(iter);
+
+       VECCOPY(parent->tail, iter->p);
+
+       /* fix last bone */
+       Mat4MulVecfl(invmat, parent->tail);
+       Mat4MulVecfl(invmat, parent->head);
+       setBoneRollFromNormal(parent, iter->no, invmat, tmat);
+       lastBone = parent;
+       
+       return lastBone;
+}
index 280292abaf031eca6c190dc258f045d2b767230b..bb0fc08905cc60d7f2c8fa91e91b74d31661ee87 100644 (file)
@@ -1655,100 +1655,6 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
        return bone;
 }
 
-EditBone * generateBonesForArc(RigGraph *rigg, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
-       ReebArcIterator iter;
-       float n[3];
-       float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
-       EditBone *lastBone = NULL;
-       
-       /* init iterator to get start and end from head */
-       initArcIterator(&iter, arc, head);
-       
-       /* Calculate overall */
-       VecSubf(n, arc->buckets[iter.end].p, head->p);
-       
-       if (1 /* G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION */ )
-       {
-               EmbedBucket *bucket = NULL;
-               EmbedBucket *previous = NULL;
-               EditBone *child = NULL;
-               EditBone *parent = NULL;
-               float normal[3] = {0, 0, 0};
-               float avg_normal[3];
-               int total = 0;
-               int boneStart = iter.start;
-               
-               parent = add_editbonetolist("Bone", rigg->editbones);
-               parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-               VECCOPY(parent->head, head->p);
-               
-               for (previous = iter.next(&iter), bucket = iter.next(&iter);
-                       bucket;
-                       previous = bucket, bucket = iter.next(&iter))
-               {
-                       float btail[3];
-                       float value = 0;
-
-                       if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
-                       {
-                               VECCOPY(btail, bucket->p);
-                       }
-                       else
-                       {
-                               float length;
-                               
-                               /* Calculate normal */
-                               VecSubf(n, bucket->p, parent->head);
-                               length = Normalize(n);
-                               
-                               total += 1;
-                               VecAddf(normal, normal, n);
-                               VECCOPY(avg_normal, normal);
-                               VecMulf(avg_normal, 1.0f / total);
-                                
-                               VECCOPY(btail, avg_normal);
-                               VecMulf(btail, length);
-                               VecAddf(btail, btail, parent->head);
-                       }
-
-                       if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
-                       {
-                               value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
-                       }
-                       else
-                       {
-                               float n[3];
-                               
-                               VecSubf(n, btail, parent->head);
-                               value = calcVariance(arc, boneStart, iter.index, parent->head, n);
-                       }
-
-                       if (value > ADAPTIVE_THRESHOLD)
-                       {
-                               VECCOPY(parent->tail, btail);
-
-                               child = add_editbonetolist("Bone", rigg->editbones);
-                               VECCOPY(child->head, parent->tail);
-                               child->parent = parent;
-                               child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                               
-                               parent = child; // new child is next parent
-                               boneStart = iter.index; // start from end
-                               
-                               normal[0] = normal[1] = normal[2] = 0;
-                               total = 0;
-                       }
-               }
-
-               VECCOPY(parent->tail, tail->p);
-               
-               lastBone = parent; /* set last bone in the chain */
-       }
-       
-       return lastBone;
-}
-
 void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
 {
        while (node->multi_level > multi_level_limit && node->link_up)
@@ -1775,7 +1681,7 @@ void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level
                                
                                earc->flag = ARC_USED;
                                
-                               generateBonesForArc(rigg, earc, node, other);
+                               //generateBonesForArc(rigg, earc, node, other);
                                generateMissingArcsFromNode(rigg, other, multi_level_limit);
                        }
                }
@@ -2048,7 +1954,7 @@ static void printPositions(int *positions, int nb_positions)
 
 #define MAX_COST FLT_MAX /* FIX ME */
 
-static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i0, int i1)
+static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1)
 {
        EmbedBucket *bucket = NULL;
        float max_dist = 0;
@@ -2068,7 +1974,7 @@ static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i
                        {
                                float dist;
                                
-                               bucket = iter->peek(iter, j);
+                               bucket = IT_peek(iter, j);
        
                                VecSubf(v2, bucket->p, vec1);
                
@@ -2128,7 +2034,7 @@ static float costLength(float original_length, float current_length)
        }
 }
 
-static float calcCostLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
+static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
 {
        float vec[3];
        float length;
@@ -2139,7 +2045,7 @@ static float calcCostLengthDistance(ReebArcIterator *iter, float **vec_cache, Ri
        return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
 }
 
-static float calcCostAngleLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2)
+static float calcCostAngleLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2)
 {
        float vec_second[3], vec_first[3];
        float length2;
@@ -2189,7 +2095,7 @@ static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions,
        }
 }
 
-static MemoNode * solveJoints(MemoNode *table, ReebArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left)
+static MemoNode * solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left)
 {
        MemoNode *node;
        int index = indexMemoNode(nb_positions, previous, current, joints_left);
@@ -2277,7 +2183,8 @@ static int testFlipArc(RigArc *iarc, RigNode *inode_start)
 
 static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
 {
-       ReebArcIterator iter;
+       ReebArcIterator arc_iter;
+       BArcIterator *iter = (BArcIterator*)&arc_iter;
        RigEdge *edge;
        EmbedBucket *bucket = NULL;
        ReebNode *node_start, *node_end;
@@ -2332,15 +2239,15 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                positions_cache[0] = node_start->p;
                positions_cache[nb_positions + 1] = node_end->p;
                
-               initArcIterator(&iter, earc, node_start);
+               initArcIterator(iter, earc, node_start);
 
                for (i = 1; i <= nb_positions; i++)
                {
-                       EmbedBucket *bucket = iter.peek(&iter, i);
+                       EmbedBucket *bucket = IT_peek(iter, i);
                        positions_cache[i] = bucket->p;
                }
 
-               result = solveJoints(table, &iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints);
+               result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints);
                
                min_cost = result->weight;
                copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
@@ -2422,7 +2329,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                        }
                
                        /* calculating cost */
-                       initArcIterator(&iter, earc, node_start);
+                       initArcIterator(iter, earc, node_start);
                        
                        vec0 = NULL;
                        vec1 = node_start->p;
@@ -2443,13 +2350,13 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                                        if (i < nb_joints)
                                        {
                                                i2 = positions[i];
-                                               bucket = iter.peek(&iter, positions[i]);
+                                               bucket = IT_peek(iter, positions[i]);
                                                vec2 = bucket->p;
                                                vec_cache[i + 1] = vec2; /* update cache for updated position */
                                        }
                                        else
                                        {
-                                               i2 = iter.length;
+                                               i2 = iter->length;
                                                vec2 = node_end->p;
                                        }
                                        
@@ -2485,7 +2392,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                                        new_cost += costLength(edge->length, length2);
                                        
                                        /* Distance Cost */
-                                       new_cost += costDistance(&iter, vec1, vec2, i1, i2);
+                                       new_cost += costDistance(iter, vec1, vec2, i1, i2);
                                        
                                        cost_cache[i] = new_cost;
                                }
@@ -2518,7 +2425,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
        }
 
        vec0 = node_start->p;
-       initArcIterator(&iter, earc, node_start);
+       initArcIterator(iter, earc, node_start);
        
 #ifndef USE_THREADS
        printPositions(best_positions, nb_joints);
@@ -2535,7 +2442,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                float *no = NULL;
                if (i < nb_joints)
                {
-                       bucket = iter.peek(&iter, best_positions[i]);
+                       bucket = IT_peek(iter, best_positions[i]);
                        vec1 = bucket->p;
                        no = bucket->no;
                }
@@ -2558,7 +2465,8 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
 
 static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
 {
-       ReebArcIterator iter;
+       ReebArcIterator arc_iter;
+       BArcIterator *iter = (BArcIterator*)&arc_iter;
        ReebArc *earc = iarc->link_mesh;
        ReebNode *node_start, *node_end;
        RigEdge *edge;
@@ -2580,9 +2488,9 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
                node_end = (ReebNode*)earc->tail;
        }
        
-       initArcIterator(&iter, earc, node_start);
+       initArcIterator(iter, earc, node_start);
 
-       bucket = iter.next(&iter);
+       bucket = IT_next(iter);
        
        vec0 = node_start->p;
        
@@ -2593,15 +2501,15 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
                embedding_length += VecLenf(vec0, vec1);
                
                vec0 = vec1;
-               bucket = iter.next(&iter);
+               bucket = IT_next(iter);
        }
        
        embedding_length += VecLenf(node_end->p, vec1);
        
        /* fit bones */
-       initArcIterator(&iter, earc, node_start);
+       initArcIterator(iter, earc, node_start);
 
-       bucket = iter.next(&iter);
+       bucket = IT_next(iter);
 
        vec0 = node_start->p;
        previous_vec = vec0;
@@ -2616,7 +2524,7 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
                while (bucket && new_bone_length > length)
                {
                        length += VecLenf(previous_vec, vec1);
-                       bucket = iter.next(&iter);
+                       bucket = IT_next(iter);
                        previous_vec = vec1;
                        vec1 = bucket->p;
                        no = bucket->no;
index d558445dec67c84a6689075843b02b14213ccebd..78af0a726c226f9703e3a15116fc3639eb7216dd 100644 (file)
@@ -54,6 +54,7 @@
 #include "BIF_editarmature.h"
 #include "BIF_sketch.h"
 #include "BIF_retarget.h"
+#include "BIF_generate.h"
 
 #include "blendef.h"
 #include "mydevice.h"
@@ -117,6 +118,26 @@ typedef struct SK_Sketch
        SK_Point        next_point;
 } SK_Sketch;
 
+typedef struct SK_StrokeIterator {
+       HeadFct         head;
+       TailFct         tail;
+       PeekFct         peek;
+       NextFct         next;
+       NextNFct        nextN;
+       PreviousFct     previous;
+       StoppedFct      stopped;
+       
+       float *p, *no;
+       
+       int length;
+       int index;
+       /*********************************/
+       SK_Stroke *stroke;
+       int start;
+       int end;
+       int stride;
+} SK_StrokeIterator;
+
 SK_Sketch *GLOBAL_sketch = NULL;
 SK_Point boneSnap;
 
@@ -124,7 +145,7 @@ SK_Point boneSnap;
 
 /******************** PROTOTYPES ******************************/
 
-typedef int(NextSubdivisionFunc)(SK_Stroke*, int, int, float[3], float[3]);
+void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end);
 
 void sk_deleteSelectedStrokes(SK_Sketch *sketch);
 
@@ -133,10 +154,6 @@ void sk_freeSketch(SK_Sketch *sketch);
 
 SK_Point *sk_lastStrokePoint(SK_Stroke *stk);
 
-int nextFixedSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
-int nextLengthSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
-int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
-
 /******************** TEMPLATES UTILS *************************/
 
 char  *TEMPLATES_MENU = NULL;
@@ -990,18 +1007,20 @@ void sk_drawStroke(SK_Stroke *stk, int id, float color[3])
 //     glEnd();
 }
 
-void drawSubdividedStrokeBy(SK_Stroke *stk, int start, int end, NextSubdivisionFunc next_subdividion)
+void drawSubdividedStrokeBy(BArcIterator *iter, NextSubdivisionFunc next_subdividion)
 {
        float head[3], tail[3];
-       int bone_start = start;
+       int bone_start = 0;
+       int end = iter->length;
        int index;
 
-       VECCOPY(head, stk->points[start].p);
+       iter->head(iter);
+       VECCOPY(head, iter->p);
        
        glColor3f(0, 1, 1);
        glBegin(GL_POINTS);
        
-       index = next_subdividion(stk, bone_start, end, head, tail);
+       index = next_subdividion(iter, bone_start, end, head, tail);
        while (index != -1)
        {
                glVertex3fv(tail);
@@ -1009,7 +1028,7 @@ void drawSubdividedStrokeBy(SK_Stroke *stk, int start, int end, NextSubdivisionF
                VECCOPY(head, tail);
                bone_start = index; // start next bone from current index
 
-               index = next_subdividion(stk, bone_start, end, head, tail);
+               index = next_subdividion(iter, bone_start, end, head, tail);
        }
        
        glEnd();
@@ -1040,17 +1059,22 @@ void sk_drawStrokeSubdivision(SK_Stroke *stk)
                        {
                                if (i - head_index > 1)
                                {
+                                       SK_StrokeIterator sk_iter;
+                                       BArcIterator *iter = (BArcIterator*)&sk_iter;
+                                       
+                                       initStrokeIterator(iter, stk, head_index, i);
+
                                        if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
                                        {
-                                               drawSubdividedStrokeBy(stk, head_index, i, nextCorrelationSubdivision);
+                                               drawSubdividedStrokeBy(iter, nextCorrelationSubdivision);
                                        }
                                        else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
                                        {
-                                               drawSubdividedStrokeBy(stk, head_index, i, nextLengthSubdivision);
+                                               drawSubdividedStrokeBy(iter, nextLengthSubdivision);
                                        }
                                        else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
                                        {
-                                               drawSubdividedStrokeBy(stk, head_index, i, nextFixedSubdivision);
+                                               drawSubdividedStrokeBy(iter, nextFixedSubdivision);
                                        }
                                        
                                }
@@ -1354,13 +1378,29 @@ int sk_getStrokeEmbedPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_D
                        float vec[3];
                        float new_dist;
                        
-                       p1->flag = 0;
-                       
-                       for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
+                       p1->flag = 1;
+
+                       /* if peeling objects, take the first and last from each object */                      
+                       if (G.scene->snap_flag & SCE_SNAP_PEEL_OBJECT)
                        {
-                               /* nothing to do here */
+                               SK_DepthPeel *peel;
+                               for (peel = p1->next; peel; peel = peel->next)
+                               {
+                                       if (peel->ob == p1->ob)
+                                       {
+                                               peel->flag = 1;
+                                               p2 = peel;
+                                       }
+                               }
+                       }
+                       /* otherwise, pair first with second and so on */
+                       else
+                       {
+                               for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
+                               {
+                                       /* nothing to do here */
+                               }
                        }
-                       
                        
                        if (p2)
                        {
@@ -1528,250 +1568,175 @@ void sk_initDrawData(SK_DrawData *dd)
 }
 /********************************************/
 
-/* bone is assumed to be in GLOBAL space */
-void setBoneRollFromPoint(EditBone *bone, SK_Point *pt, float invmat[][4], float tmat[][3])
-{
-       float tangent[3], cotangent[3], normal[3];
-       
-       VecSubf(tangent, bone->tail, bone->head);
-       Crossf(cotangent, tangent, pt->no);
-       Crossf(normal, cotangent, tangent);
-       
-       Mat3MulVecfl(tmat, normal);
-       Normalize(normal);
-       
-       bone->roll = rollBoneToVector(bone, normal);
+static void* headPoint(void *arg);
+static void* tailPoint(void *arg);
+static void* nextPoint(void *arg);
+static void* nextNPoint(void *arg, int n);
+static void* peekPoint(void *arg, int n);
+static void* previousPoint(void *arg);
+static int   iteratorStopped(void *arg);
 
+static void initIteratorFct(SK_StrokeIterator *iter)
+{
+       iter->head = headPoint;
+       iter->tail = tailPoint;
+       iter->peek = peekPoint;
+       iter->next = nextPoint;
+       iter->nextN = nextNPoint;
+       iter->previous = previousPoint;
+       iter->stopped = iteratorStopped;        
 }
 
-float calcStrokeCorrelation(SK_Stroke *stk, int start, int end, float v0[3], float n[3])
+static SK_Point* setIteratorValues(SK_StrokeIterator *iter, int index)
 {
-       int len = 2 + abs(end - start);
+       SK_Point *pt = NULL;
        
-       if (len > 2)
+       if (index >= 0 && index < iter->length)
        {
-               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; 
+               pt = &(iter->stroke->points[iter->start + (iter->stride * index)]);
+               iter->p = pt->p;
+               iter->no = pt->no;
        }
        else
        {
-               return 1.0f;
+               iter->p = NULL;
+               iter->no = NULL;
        }
+       
+       return pt;
 }
 
-int nextFixedSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end)
 {
-       static float stroke_length = 0;
-       static float current_length;
-       static char n;
-       float length_threshold;
-       int i;
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+
+       initIteratorFct(iter);
+       iter->stroke = stk;
        
-       if (stroke_length == 0)
+       if (start < end)
        {
-               current_length = 0;
-               for (i = start + 1; i <= end; i++)
-               {
-                       stroke_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
-               }
-               
-               n = 0;
-               current_length = 0;
+               iter->start = start + 1;
+               iter->end = end - 1;
+               iter->stride = 1;
        }
-       
-       n++;
-       
-       length_threshold = n * stroke_length / G.scene->toolsettings->skgen_subdivision_number;
-       
-       /* < and not <= because we don't care about end, it is P_EXACT anyway */
-       for (i = start + 1; i < end; i++)
+       else
        {
-               current_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
-
-               if (current_length >= length_threshold)
-               {
-                       VECCOPY(p, stk->points[i].p);
-                       return i;
-               }
+               iter->start = start - 1;
+               iter->end = end + 1;
+               iter->stride = -1;
        }
        
-       stroke_length = 0;
+       iter->length = iter->stride * (iter->end - iter->start + 1);
        
-       return -1;
+       iter->index = -1;
 }
-int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+
+
+static void* headPoint(void *arg)
 {
-       float correlation_threshold = G.scene->toolsettings->skgen_correlation_limit;
-       float n[3];
-       int i;
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
        
-       for (i = start + 2; i <= end; i++)
-       {
-               /* Calculate normal */
-               VecSubf(n, stk->points[i].p, head);
-
-               if (calcStrokeCorrelation(stk, start, i, stk->points[start].p, n) < correlation_threshold)
-               {
-                       VECCOPY(p, stk->points[i - 1].p);
-                       return i - 1;
-               }
-       }
+       result = &(iter->stroke->points[iter->start - iter->stride]);
+       iter->p = result->p;
+       iter->no = result->no;
        
-       return -1;
+       return result;
 }
 
-int nextLengthSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+static void* tailPoint(void *arg)
 {
-       float lengthLimit = G.scene->toolsettings->skgen_length_limit;
-       int same = 1;
-       int i;
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
        
-       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, 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, 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(p, dv);
-                                       VecMulf(p, f);
-                                       VecAddf(p, p, vec0);
-                               }
-                               else
-                               {
-                                       VECCOPY(p, vec1);
-                               }
-                       }
-                       else
-                       {
-                               float dv[3];
-                               
-                               VecSubf(dv, vec1, vec0);
-                               Normalize(dv);
-                                
-                               VECCOPY(p, dv);
-                               VecMulf(p, lengthLimit);
-                               VecAddf(p, p, head);
-                       }
-                       
-                       return i - 1; /* restart at lower bound */
-               }
-               else
-               {
-                       i++;
-                       same = 0; // Reset same
-               }
-       }
+       result = &(iter->stroke->points[iter->end + iter->stride]);
+       iter->p = result->p;
+       iter->no = result->no;
        
-       return -1;
+       return result;
 }
 
-EditBone * subdivideStrokeBy(SK_Stroke *stk, int start, int end, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion)
+static void* nextPoint(void *arg)
 {
-       bArmature *arm = G.obedit->data;
-       EditBone *lastBone = NULL;
-       EditBone *child = NULL;
-       EditBone *parent = NULL;
-       int bone_start = start;
-       int index;
-       
-       parent = addEditBone("Bone", &G.edbo, arm);
-       VECCOPY(parent->head, stk->points[start].p);
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
        
-       index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
-       while (index != -1)
+       if (iter->index < iter->length)
        {
-               setBoneRollFromPoint(parent, &stk->points[index], invmat, tmat);
+               iter->index++;
+               result = setIteratorValues(iter, iter->index);
+       }
 
-               child = addEditBone("Bone", &G.edbo, arm);
-               VECCOPY(child->head, parent->tail);
-               child->parent = parent;
-               child->flag |= BONE_CONNECTED;
-               
-               /* going to next bone, fix parent */
-               Mat4MulVecfl(invmat, parent->tail);
-               Mat4MulVecfl(invmat, parent->head);
+       return result;
+}
 
-               parent = child; // new child is next parent
-               bone_start = index; // start next bone from current index
+static void* nextNPoint(void *arg, int n)
+{
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
+               
+       iter->index += n;
 
-               index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
+       /* check if passed end */
+       if (iter->index < iter->length)
+       {
+               result = setIteratorValues(iter, iter->index);
+       }
+       else
+       {
+               /* stop iterator if passed end */
+               iter->index = iter->length; 
        }
 
-       VECCOPY(parent->tail, stk->points[end].p);
+       return result;
+}
 
-       setBoneRollFromPoint(parent, &stk->points[end], invmat, tmat);
+static void* peekPoint(void *arg, int n)
+{
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
+       int index = iter->index + n;
 
-       /* fix last bone */
-       Mat4MulVecfl(invmat, parent->tail);
-       Mat4MulVecfl(invmat, parent->head);
-       lastBone = parent;
+       /* check if passed end */
+       if (index < iter->length)
+       {
+               result = setIteratorValues(iter, index);
+       }
+
+       return result;
+}
+
+static void* previousPoint(void *arg)
+{
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+       SK_Point *result = NULL;
        
-       return lastBone;
+       if (iter->index > 0)
+       {
+               iter->index--;
+               result = setIteratorValues(iter, iter->index);
+       }
+
+       return result;
 }
 
+static int iteratorStopped(void *arg)
+{
+       SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
+
+       if (iter->index == iter->length)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
 
 void sk_convertStroke(SK_Stroke *stk)
 {
-       bArmature *arm= G.obedit->data;
+       bArmature *arm = G.obedit->data;
        SK_Point *head;
        EditBone *parent = NULL;
        float invmat[4][4]; /* move in caller function */
@@ -1804,17 +1769,22 @@ void sk_convertStroke(SK_Stroke *stk)
                                
                                if (i - head_index > 1)
                                {
+                                       SK_StrokeIterator sk_iter;
+                                       BArcIterator *iter = (BArcIterator*)&sk_iter;
+
+                                       initStrokeIterator(iter, stk, head_index, i);
+                                       
                                        if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
                                        {
-                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextCorrelationSubdivision);
+                                               bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextCorrelationSubdivision);
                                        }
                                        else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
                                        {
-                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextLengthSubdivision);
+                                               bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextLengthSubdivision);
                                        }
                                        else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
                                        {
-                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextFixedSubdivision);
+                                               bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextFixedSubdivision);
                                        }
                                }
                                
@@ -1824,10 +1794,10 @@ void sk_convertStroke(SK_Stroke *stk)
                                        
                                        VECCOPY(bone->head, head->p);
                                        VECCOPY(bone->tail, pt->p);
-                                       setBoneRollFromPoint(bone, pt, invmat, tmat);
-                                       
+
                                        Mat4MulVecfl(invmat, bone->head);
                                        Mat4MulVecfl(invmat, bone->tail);
+                                       setBoneRollFromNormal(bone, pt->no, invmat, tmat);
                                }
                                
                                new_parent = bone;
@@ -1995,6 +1965,9 @@ int sk_getIntersections(ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
 
 int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
 {
+       SK_StrokeIterator sk_iter;
+       BArcIterator *iter = (BArcIterator*)&sk_iter;
+       
        float CORRELATION_THRESHOLD = 0.99f;
        float *vec;
        int i, j;
@@ -2002,6 +1975,8 @@ int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
        sk_appendStrokePoint(segments, &gesture->points[0]);
        vec = segments->points[segments->nb_points - 1].p;
 
+       initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1);
+
        for (i = 1, j = 0; i < gesture->nb_points; i++)
        { 
                float n[3];
@@ -2009,7 +1984,7 @@ int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
                /* Calculate normal */
                VecSubf(n, gesture->points[i].p, vec);
                
-               if (calcStrokeCorrelation(gesture, j, i, vec, n) < CORRELATION_THRESHOLD)
+               if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD)
                {
                        j = i - 1;
                        sk_appendStrokePoint(segments, &gesture->points[j]);
index bb53269bf12863909811ce97a71b03352ab82bd5..553a758c9d59a5f077f00ff6beb0b1ab0d85f63b 100644 (file)
@@ -850,7 +850,8 @@ void fillArcEmptyBuckets(ReebArc *arc)
 
 static void ExtendArcBuckets(ReebArc *arc)
 {
-       ReebArcIterator iter;
+       ReebArcIterator arc_iter;
+       BArcIterator *iter = (BArcIterator*)&arc_iter;
        EmbedBucket *last_bucket, *first_bucket;
        float *previous = NULL;
        float average_length = 0, length;
@@ -861,16 +862,16 @@ static void ExtendArcBuckets(ReebArc *arc)
                return; /* failsafe, shouldn't happen */
        }
        
-       initArcIterator(&iter, arc, arc->head);
-       iter.next(&iter);
-       previous = iter.p;
+       initArcIterator(iter, arc, arc->head);
+       IT_next(iter);
+       previous = iter->p;
        
-       for (   iter.next(&iter);
-                       iter.stopped(&iter) == 0;
-                       previous = iter.p, iter.next(&iter)
+       for (   IT_next(iter);
+                       IT_stopped(iter) == 0;
+                       previous = iter->p, IT_next(iter)
                )
        {
-               average_length += VecLenf(previous, iter.p);
+               average_length += VecLenf(previous, iter->p);
        }
        average_length /= (arc->bcount - 1);
        
@@ -927,19 +928,20 @@ void extendGraphBuckets(ReebGraph *rg)
 
 void calculateArcLength(ReebArc *arc)
 {
-       ReebArcIterator iter;
+       ReebArcIterator arc_iter;
+       BArcIterator *iter = (BArcIterator*)&arc_iter;
        float *vec0, *vec1;
 
        arc->length = 0;
        
-       initArcIterator(&iter, arc, arc->head);
+       initArcIterator(iter, arc, arc->head);
 
        vec0 = arc->head->p;
        vec1 = arc->head->p; /* in case there's no embedding */
 
-       while (iter.next(&iter))        
+       while (IT_next(iter))   
        {
-               vec1 = iter.p;
+               vec1 = iter->p;
                
                arc->length += VecLenf(vec0, vec1);
                
@@ -996,28 +998,30 @@ void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count)
                 * */
                if (arc1->bcount > 0 && arc2->bcount > 0)
                {
-                       ReebArcIterator iter1, iter2;
+                       ReebArcIterator arc_iter1, arc_iter2;
+                       BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+                       BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
                        EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
                        
-                       initArcIterator(&iter1, arc1, (ReebNode*)root_node);
-                       initArcIterator(&iter2, arc2, (ReebNode*)root_node);
+                       initArcIterator(iter1, arc1, (ReebNode*)root_node);
+                       initArcIterator(iter2, arc2, (ReebNode*)root_node);
                        
-                       bucket1 = iter1.next(&iter1);
-                       bucket2 = iter2.next(&iter2);
+                       bucket1 = IT_next(iter1);
+                       bucket2 = IT_next(iter2);
                
                        /* Make sure they both start at the same value */       
                        while(bucket1 && bucket2 && bucket1->val < bucket2->val)
                        {
-                               bucket1 = iter1.next(&iter1);
+                               bucket1 = IT_next(iter1);
                        }
                        
                        while(bucket1 && bucket2 && bucket2->val < bucket1->val)
                        {
-                               bucket2 = iter2.next(&iter2);
+                               bucket2 = IT_next(iter2);
                        }
        
        
-                       for ( ;bucket1 && bucket2; bucket1 = iter1.next(&iter1), bucket2 = iter2.next(&iter2))
+                       for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
                        {
                                bucket2->nv += bucket1->nv; /* add counts */
                                
@@ -1056,28 +1060,30 @@ void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count)
                 * */
                if (arc1->bcount > 0 && arc2->bcount > 0)
                {
-                       ReebArcIterator iter1, iter2;
+                       ReebArcIterator arc_iter1, arc_iter2;
+                       BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+                       BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
                        EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
                        
-                       initArcIterator(&iter1, arc1, node);
-                       initArcIterator(&iter2, arc2, node);
+                       initArcIterator(iter1, arc1, node);
+                       initArcIterator(iter2, arc2, node);
                        
-                       bucket1 = iter1.next(&iter1);
-                       bucket2 = iter2.next(&iter2);
+                       bucket1 = IT_next(iter1);
+                       bucket2 = IT_next(iter2);
                
                        /* Make sure they both start at the same value */       
                        while(bucket1 && bucket1->val < bucket2->val)
                        {
-                               bucket1 = iter1.next(&iter1);
+                               bucket1 = IT_next(iter1);
                        }
                        
                        while(bucket2 && bucket2->val < bucket1->val)
                        {
-                               bucket2 = iter2.next(&iter2);
+                               bucket2 = IT_next(iter2);
                        }
        
        
-                       for ( ;bucket1 && bucket2; bucket1 = iter1.next(&iter1), bucket2 = iter1.next(&iter2))
+                       for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
                        {
                                /* copy and mirror back to bucket2 */                   
                                bucket2->nv = bucket1->nv;
@@ -1115,28 +1121,30 @@ void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BAr
         * */
        if (arc1->bcount > 0 && arc2->bcount > 0)
        {
-               ReebArcIterator iter1, iter2;
+               ReebArcIterator arc_iter1, arc_iter2;
+               BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+               BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
                EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
                
-               initArcIterator(&iter1, arc1, (ReebNode*)root_node);
-               initArcIterator(&iter2, arc2, (ReebNode*)root_node);
+               initArcIterator(iter1, arc1, (ReebNode*)root_node);
+               initArcIterator(iter2, arc2, (ReebNode*)root_node);
                
-               bucket1 = iter1.next(&iter1);
-               bucket2 = iter2.next(&iter2);
+               bucket1 = IT_next(iter1);
+               bucket2 = IT_next(iter2);
        
                /* Make sure they both start at the same value */       
                while(bucket1 && bucket1->val < bucket2->val)
                {
-                       bucket1 = iter1.next(&iter1);
+                       bucket1 = IT_next(iter1);
                }
                
                while(bucket2 && bucket2->val < bucket1->val)
                {
-                       bucket2 = iter1.next(&iter2);
+                       bucket2 = IT_next(iter2);
                }
 
 
-               for ( ;bucket1 && bucket2; bucket1 = iter2.next(&iter1), bucket2 = iter2.next(&iter2))
+               for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
                {
                        bucket1->nv += bucket2->nv; /* add counts */
                        
@@ -1763,15 +1771,16 @@ int filterSmartReebGraph(ReebGraph *rg, float threshold)
                                EditFace *efa = BLI_ghashIterator_getValue(&ghi);
 
 #if 0
-                               ReebArcIterator iter;
+                               ReebArcIterator arc_iter;
+                               BArcIterator *iter = (BArcIterator*)&arc_iter;
                                EmbedBucket *bucket = NULL;
                                EmbedBucket *previous = NULL;
                                float min_distance = -1;
                                float angle = 0;
                
-                               initArcIterator(&iter, arc, arc->head);
+                               initArcIterator(iter, arc, arc->head);
                
-                               bucket = nextBucket(&iter);
+                               bucket = nextBucket(iter);
                                
                                while (bucket != NULL)
                                {
@@ -1806,7 +1815,7 @@ int filterSmartReebGraph(ReebGraph *rg, float threshold)
                                        }
                                        
                                        previous = bucket;
-                                       bucket = nextBucket(&iter);
+                                       bucket = nextBucket(iter);
                                }
                                
                                avg_angle += saacos(fabs(angle));
@@ -3296,14 +3305,18 @@ void arcToVCol(ReebGraph *rg, EditMesh *em, int index)
 
 /****************************************** BUCKET ITERATOR **************************************************/
 
-void* nextBucket(void *arg);
-void* nextNBucket(void *arg, int n);
-void* peekBucket(void *arg, int n);
-void* previousBucket(void *arg);
-int iteratorStopped(void *arg);
+static void* headNode(void *arg);
+static void* tailNode(void *arg);
+static void* nextBucket(void *arg);
+static void* nextNBucket(void *arg, int n);
+static void* peekBucket(void *arg, int n);
+static void* previousBucket(void *arg);
+static int   iteratorStopped(void *arg);
 
-void initIteratorFct(ReebArcIterator *iter)
+static void initIteratorFct(ReebArcIterator *iter)
 {
+       iter->head = headNode;
+       iter->tail = tailNode;
        iter->peek = peekBucket;
        iter->next = nextBucket;
        iter->nextN = nextNBucket;
@@ -3311,7 +3324,7 @@ void initIteratorFct(ReebArcIterator *iter)
        iter->stopped = iteratorStopped;        
 }
 
-void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket)
+static void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket)
 {
        if (bucket)
        {
@@ -3325,8 +3338,10 @@ void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket)
        }
 }
 
-void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head)
+void initArcIterator(BArcIterator *arg, ReebArc *arc, ReebNode *head)
 {
+       ReebArcIterator *iter = (ReebArcIterator*)arg;
+
        initIteratorFct(iter);
        iter->arc = arc;
        
@@ -3345,11 +3360,13 @@ void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head)
        
        iter->length = arc->bcount;
        
-       iter->index = iter->start - iter->stride;
+       iter->index = -1;
 }
 
-void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start)
+void initArcIteratorStart(BArcIterator *arg, struct ReebArc *arc, struct ReebNode *head, int start)
 {
+       ReebArcIterator *iter = (ReebArcIterator*)arg;
+
        initIteratorFct(iter);
        iter->arc = arc;
        
@@ -3366,7 +3383,7 @@ void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, str
                iter->stride = -1;
        }
        
-       iter->index = iter->start - iter->stride;
+       iter->index = -1;
        
        iter->length = arc->bcount - start;
 
@@ -3376,8 +3393,10 @@ void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, str
        }
 }
 
-void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end)
+void initArcIterator2(BArcIterator *arg, ReebArc *arc, int start, int end)
 {
+       ReebArcIterator *iter = (ReebArcIterator*)arg;
+
        initIteratorFct(iter);
        iter->arc = arc;
        
@@ -3393,86 +3412,124 @@ void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end)
                iter->stride = -1;
        }
 
-       iter->index = iter->start - iter->stride;
+       iter->index = -1;
 
        iter->length = abs(iter->end - iter->start) + 1;
 }
 
-void* nextBucket(void *arg)
+static void* headNode(void *arg)
+{
+       ReebArcIterator *iter = (ReebArcIterator*)arg;
+       ReebNode *node;
+       
+       if (iter->start < iter->end)
+       {
+               node = iter->arc->head;
+       }
+       else
+       {
+               node = iter->arc->tail;
+       }
+       
+       iter->p = node->p;
+       iter->no = node->no;
+       
+       return node;
+}
+
+static void* tailNode(void *arg)
+{
+       ReebArcIterator *iter = (ReebArcIterator*)arg;
+       ReebNode *node;
+       
+       if (iter->start < iter->end)
+       {
+               node = iter->arc->tail;
+       }
+       else
+       {
+               node = iter->arc->head;
+       }
+       
+       iter->p = node->p;
+       iter->no = node->no;
+       
+       return node;
+}
+
+static void* nextBucket(void *arg)
 {
        ReebArcIterator *iter = (ReebArcIterator*)arg;
        EmbedBucket *result = NULL;
        
-       if (iter->index != iter->end)
+       if (iter->index < iter->length)
        {
-               iter->index += iter->stride;
-               result = &(iter->arc->buckets[iter->index]);
+               iter->index++;
+               result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
        }
        
        setIteratorValues(iter, result);
        return result;
 }
 
-void* nextNBucket(void *arg, int n)
+static void* nextNBucket(void *arg, int n)
 {
        ReebArcIterator *iter = (ReebArcIterator*)arg;
        EmbedBucket *result = NULL;
                
-       iter->index += n * iter->stride;
+       iter->index += n;
 
        /* check if passed end */
-       if ((iter->stride == 1 && iter->index <= iter->end) ||
-               (iter->stride == -1 && iter->index >= iter->end))
+       if (iter->index < iter->length)
        {
-               result = &(iter->arc->buckets[iter->index]);
+               result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
        }
        else
        {
                /* stop iterator if passed end */
-               iter->index = iter->end
+               iter->index = iter->length
        }
        
        setIteratorValues(iter, result);
        return result;
 }
 
-void* peekBucket(void *arg, int n)
+static void* peekBucket(void *arg, int n)
 {
        ReebArcIterator *iter = (ReebArcIterator*)arg;
        EmbedBucket *result = NULL;
-       int index = iter->index + n * iter->stride;
+       int index = iter->index + n;
 
        /* check if passed end */
-       if ((iter->stride == 1 && index <= iter->end && index >= iter->start) ||
-               (iter->stride == -1 && index >= iter->end && index <= iter->start))
+       if (index < iter->length)
        {
-               result = &(iter->arc->buckets[index]);
+               result = &(iter->arc->buckets[iter->start + (iter->stride * index)]);
        }
 
        setIteratorValues(iter, result);
        return result;
 }
 
-void* previousBucket(void *arg)
+static void* previousBucket(void *arg)
 {
        ReebArcIterator *iter = (ReebArcIterator*)arg;
        EmbedBucket *result = NULL;
        
-       if (iter->index != iter->start)
+       if (iter->index > 0)
        {
-               iter->index -= iter->stride;
-               result = &(iter->arc->buckets[iter->index]);
+               iter->index--;
+               result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
        }
 
        setIteratorValues(iter, result);
        return result;
 }
 
-int iteratorStopped(void *arg)
+static int iteratorStopped(void *arg)
 {
        ReebArcIterator *iter = (ReebArcIterator*)arg;
 
-       if (iter->index == iter->end)
+       if (iter->index == iter->length)
        {
                return 1;
        }
@@ -3711,7 +3768,8 @@ void REEB_draw()
        glDisable(GL_DEPTH_TEST);
        for (arc = rg->arcs.first; arc; arc = arc->next, i++)
        {
-               ReebArcIterator iter;
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
                float vec[3];
                char text[128];
                char *s = text;
@@ -3723,10 +3781,10 @@ void REEB_draw()
                        
                        if (arc->bcount)
                        {
-                               initArcIterator(&iter, arc, arc->head);
-                               for (iter.next(&iter); iter.stopped(&iter) == 0; iter.next(&iter))
+                               initArcIterator(iter, arc, arc->head);
+                               for (IT_next(iter); IT_stopped(iter) == 0; IT_next(iter))
                                {
-                                       glVertex3fv(iter.p);
+                                       glVertex3fv(iter->p);
                                }
                        }
                        
@@ -3756,10 +3814,10 @@ void REEB_draw()
                        
                        if (arc->bcount)
                        {
-                               initArcIterator(&iter, arc, arc->head);
-                               for (iter.next(&iter); iter.stopped(&iter) == 0; iter.next(&iter))
+                               initArcIterator(iter, arc, arc->head);
+                               for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
                                {
-                                       glVertex3fv(iter.p);
+                                       glVertex3fv(iter->p);
                                }
                        }
                        
@@ -3777,10 +3835,10 @@ void REEB_draw()
                                glColor3f(0.5f, 0.5f, 1);                               
                                if (arc->bcount)
                                {
-                                       initArcIterator(&iter, arc, arc->head);
-                                       for (iter.next(&iter); iter.stopped(&iter) == 0; iter.next(&iter))
+                                       initArcIterator(iter, arc, arc->head);
+                                       for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
                                        {
-                                               glVertex3fv(iter.p);
+                                               glVertex3fv(iter->p);
                                        }
                                }
                        glEnd();