Added method to remove vertices from basic meshes by remapping the v/e/l/p custom...
[blender.git] / source / blender / editors / sculpt_paint / sculpt.c
index b6b45b68c10e2d67bafd9cd147c9c98974f7738c..8f2d0242ea0112bafa524d7b9ff148d892ec01dc 100644 (file)
 #include "BLI_alloca.h"
 #include "BLI_array.h"
 
-/*#define DEBUG_DRAW*/
+#define SIL_STROKE_STORE_CHUNK 512
+/* Store bias is used to bias a close estimate since resizing is more expensive than bigger array on first allocate*/
+#define STORE_ESTIMATE_BIAS 0.1f
+/* Fillet Blur determines the fuzziness wether a vert is intersecting or not.
+ * Important for example if two shapes with the same thickness intersect. */
+#define SIL_FILLET_BLUR_MAX 0.3f
+#define SIL_FILLET_BLUR_MIN 0.001f
+
+#define DEBUG_DRAW
 #ifdef DEBUG_DRAW
 /* static void bl_debug_draw(void);*/
 /* add these locally when using these functions for testing */
@@ -142,6 +150,117 @@ static void bl_debug_draw_point(const float pos[3],const float thickness)
 }
 #endif
 
+typedef struct {
+       float bmin[3], bmax[3];
+} BB;
+
+/*     init data:
+ *     Silhouette Data */
+typedef struct SilhouetteStroke {
+       float *points;
+       float *points_v2;
+       int totvert;
+       int max_verts;
+       BB bb;
+} SilhouetteStroke;
+
+#ifdef DEBUG_DRAW
+void bl_debug_draw_BB_add(BB *bb,const unsigned int col){
+       float v1[3],v2[3],v3[3],v4[3];
+       float xd[3], yd[3], zd[3];
+
+       bl_debug_color_set(col);
+
+       xd[0] = bb->bmax[0]-bb->bmin[0];
+       xd[1] = 0.0f;
+       xd[2] = 0.0f;
+
+       yd[0] = 0.0f;
+       yd[1] = bb->bmax[1]-bb->bmin[1];
+       yd[2] = 0.0f;
+
+       zd[0] = 0.0f;
+       zd[1] = 0.0f;
+       zd[2] = bb->bmax[2]-bb->bmin[2];
+
+       copy_v3_v3(v1,bb->bmin);
+       copy_v3_v3(v2,bb->bmin);
+       add_v3_v3(v2,xd);
+       add_v3_v3v3(v3,v1,yd);
+       add_v3_v3v3(v4,v2,yd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       add_v3_v3v3(v3,v1,zd);
+       add_v3_v3v3(v4,v2,zd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       sub_v3_v3v3(v3,v1,yd);
+       sub_v3_v3v3(v4,v2,yd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       sub_v3_v3v3(v3,v1,zd);
+       sub_v3_v3v3(v4,v2,zd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+       
+}
+#endif
+
+
+typedef enum {
+       SIL_INIT = 0,
+       SIL_DRAWING = 1,
+       SIL_OP = 2
+} SilhouetteState;
+
+typedef struct SilhouetteData {
+       ARegion *ar;            /* region that Silhouette started drawn in */
+       void *draw_handle;      /* for drawing preview loop */
+       ViewContext vc;
+       SilhouetteStroke *current_stroke;
+       Object *ob;
+       BMEditMesh *em;                 /*Triangulated stroke for spine generation*/
+       Scene *scene;
+
+       float add_col[3];               /* preview color */
+       float last_mouse_pos[2];
+
+       SilhouetteState state;  /* Operator state */
+
+       float depth;                                    /* Depth or thickness of the generated shape */
+       float smoothness;                               /* Smoothness of the generated shape */
+       int resolution;                                 /* Subdivision of the shape*/
+       float anchor[3];                                /* Origin point of the reference plane */
+       float z_vec[3];                                 /* Orientation of the reference plane */
+       MeshElemMap *emap;                              /* Original Mesh vert -> edges map */
+       GHash *i_edges;                                 /* Edges crossing the both shapes. (only orig mesh)*/
+       int *fillet_ring_orig;                  /* ring_edges to connect to in the orig mesh */
+       int *fillet_ring_orig_start;    /* start positions to each individual ring */
+       int *fillet_ring_new;                   /* ring_edges to connect to in the new mesh */
+       int *fillet_ring_new_start;             /* start positions to each individual ring */
+       int num_rings, fillet_ring_tot;
+       int *inter_edges;                               /* edges crossing the two shapes */
+       int num_inter_edges;                    /* number of edges crossing */
+       BB *fillet_ring_bbs;                            /* every ring gets a Bounding box to check intersection with branches */
+} SilhouetteData;
+
 /** \name Tool Capabilities
  *
  * Avoid duplicate checks, internal logic only,
@@ -548,6 +667,9 @@ typedef struct SculptThreadedTaskData {
        float strength;
        bool smooth_mask;
        bool has_bm_orco;
+       SilhouetteData *sil;
+       int *v_to_rm; /* Shared array handle access with mutex! */
+       int num_v_to_rm;
 
        SculptProjectVector *spvc;
        float *offset;
@@ -4749,8 +4871,11 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
                                     const float mouse[2])
 {
        /* Don't start the stroke until mouse goes over the mesh.
-        * note: mouse will only be null when re-executing the saved stroke. */
-       if (!mouse || over_mesh(C, op, mouse[0], mouse[1])) {
+        * note: mouse will only be null when re-executing the saved stroke.
+        * We have exception for 'exec' strokes since they may not set 'mouse', only 'location', see: T52195. */
+       if (((op->flag & OP_IS_INVOKE) == 0) ||
+           (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1]))
+       {
                Object *ob = CTX_data_active_object(C);
                SculptSession *ss = ob->sculpt;
                Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -5024,40 +5149,36 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
 
 /****************** Topology tools Silhouette ******************/
 
-/*     init data:
- *     Silhouette Data */
-typedef struct SilhouetteStroke {
-       float *points;
-       int totvert;
-       int max_verts;
-}SilhouetteStroke;
+/* Axis-aligned bounding box (Same as in pbvh_intern.h)*/
 
-typedef enum {
-       SIL_INIT = 0,
-       SIL_DRAWING = 1,
-       SIL_OP = 2
-} SilhouetteState;
+/* TODO: import BB functions */
+/* Expand the bounding box to include a new coordinate */
+static void BB_expand(BB *bb, const float co[3])
+{
+       for (int i = 0; i < 3; ++i) {
+               bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
+               bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
+       }
+}
 
-typedef struct SilhouetteData {
-       ARegion *ar;            /* region that Silhouette started drawn in */
-       void *draw_handle;      /* for drawing preview loop */
-       ViewContext vc;
-       SilhouetteStroke *current_stroke;
-       Object *ob;
-       BMEditMesh *em;                 /*Triangulated stroke for spine generation*/
-       Scene *scene;
+static void BB_reset(BB *bb)
+{
+       bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
+       bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
+}
 
-       float add_col[3];               /* preview color */
-       float last_mouse_pos[2];
+static bool bb_intersect(BB *bb1, BB *bb2) {
+       int i;
 
-       SilhouetteState state;  /* Operator state */
+       /* min is inclusive max is exclusive? BB*/
+       for (i = 0; i < 3; ++i) {
+               if(bb1->bmin[i] >= bb2->bmax[i] || bb1->bmax[i] < bb2->bmin[i]){
+                       return false;
+               }
+       }
 
-       float depth;                    /* Depth or thickness of the generated shape */
-       float smoothness;               /* Smoothness of the generated shape */
-       int resolution;                 /* Subdivision of the shape*/
-       float anchor[3];                /* Origin point of the reference plane */
-       float z_vec[3];                 /* Orientation of the reference plane */
-} SilhouetteData;
+       return true;
+}
 
 static void silhouette_stroke_free(SilhouetteStroke *stroke)
 {
@@ -5069,13 +5190,14 @@ static void silhouette_stroke_free(SilhouetteStroke *stroke)
        }
 }
 
-static SilhouetteStroke *silhouette_stroke_new(int max_verts)
+static SilhouetteStroke *silhouette_stroke_new()
 {
        SilhouetteStroke *stroke = MEM_callocN(sizeof(SilhouetteStroke), "SilhouetteStroke");
-       stroke->points = 0;
-       stroke->points = MEM_callocN(sizeof(float) * 3 * max_verts,"SilhouetteStrokePoints");/* TODO: Dynamic length */
+       stroke->points = MEM_callocN(sizeof(float) * 3 * SIL_STROKE_STORE_CHUNK,"SilhouetteStrokePoints");
+       stroke->points_v2 = MEM_callocN(sizeof(float) * 2 * SIL_STROKE_STORE_CHUNK,"SilhouetteStrokePoints");
        stroke->totvert = 0;
-       stroke->max_verts = max_verts;
+       stroke->max_verts = SIL_STROKE_STORE_CHUNK;
+       BB_reset(&stroke->bb);
        return stroke;
 }
 
@@ -5089,7 +5211,7 @@ static SilhouetteData *silhouette_data_new(bContext *C)
        const float *fp = ED_view3d_cursor3d_get(scene, v3d);
 
        sil->ar = CTX_wm_region(C);
-       sil->current_stroke = silhouette_stroke_new(1024);
+       sil->current_stroke = silhouette_stroke_new();
        view3d_set_viewcontext(C, &sil->vc);
 
        sil->add_col[0] = 1.00; /* add mode color is light red */
@@ -5103,6 +5225,14 @@ static SilhouetteData *silhouette_data_new(bContext *C)
 
        copy_v3_v3(sil->anchor, fp);
 
+       /* Intersection variables */
+       sil->fillet_ring_orig = NULL;
+       sil->fillet_ring_orig_start = NULL;
+       sil->fillet_ring_new = NULL;
+       sil->fillet_ring_new_start = NULL;
+       sil->inter_edges = NULL;
+       sil->fillet_ring_bbs = NULL;
+
        sil->scene = scene;
        sil->ob = obedit;
        sil->state = SIL_INIT;
@@ -5115,6 +5245,25 @@ static void silhouette_data_free(struct wmOperator *op)
        data = op->customdata;
        if (data) {
                silhouette_stroke_free(data->current_stroke);
+
+               if (data->inter_edges) {
+                       MEM_freeN(data->inter_edges);
+               }
+               if (data->fillet_ring_orig) {
+                       MEM_freeN(data->fillet_ring_orig);
+               }
+               if (data->fillet_ring_orig_start) {
+                       MEM_freeN(data->fillet_ring_orig_start);
+               }
+               if (data->fillet_ring_new) {
+                       MEM_freeN(data->fillet_ring_new);
+               }
+               if (data->fillet_ring_new_start) {
+                       MEM_freeN(data->fillet_ring_new_start);
+               }
+               if (data->fillet_ring_bbs) {
+                       MEM_freeN(data->fillet_ring_bbs);
+               }
                MEM_SAFE_FREE(data);
        }
 }
@@ -5125,31 +5274,42 @@ static void silhoute_stroke_point_to_3d(SilhouetteData *sil, int point, float r_
        /*ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, &sil->current_stroke->points[point], r_v);*/
 }
 
+#if 0
 /* TODO: Add dynamic memory allocation */
 static void silhouette_stroke_add_3Dpoint(SilhouetteStroke *stroke, float point[3])
 {
-       if (stroke->totvert < stroke->max_verts) {
-               copy_v3_v3(&stroke->points[stroke->totvert * 3], point);
-               stroke->totvert ++;
-       } else {
-               printf("Stroke reached maximum vert count.\n");
+       if (stroke->totvert >= stroke->max_verts) {
+               stroke->max_verts += SIL_STROKE_STORE_CHUNK;
+               stroke->points = MEM_reallocN(stroke->points, sizeof(float) * 3 * stroke->max_verts);
+               stroke->points_v2 = MEM_reallocN(stroke->points_v2, sizeof(float) * 2 * stroke->max_verts);
        }
+
+       copy_v3_v3(&stroke->points[stroke->totvert * 3], point);
+       stroke->totvert ++;
 }
+#endif
 
 static void silhouette_stroke_add_point(SilhouetteData *sil, SilhouetteStroke *stroke, float point[2])
 {
-       if (stroke->totvert < stroke->max_verts) {
-               ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, point, &sil->current_stroke->points[stroke->totvert * 3]);
-               stroke->totvert ++;
-       } else {
-               printf("Stroke reached maximum vert count.\n");
+       if (stroke->totvert >= stroke->max_verts) {
+               stroke->max_verts += SIL_STROKE_STORE_CHUNK;
+               stroke->points = MEM_reallocN(stroke->points, sizeof(float) * 3 * stroke->max_verts);
+               stroke->points_v2 = MEM_reallocN(stroke->points_v2, sizeof(float) * 2 * stroke->max_verts);
        }
+
+       copy_v2_v2(&stroke->points_v2[stroke->totvert * 2], point);
+       ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, point, &sil->current_stroke->points[stroke->totvert * 3]);
+       BB_expand(&stroke->bb, &sil->current_stroke->points[stroke->totvert * 3]);
+       stroke->totvert ++;
 }
 
 /* Set reference plane, 3D plane which is drawn on in 2D */
 static void silhouette_set_ref_plane(SilhouetteData *sil)
 {
-       ED_view3d_global_to_vector(sil->ar->regiondata, sil->anchor, sil->z_vec);
+       /*Get the view vector. Same as ED_view3d_global_to_vector from the center of screen or orthographic*/
+       negate_v3_v3(sil->z_vec, sil->vc.rv3d->viewinv[2]);
+       normalize_v3(sil->z_vec);
+       /*ED_view3d_global_to_vector(sil->ar->regiondata, sil->anchor, sil->z_vec);*/
 }
 
 static void sculpt_silhouette_stroke_update(float mouse[2], SilhouetteData *sil)
@@ -5194,6 +5354,8 @@ typedef struct SpineBranch{
        BranchState flag;
        int *e_start_arr;               /* Edges on the ends are stored (used primarly for bridging) */
        int fs_bs_offset;               /* Frontside edge offset to backside*/
+       int *e_flip_side_ends;  /* Front and backside connecting edges of each part*/
+       bool intersecting;
 }SpineBranch;
 
 /* Main Tree Container */
@@ -5202,6 +5364,31 @@ typedef struct Spine{
        SpineBranch **branches; /* All branches. Can contain Null pointers if branches got removed*/
 }Spine;
 
+typedef struct {
+       SculptSession *ss;
+       BB *bb_target;
+       bool original;
+} SculptSearchBBData;
+
+/* Search nodes to integrate another BB into (used for silhouette)*/
+static bool sculpt_search_BB_cb(PBVHNode *node, void *data_v)
+{
+       SculptSearchBBData *data = data_v;
+       BB *bb_target = data->bb_target;
+       float bb_min[3], bb_max[3];
+       int i;
+
+       BKE_pbvh_node_get_BB(node, bb_min, bb_max);
+
+       /* min is inclusive max is exclusive? BB*/
+       for (i = 0; i < 3; ++i) {
+               if(bb_target->bmin[i] >= bb_max[i] || bb_target->bmax[i] < bb_min[i]){
+                       return false;
+               }
+       }
+       return true;
+}
+
 static int get_adjacent_faces(BMFace *f, BMFace **ad_f, BMFace *last_f)
 {
        int ad_faces = 0;
@@ -5294,6 +5481,7 @@ static void free_spine_branch(SpineBranch *branch)
        }
        if (branch->flag & BRANCH_EDGE_GEN) {
                MEM_freeN(branch->e_start_arr);
+               MEM_freeN(branch->e_flip_side_ends);
        }
        MEM_freeN(branch);
 }
@@ -5554,7 +5742,7 @@ static void calc_vert_quarter(Mesh *me, float a[3], float b[3], float c[3], int
        float v1[3], v2[3], v3[3], v4[3], v5[3], up[3], side[3], d[3];
        float f_sin, f_cos;
        int s_steps_w = inv_smooth * w_h_steps;
-       int s_steps_v = inv_smooth * v_steps;
+       int s_steps_v = fmax(1, inv_smooth * v_steps);
        int s_steps_c = v_steps - s_steps_v + w_h_steps - s_steps_w;
 
        ED_mesh_vertices_add(me, NULL, v_steps + w_h_steps - (flip_side ? 1 : 0));
@@ -5833,6 +6021,52 @@ static int add_quad(Mesh *me, int edge_b, int edge_a, int edge_c, bool flip)
        return e_start;
 }
 
+static void add_face(Mesh *me, int e1, int e2, int e3, int e4, int l_start, int p_start, bool flip){
+       int comp_v1;
+
+       if (me->medge[e1].v1 == me->medge[e2].v1 || me->medge[e1].v1 == me->medge[e2].v2) {
+               comp_v1 = me->medge[e1].v1;
+               me->mloop[l_start].v = me->medge[e1].v2;
+               me->mloop[l_start].e = e1;
+       } else {
+               comp_v1 = me->medge[e1].v2;
+               me->mloop[l_start].v = me->medge[e1].v1;
+               me->mloop[l_start].e = e1;
+       }
+       if (me->medge[e2].v1 == comp_v1) {
+               me->mloop[l_start + (flip ? 3 : 1)].v = me->medge[e2].v1;
+               comp_v1 = me->medge[e2].v2;
+       } else {
+               me->mloop[l_start + (flip ? 3 : 1)].v = me->medge[e2].v2;
+               comp_v1 = me->medge[e2].v1;
+       }
+       me->mloop[l_start + (flip ? 3 : 1)].e = e2;
+
+       if (me->medge[e3].v1 == comp_v1) {
+               me->mloop[l_start + 2].v = me->medge[e3].v1;
+               comp_v1 = me->medge[e3].v2;
+       } else {
+               me->mloop[l_start + 2].v = me->medge[e3].v2;
+               comp_v1 = me->medge[e3].v1;
+       }
+       me->mloop[l_start + 2].e = e3;
+
+       if (me->medge[e4].v1 == comp_v1) {
+               me->mloop[l_start + (flip ? 1 : 3)].v = me->medge[e4].v1;
+               comp_v1 = me->medge[e4].v2;
+       } else {
+               me->mloop[l_start + (flip ? 1 : 3)].v = me->medge[e4].v2;
+               comp_v1 = me->medge[e4].v1;
+       }
+       me->mloop[l_start + (flip ? 1 : 3)].e = e4;
+
+       me->mpoly[p_start].totloop = 4;
+       me->mpoly[p_start].loopstart = l_start;
+       me->mpoly[p_start].mat_nr = 0;
+       me->mpoly[p_start].flag = 0;
+       me->mpoly[p_start].pad = 0;
+}
+
 /* TODO: is there a sort function already?*/
 static int cmpfunc (const void * a, const void * b)
 {
@@ -5939,7 +6173,8 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
        int e_cap_start_a, e_cap_start_b, e_cap_start_c;
        int e_corner_a, e_corner_b;
        int cap_end_flip_e_start, cap_end_flip_start_a_l, cap_end_flip_start_b_l;
-       int cap_end_flip_start_a_r, cap_end_flip_start_b_r;
+       int cap_end_flip_start_a_r, cap_end_flip_start_b_r, e_cap_tube_start, e_cap_tube_end;
+       int e_flip_tube_end[2];
        BLI_array_declare(cap_p);
 
        if (!flip_side) {
@@ -5964,7 +6199,8 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
        }
 
        if (!(branch->flag & BRANCH_EDGE_GEN)) {
-               branch->e_start_arr = MEM_callocN(sizeof(int) * 4,"edge startposition array");
+               branch->e_start_arr = MEM_callocN(sizeof(int) * 4, "edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 2, "fs bs edges");
                branch->flag |= BRANCH_EDGE_GEN;
        }
 
@@ -6024,6 +6260,7 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                        cap_length = totlength - left[totl * 4 - 1] - right[totr * 4 - 1];
 
                        if (flip_side) {
+                               branch->e_flip_side_ends[0] = me->totedge;
                                bridge_loops(me,
                                                         e_flip_start + 1,
                                                         e_flip_start - branch->fs_bs_offset + 1,
@@ -6032,7 +6269,8 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                                                         ((v_steps - 1) * 2 + w_steps) * 2 - 1,
                                                         (v_steps * 2 + w_steps) * 2 - 1,
                                                         !n_g_flip);
-
+                               branch->e_flip_side_ends[1] = me->totedge;
+                               e_flip_tube_end[0] = me->totedge - 1;
                                bridge_loops(me,
                                                         e_flip_start + ((v_steps - 1) * 2 + w_steps) * 2 - 2,
                                                         e_flip_start - branch->fs_bs_offset + (v_steps * 2 + w_steps) * 2 - 2,
@@ -6041,6 +6279,7 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                                                         ((v_steps - 1) * 2 + w_steps) * 2 - 1,
                                                         (v_steps * 2 + w_steps) * 2 - 1,
                                                         n_g_flip);
+                               e_flip_tube_end[1] = me->totedge - 1;
                                e_flip_offset += u_steps * 2 - 2;
                        }
                }
@@ -6208,6 +6447,7 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                branch->e_start_arr[flip_side ? 2 : 0] = e_cap_start_a;
                branch->e_start_arr[flip_side ? 3 : 1] = 1;
        } else {
+               e_cap_tube_start = me->totedge;
                bridge_loops(me,
                                         e_cap_start_a,
                                         e_start_tube[flip_side ? 6 : 2],
@@ -6216,6 +6456,8 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                                         1,
                                         1,
                                         n_g_flip);
+               e_cap_tube_end = me->totedge - 1;
+               e_flip_offset += 2;
                branch->e_start_arr[flip_side ? 2 : 0] = e_start_tube[flip_side ? 4 : 0];
                branch->e_start_arr[flip_side ? 3 : 1] = e_start_tube[flip_side ? 5 : 1];
        }
@@ -6225,6 +6467,30 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
        } else {
                add_quad(me, cap_end_flip_e_start, cap_end_flip_start_a_l, cap_end_flip_start_b_l, !n_g_flip);
                add_quad(me, cap_end_flip_e_start + w_steps - 1, cap_end_flip_start_a_r, cap_end_flip_start_b_r, n_g_flip);
+               if (totlength <= step_size * w_steps || totl == 0 || totr == 0) {
+                       branch->e_flip_side_ends[0] = me->totedge - 2;
+                       branch->e_flip_side_ends[1] = me->totedge - 1;
+               } else {
+                       ED_mesh_loops_add(me, NULL, 8);
+                       ED_mesh_polys_add(me, NULL, 2);
+                       add_face(me,
+                                        e_flip_tube_end[0],
+                                        e_cap_tube_start - branch->fs_bs_offset + e_flip_offset,
+                                        me->totedge - 2,
+                                        e_cap_tube_start,
+                                        me->totloop - 8,
+                                        me->totpoly - 2,
+                                        n_g_flip);
+
+                       add_face(me,
+                                        e_flip_tube_end[1],
+                                        e_cap_tube_end - branch->fs_bs_offset + e_flip_offset + 2,
+                                        me->totedge - 1,
+                                        e_cap_tube_end,
+                                        me->totloop - 4,
+                                        me->totpoly - 1,
+                                        !n_g_flip);
+               }
        }
 
        BLI_array_free(cap_p);
@@ -6265,7 +6531,7 @@ static void add_ss_tinter(SilhouetteData *sil, Spine *spine, SpineBranch *branch
        int v_start, v_start_center;
        int e_start[3], e_start_center, e_start_inner[3], e_t_sign[6];
        int stride_le;
-       int ori;
+       int ori[3];
        int e_flip_offset = 0;  /* carry edgecount difference in both sides to refrence opposing edges by subtracting totedge - flip offset. Only valid if flip_side = true*/
        int e_flip_start[3];
        int e_flip_q_l[3], e_flip_q_r[3];
@@ -6337,6 +6603,7 @@ static void add_ss_tinter(SilhouetteData *sil, Spine *spine, SpineBranch *branch
 
        if (!(branch->flag & BRANCH_EDGE_GEN)) {
                branch->e_start_arr = MEM_callocN(sizeof(int) * 12,"edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 6, "fs bs edges");
                branch->flag |= BRANCH_EDGE_GEN;
        }
 
@@ -6352,9 +6619,9 @@ static void add_ss_tinter(SilhouetteData *sil, Spine *spine, SpineBranch *branch
 
                v_start = me->totvert;
 
-               ori = calc_branch_orientation(spine, branch, &center_s[s * 3], s);
-               branch->e_start_arr[(flip_side ? 6 : 0) + ori * 2] = me->totedge;
-               branch->e_start_arr[(flip_side ? 6 : 0) + ori * 2 + 1] = 1;
+               ori[s] = calc_branch_orientation(spine, branch, &center_s[s * 3], s);
+               branch->e_start_arr[(flip_side ? 6 : 0) + ori[s] * 2] = me->totedge;
+               branch->e_start_arr[(flip_side ? 6 : 0) + ori[s] * 2 + 1] = 1;
 
                calc_vert_half(me,
                                           &sa[b_start[s]],
@@ -6527,11 +6794,13 @@ static void add_ss_tinter(SilhouetteData *sil, Spine *spine, SpineBranch *branch
                e_t_sign[s * 2 + 1] = e_side_a;
 
                if (flip_side) {
+                       branch->e_flip_side_ends[ori[s] * 2] = me->totedge;
                        add_quad(me,
                                         e_flip_q_l[0],
                                         e_flip_q_l[1],
                                         e_flip_q_l[2],
                                         !n_g_flip);
+                       branch->e_flip_side_ends[ori[s] * 2 + 1] = me->totedge;
                        add_quad(me,
                                         e_flip_q_r[0],
                                         e_flip_q_r[1],
@@ -6642,6 +6911,7 @@ static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, floa
 
        if (!(branch->flag & BRANCH_EDGE_GEN)) {
                branch->e_start_arr = MEM_callocN(sizeof(int) * 8, "edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 4, "fs bs edges");
                branch->flag |= BRANCH_EDGE_GEN;
        }
 
@@ -6650,6 +6920,7 @@ static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, floa
        fill_tube(me, left, right, totl, totr, u_steps, z_vec, v_steps, w_steps, w_fact, branch->e_start_arr, n_g_flip, flip_side);
 
        if (flip_side) {
+               branch->e_flip_side_ends[0] = me->totedge;
                bridge_loops(me,
                                         e_start + 1,
                                         e_start - branch->fs_bs_offset + 1,
@@ -6658,7 +6929,8 @@ static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, floa
                                         ((v_steps - 1) * 2 + w_steps) * 2 - 1,
                                         (v_steps * 2 + w_steps) * 2 - 1,
                                         !n_g_flip);
-
+               branch->e_flip_side_ends[1] = me->totedge;
+               branch->e_flip_side_ends[2] = me->totedge - 1;
                bridge_loops(me,
                                         e_start + ((v_steps - 1) * 2 + w_steps) * 2 - 2,
                                         e_start - branch->fs_bs_offset + (v_steps * 2 + w_steps) * 2 - 2,
@@ -6667,6 +6939,7 @@ static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, floa
                                         ((v_steps - 1) * 2 + w_steps) * 2 - 1,
                                         (v_steps * 2 + w_steps) * 2 - 1,
                                         n_g_flip);
+               branch->e_flip_side_ends[3] = me->totedge - 1;
        } else {
                branch->fs_bs_offset = me->totedge - branch->fs_bs_offset;
        }
@@ -6688,20 +6961,16 @@ static int r_branch_count(Spine *spine, SpineBranch *b)
 }
 
 /* TODO: T-Intersections are sometimes misordered! Connects the different Branches if they have the BRANCH_EDGE_GEN flag set. */
-static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_branch, SpineBranch *prev_branch, int verts_per_loop, bool n_g_flip, bool flip_side)
+static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_branch, SpineBranch *prev_branch, int verts_per_loop, bool n_g_flip)
 {
-       int b_fork_off, a_fork_off;
+       int b_fork_off, a_fork_off, a_fork_off_inv, b_fork_off_inv, comp_e_start, comp_e_start_flip;
        float dist_a, dist_b;
-       if (flip_side) {
-               a_fork_off = active_branch->totforks;
-       } else {
-               a_fork_off = 0;
-       }
+       a_fork_off = 0;
        for (int i = 0; i < active_branch->totforks; i++) {
                SpineBranch *comp = spine->branches[active_branch->terminal_points[i * 2 + 1]];
                if (comp && comp != prev_branch) {
                        if (active_branch->flag & BRANCH_EDGE_GEN && comp->flag & BRANCH_EDGE_GEN) {
-                               b_fork_off = (flip_side ? comp->totforks : 0);
+                               b_fork_off = 0;
                                for (int sb = 0; sb < comp->totforks; sb++) {
                                        if (spine->branches[comp->terminal_points[sb * 2 + 1]]) {
                                                if (comp->terminal_points[sb * 2 + 1] == active_branch->idx) {
@@ -6713,7 +6982,7 @@ static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_bra
 
                                /* TODO: Might fail with thin geometry */
                                dist_a = len_v3v3(me->mvert[me->medge[active_branch->e_start_arr[a_fork_off * 2]].v1].co, me->mvert[me->medge[comp->e_start_arr[b_fork_off * 2]].v1].co);
-                               dist_b = len_v3v3(me->mvert[me->medge[active_branch->e_start_arr[a_fork_off * 2]].v1].co, me->mvert[me->medge[comp->e_start_arr[b_fork_off * 2] + (verts_per_loop - 2 - (flip_side ? 2 : 0)) * comp->e_start_arr[b_fork_off * 2 + 1]].v2].co);
+                               dist_b = len_v3v3(me->mvert[me->medge[active_branch->e_start_arr[a_fork_off * 2]].v1].co, me->mvert[me->medge[comp->e_start_arr[b_fork_off * 2] + (verts_per_loop - 2 - 0) * comp->e_start_arr[b_fork_off * 2 + 1]].v2].co);
 
                                /* TODO: Tube bug inverse?
                                if (comp->hull_points[0] == 0) {
@@ -6721,27 +6990,54 @@ static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_bra
                                        bl_debug_draw_medge_add(me, comp->e_start_arr[b_fork_off * 2] + comp->e_start_arr[b_fork_off * 2 + 1] * (verts_per_loop - 2));
                                        bl_debug_color_set(0x000000);
                                }*/
+                               a_fork_off_inv = a_fork_off * 2 + active_branch->totforks * 2;
+                               b_fork_off_inv = b_fork_off * 2 + comp->totforks * 2;
                                if (dist_a > dist_b) {
-                                       bridge_loops(me,
-                                                                active_branch->e_start_arr[a_fork_off * 2],
-                                                                comp->e_start_arr[b_fork_off * 2] + comp->e_start_arr[b_fork_off * 2 + 1] * (verts_per_loop - 2 - (flip_side ? 2 : 0)),
-                                                                verts_per_loop - (flip_side ? 2 : 0),
-                                                                true,
-                                                                active_branch->e_start_arr[a_fork_off * 2 + 1],
-                                                                comp->e_start_arr[b_fork_off * 2 + 1],
-                                                                n_g_flip ^ flip_side);
+                                       comp_e_start = comp->e_start_arr[b_fork_off * 2] + comp->e_start_arr[b_fork_off * 2 + 1] * (verts_per_loop - 2);
+                                       comp_e_start_flip = comp->e_start_arr[b_fork_off_inv] + comp->e_start_arr[b_fork_off_inv + 1] * (verts_per_loop - 4);
                                } else {
-                                       bridge_loops(me,
-                                                                active_branch->e_start_arr[a_fork_off * 2],
-                                                                comp->e_start_arr[b_fork_off * 2],
-                                                                verts_per_loop - (flip_side ? 2 : 0),
-                                                                false,
-                                                                active_branch->e_start_arr[a_fork_off * 2 + 1],
-                                                                comp->e_start_arr[b_fork_off * 2 + 1],
-                                                                !n_g_flip ^ flip_side);
+                                       comp_e_start = comp->e_start_arr[b_fork_off * 2];
+                                       comp_e_start_flip = comp->e_start_arr[b_fork_off_inv];
                                }
+                               bridge_loops(me,
+                                                        active_branch->e_start_arr[a_fork_off * 2],
+                                                        comp_e_start,
+                                                        verts_per_loop,
+                                                        (dist_a > dist_b),
+                                                        active_branch->e_start_arr[a_fork_off * 2 + 1],
+                                                        comp->e_start_arr[b_fork_off * 2 + 1],
+                                                        !n_g_flip ^ (dist_a > dist_b));
+
+                               bridge_loops(me,
+                                                        active_branch->e_start_arr[a_fork_off_inv],
+                                                        comp_e_start_flip,
+                                                        verts_per_loop - 2,
+                                                        (dist_a > dist_b),
+                                                        active_branch->e_start_arr[a_fork_off_inv + 1],
+                                                        comp->e_start_arr[b_fork_off_inv + 1],
+                                                        n_g_flip ^ (dist_a > dist_b));
+
+                               ED_mesh_loops_add(me, NULL, 8);
+                               ED_mesh_polys_add(me, NULL, 2);
+                               add_face(me,
+                                                me->totedge - 1,
+                                                active_branch->e_flip_side_ends[a_fork_off * 2 + 1],
+                                                me->totedge - verts_per_loop + 1,
+                                                comp->e_flip_side_ends[b_fork_off * 2 + ((dist_a > dist_b) ? 0 : 1)],
+                                                me->totloop - 8,
+                                                me->totpoly - 2,
+                                                n_g_flip ^ (dist_a > dist_b));
+
+                               add_face(me,
+                                                me->totedge - verts_per_loop + 2,
+                                                active_branch->e_flip_side_ends[a_fork_off * 2],
+                                                me->totedge - verts_per_loop * 2 + 2,
+                                                comp->e_flip_side_ends[b_fork_off * 2 + ((dist_a > dist_b) ? 1 : 0)],
+                                                me->totloop - 4,
+                                                me->totpoly - 1,
+                                                !n_g_flip ^ (dist_a > dist_b));
                        }
-                       bridge_all_parts_rec(me, spine, comp, active_branch, verts_per_loop, n_g_flip, flip_side);
+                       bridge_all_parts_rec(me, spine, comp, active_branch, verts_per_loop, n_g_flip);
                }
                if (comp) {
                        a_fork_off ++;
@@ -6749,7 +7045,7 @@ static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_bra
        }
 }
 
-static void bridge_all_parts(Mesh *me, Spine *spine, int verts_per_loop, bool n_g_flip, bool flip_side)
+static void bridge_all_parts(Mesh *me, Spine *spine, int verts_per_loop, bool n_g_flip)
 {
        SpineBranch *active_branch = NULL;
        for (int i = 0; i < spine->totbranches; i++) {
@@ -6763,7 +7059,7 @@ static void bridge_all_parts(Mesh *me, Spine *spine, int verts_per_loop, bool n_
                /* No Branches in the spine. Should not happen. */
                return;
        }
-       bridge_all_parts_rec(me, spine, active_branch, NULL, verts_per_loop, n_g_flip, flip_side);
+       bridge_all_parts_rec(me, spine, active_branch, NULL, verts_per_loop, n_g_flip);
 }
 
 static bool calc_stroke_normal_ori(SilhouetteStroke *stroke, float z_vec[3]) {
@@ -6808,29 +7104,28 @@ static void silhouette_create_shape_mesh(bContext *C, Mesh *me, SilhouetteData *
                                        add_ss_cap(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
                                        add_ss_cap(sil, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
 #ifdef DEBUG_DRAW
-                                       debug_branch(a_branch, 0x00ff00);
+                                       /*debug_branch(a_branch, 0x00ff00);*/
 #endif
                                        break;
                                case 2:
                                        add_ss_tube(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
                                        add_ss_tube(sil, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
 #ifdef DEBUG_DRAW
-                                       debug_branch(a_branch, 0xff0000);
+                                       /*debug_branch(a_branch, 0xff0000);*/
 #endif
                                        break;
                                case 3:
                                        add_ss_tinter(sil, spine, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
                                        add_ss_tinter(sil, spine, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
 #ifdef DEBUG_DRAW
-                                       debug_branch(a_branch, 0x0000ff);
+                                       /*debug_branch(a_branch, 0x0000ff);*/
 #endif
                                        break;
                        }
                }
        }
 
-       bridge_all_parts(me, spine, v_steps * 2 + w_steps, n_ori, false);
-       bridge_all_parts(me, spine, v_steps * 2 + w_steps, n_ori, true);
+       bridge_all_parts(me, spine, v_steps * 2 + w_steps, n_ori);
 
        free_spine(spine);
 
@@ -6838,42 +7133,759 @@ static void silhouette_create_shape_mesh(bContext *C, Mesh *me, SilhouetteData *
 }
 
 /* Adds additional points to the stroke if start and end are far apart. */
-static void stroke_smooth_cap(SilhouetteStroke *stroke, float max_dist)
+static void stroke_smooth_cap(SilhouetteData *sil, SilhouetteStroke *stroke, float max_dist)
 {
-       float v1[3], v2[3], dv[3];
+       float v1[2], v2[2], dv[2];
        float length = 0;
-       copy_v3_v3(v1, &stroke->points[0]);
-       copy_v3_v3(v2, &stroke->points[stroke->totvert * 3 - 3]);
+       copy_v2_v2(v1, &stroke->points_v2[0]);
+       copy_v2_v2(v2, &stroke->points_v2[stroke->totvert * 2 - 2]);
 
-       sub_v3_v3v3(dv,v1,v2);
-       length = len_v3(dv);
+       sub_v2_v2v2(dv,v1,v2);
+       length = len_v2(dv);
 
        if (length > max_dist) {
                int steps = floorf(length / (float)max_dist);
-               mul_v3_fl(dv, 1.0f / (float)steps);
+               mul_v2_fl(dv, 1.0f / (float)steps);
                for (int i = 1; i < steps; i++) {
-                       mul_v3_v3fl(v1, dv, i);
-                       add_v3_v3(v1, v2);
-                       silhouette_stroke_add_3Dpoint(stroke, v1);
+                       mul_v2_v2fl(v1, dv, i);
+                       add_v2_v2(v1, v2);
+                       silhouette_stroke_add_point(sil, stroke, v1);
                }
        }
 }
 
+static void remove_connected_from_edgehash(MeshElemMap *emap, GHash *edge_hash, int v) {
+       for (int e = 0; e < emap[v].count; e++) {
+               BLI_ghash_remove(edge_hash, emap[v].indices[e], NULL, NULL);
+       }
+}
+
+static bool has_cross_border_neighbour(Mesh *me, GHash *vert_hash, GHash *edge_hash, MeshElemMap *emap, int edge, int l_v_edge, int depth) {
+       int v_edge;
+
+       v_edge = me->medge[edge].v1 == l_v_edge ? me->medge[edge].v2 : me->medge[edge].v1;
+
+       if (depth == 0) {
+               return BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_edge));
+       } else {
+               if(!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_edge))){
+                       for (int e = 0; e < emap[v_edge].count; e++) {
+                               if(emap[v_edge].indices[e] != edge) {
+                                       if(has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, depth - 1)){
+                                               return true;
+                                       }
+                               }
+                       }
+               } else {
+                       BLI_ghash_remove(edge_hash, edge, NULL, NULL);
+               }
+       }
+       return false;
+}
+
+/* Get the adjacent edge which connects the edges within the edge_hash. Used to create multiple ordered loops
+ * v_edge is the endpoint off curr_edge from which to branch off
+ * TODO: One wide strips might get cutoff */
+static int get_adjacent_edge(Mesh *me, MeshElemMap *emap, int curr_edge, int v_edge, GHash *edge_hash, GHash *vert_hash)
+{
+       for (int e = 0; e < emap[v_edge].count; e++) {
+               if(emap[v_edge].indices[e] != curr_edge && has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, 1)) {
+                       return emap[v_edge].indices[e];
+               }
+       }
+       for (int e = 0; e < emap[v_edge].count; e++) {
+               if(emap[v_edge].indices[e] != curr_edge && has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, 2)) {
+                       return emap[v_edge].indices[e];
+               }
+       }
+       /*End Of Loop. Shouldn't happen with two manifold meshes*/
+       return -1;
+}
+
+/*TODO:Remove Temp debug function*/
+static char *cd_type_name(int t)
+{
+       char *name = "";
+       switch(t) {
+               case -1 : name = "CD_AUTO_FROM_NAME      ";break;
+               case  0 : name = "CD_MVERT               ";break;
+               case  1 : name = "CD_MSTICKY             ";break;  /* DEPRECATED */
+               case  2 : name = "CD_MDEFORMVERT         ";break;
+               case  3 : name = "CD_MEDGE               ";break;
+               case  4 : name = "CD_MFACE               ";break;
+               case  5 : name = "CD_MTFACE              ";break;
+               case  6 : name = "CD_MCOL                ";break;
+               case  7 : name = "CD_ORIGINDEX           ";break;
+               case  8 : name = "CD_NORMAL          ";break;
+                       /*      CD_POLYINDEX        = 9, */
+               case 10 : name = "CD_PROP_FLT        ";break;
+               case 11 : name = "CD_PROP_INT        ";break;
+               case 12 : name = "CD_PROP_STR        ";break;
+               case 13 : name = "CD_ORIGSPACE       ";break;  /* for modifier stack face location mapping */
+               case 14 : name = "CD_ORCO            ";break;
+               case 15 : name = "CD_MTEXPOLY        ";break;
+               case 16 : name = "CD_MLOOPUV         ";break;
+               case 17 : name = "CD_MLOOPCOL        ";break;
+               case 18 : name = "CD_TANGENT         ";break;
+               case 19 : name = "CD_MDISPS          ";break;
+               case 20 : name = "CD_PREVIEW_MCOL    ";break;  /* for displaying weightpaint colors */
+                       /*      CD_ID_MCOL          = 21, */
+               case 22 : name = "CD_TEXTURE_MLOOPCOL";break;
+               case 23 : name = "CD_CLOTH_ORCO      ";break;
+               case 24 : name = "CD_RECAST          ";break;
+
+                       /* BMESH ONLY START */
+               case 25 : name = "CD_MPOLY           ";break;
+               case 26 : name = "CD_MLOOP           ";break;
+               case 27 : name = "CD_SHAPE_KEYINDEX  ";break;
+               case 28 : name = "CD_SHAPEKEY        ";break;
+               case 29 : name = "CD_BWEIGHT         ";break;
+               case 30 : name = "CD_CREASE          ";break;
+               case 31 : name = "CD_ORIGSPACE_MLOOP ";break;
+               case 32 : name = "CD_PREVIEW_MLOOPCOL";break;
+               case 33 : name = "CD_BM_ELEM_PYPTR   ";break;
+                       /* BMESH ONLY END */
+               case 34 : name = "CD_PAINT_MASK      ";break;
+               case 35 : name = "CD_GRID_PAINT_MASK ";break;
+               case 36 : name = "CD_MVERT_SKIN      ";break;
+               case 37 : name = "CD_FREESTYLE_EDGE  ";break;
+               case 38 : name = "CD_FREESTYLE_FACE  ";break;
+               case 39 : name = "CD_MLOOPTANGENT    ";break;
+               case 40 : name = "CD_TESSLOOPNORMAL  ";break;
+               case 41 : name = "CD_CUSTOMLOOPNORMAL";break;
+
+               case 42 : name = "CD_NUMTYPES        ";break;
+               default: name = "No Name";
+       }
+       return name;
+}
+
+#if 0
+static void debug_cd(Mesh *me)
+{
+       char *name = "";
+       printf("Debugging Custom Data:\n\n");
+       printf("%i Customdata Layers in vdata\n", CustomData_number_of_layers_typemask(&me->vdata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in edata\n", CustomData_number_of_layers_typemask(&me->edata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in ldata\n", CustomData_number_of_layers_typemask(&me->ldata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in pdata\n", CustomData_number_of_layers_typemask(&me->pdata, CD_MASK_EVERYTHING));
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->vdata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->vdata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->edata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->edata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->ldata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->ldata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->pdata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->pdata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+}
+#endif
+
+/* Copy customdata from source to destination. Layers need to be matching!
+ * redirect_map needs to be the new positions ofelements in the dest array. -1 marks elements which do not get copied over. */
+static void CustomData_copy_partial(const struct CustomData *source, struct CustomData *dest, CustomDataMask mask, int *redirect_map, int tot_elem)
+{
+       int num_layers_to_copy;
+       int d_size;
+       CustomDataLayer *curr_l, *dest_l;
+       char *name;
+
+       num_layers_to_copy = CustomData_number_of_layers_typemask(source, mask);
+
+       for (int l = 0; l < num_layers_to_copy; l++) {
+               curr_l = &source->layers[l];
+               dest_l = &dest->layers[l];
+               if (CD_TYPE_AS_MASK(curr_l->type) & mask) {
+                       for (int i = 0; i < tot_elem; i++) {
+                               if(redirect_map[i] != -1) {
+                                       d_size = CustomData_sizeof(curr_l->type);
+                                       memcpy(dest_l->data + redirect_map[i] * d_size, curr_l->data + i * d_size, d_size);
+                               }
+                       }
+                       name = cd_type_name(curr_l->type);
+                       printf("Layer %s copied %i values of size %i.\n", name, tot_elem, CustomData_sizeof(curr_l->type));
+               }
+       }
+}
+
+/* Function used to remove vertices from a basic mesh
+ * Can be optimised easily be introucing multithreading
+ * Parts and ideas how multithreading can be introduced are marked with "MT:"
+ * TODO: Add Multithreading */
+static void remove_verts_from_mesh(Mesh *me, int *v_to_rm, int num_v_to_rm){
+       int *v_rd_table, *e_rd_table, *l_rd_table, *p_rd_table;
+       int next_del = 0, next_del_pos = 0;
+       MEdge e;
+       MLoop l;
+       MPoly p;
+
+       int n_totvert, n_totedge, n_totloop, n_totpoly;
+
+       CustomData vdata, edata, ldata, pdata;
+
+       /* MT: Prefix Sum / Scan to calculate new positions for vertices.
+        * Calculating the new positions with the vertices removed
+        */
+       v_rd_table = MEM_callocN(sizeof(int) * me->totvert, "Vertex redirect table");
+
+       qsort(v_to_rm, num_v_to_rm, sizeof(int), cmpfunc);
+
+       n_totvert = 0;
+       next_del = v_to_rm[0];
+       for (int i = 0; i < me->totvert; i++) {
+               if (i == next_del) {
+                       if (next_del_pos + 1 < num_v_to_rm) {
+                               next_del_pos ++;
+                               next_del = v_to_rm[next_del_pos];
+                       }
+                       v_rd_table[i] = -1;
+               } else {
+                       v_rd_table[i] = n_totvert;
+                       n_totvert ++;
+               }
+       }
+
+       /* MT: parallelize loop, !shared access to sum value
+        * Calculate new edge positions + remap vertice pointer
+        */
+       e_rd_table = MEM_callocN(sizeof(int) * me->totedge, "Edge redirect table");
+       n_totedge = 0;
+       for (int i = 0; i < me->totedge; i++) {
+               e = me->medge[i];
+               if(v_rd_table[e.v1] == -1 || v_rd_table[e.v2] == -1) {
+                       e_rd_table[i] = -1;
+               } else {
+                       e.v1 = v_rd_table[e.v1];
+                       e.v2 = v_rd_table[e.v2];
+                       me->medge[i] = e;
+                       e_rd_table[i] = n_totedge;
+                       n_totedge ++;
+               }
+       }
+
+       /* MT: same as above
+        * Calculate new loop positions + remap edge pointers */
+       l_rd_table = MEM_callocN(sizeof(int) * me->totloop, "Loop redirect table");
+       n_totloop = 0;
+       for (int i = 0; i < me->totloop; i++) {
+               l = me->mloop[i];
+               if(v_rd_table[l.v] == -1 || e_rd_table[l.e] == -1) {
+                       l_rd_table[i] = -1;
+               } else {
+                       l.v = v_rd_table[l.v];
+                       l.e = e_rd_table[l.e];
+                       me->mloop[i] = l;
+                       l_rd_table[i] = n_totloop;
+                       n_totloop ++;
+               }
+       }
+
+       /* MT: same as above
+        * Calculate new poly positions + remap pointers */
+       p_rd_table = MEM_callocN(sizeof(int) * me->totpoly, "Poly redirect table");
+       n_totpoly = 0;
+       for (int i = 0; i < me->totpoly; i++) {
+               p = me->mpoly[i];
+               for(int l = p.loopstart; l < p.loopstart + p.totloop; l++){
+                       if(l_rd_table[l] == -1) {
+                               p_rd_table[i] = -1;
+                               /* TODO: Bad practise? easily solved other way*/
+                               goto skip_poly;
+                       }
+               }
+               me->mpoly[i].loopstart = l_rd_table[me->mpoly[i].loopstart];
+               p_rd_table[i] = n_totpoly;
+               n_totpoly ++;
+               skip_poly:;
+       }
+
+       /*Redirection tables are done. Continue to copy and allocate new Customdata blocks*/
+       CustomData_copy(&me->vdata, &vdata, CD_MASK_EVERYTHING, CD_CALLOC, n_totvert);
+       CustomData_copy(&me->edata, &edata, CD_MASK_EVERYTHING, CD_CALLOC, n_totedge);
+       CustomData_copy(&me->ldata, &ldata, CD_MASK_EVERYTHING, CD_CALLOC, n_totloop);
+       CustomData_copy(&me->pdata, &pdata, CD_MASK_EVERYTHING, CD_CALLOC, n_totpoly);
+
+       CustomData_copy_partial(&me->vdata, &vdata, CD_MASK_EVERYTHING, v_rd_table, me->totvert);
+       CustomData_copy_partial(&me->edata, &edata, CD_MASK_EVERYTHING, e_rd_table, me->totedge);
+       CustomData_copy_partial(&me->ldata, &ldata, CD_MASK_EVERYTHING, l_rd_table, me->totloop);
+       CustomData_copy_partial(&me->pdata, &pdata, CD_MASK_EVERYTHING, p_rd_table, me->totpoly);
+
+       CustomData_free(&me->vdata, me->totvert);
+       CustomData_free(&me->edata, me->totedge);
+       CustomData_free(&me->ldata, me->totloop);
+       CustomData_free(&me->pdata, me->totpoly);
+
+       me->vdata = vdata;
+       me->edata = edata;
+       me->ldata = ldata;
+       me->pdata = pdata;
+
+       me->totvert = n_totvert;
+       me->totedge = n_totedge;
+       me->totloop = n_totloop;
+       me->totpoly = n_totpoly;
+
+
+       BKE_mesh_update_customdata_pointers(me, true);
+}
+
+static void calc_ring_bbs(SilhouetteData *sil, Mesh *me)
+{
+       int len, edge;
+       BB *curr;
+       sil->fillet_ring_bbs = MEM_callocN(sizeof(BB) * sil->num_rings, "ring bb mem");
+
+       for (int r = 0; r < sil->num_rings; r++) {
+               len = r + 1 < sil->num_rings ? sil->fillet_ring_new_start[r + 1] - sil->fillet_ring_new_start[r] : sil->fillet_ring_tot - sil->fillet_ring_new_start[r];
+               curr = &sil->fillet_ring_bbs[r];
+               BB_reset(curr);
+               for (int e = 0; e < len; e++) {
+                       edge = sil->fillet_ring_new[sil->fillet_ring_new_start[r] + e];
+                       BB_expand(curr, me->mvert[me->medge[edge].v1].co);
+                       BB_expand(curr, me->mvert[me->medge[edge].v2].co);
+               }
+       }
+}
+
+/* We calculate a start and an endpoint of the two node ends intersecting. Now we need to determine the right side on which the intersection happens 
+ * Returning the points in correct order (positive looping results in inner side);
+ */
+static void order_positive_is_inside(Mesh *me, SilhouetteData *sil, MeshElemMap *emap, int *r11, int *r12, int r1_start, int r1_tot, int r2_start, int r2_tot)
+{
+       int dist_1;
+       int center;
+       int comp_v1, comp_v2;
+       int comp_e;
+       int tmp_swap;
+       if (*r11 > *r12) {
+               dist_1 = r1_tot - *r11 + *r12;
+       } else {
+               dist_1 = *r12 - *r11;
+       }
+
+       center = r1_start + (*r11 + (dist_1 / 2)) % r1_tot;
+       comp_v1 = me->medge[sil->fillet_ring_new[center]].v2;
+
+       for (int e = 0; e < emap[comp_v1].count; e++) {
+               comp_e = emap[comp_v1].indices[e];
+               if (comp_e != sil->fillet_ring_new[center] && comp_e != sil->fillet_ring_new[center + 1] && comp_e != sil->fillet_ring_new[center - 1]) {
+                       comp_v2 = me->medge[comp_e].v1 == comp_v1 ? me->medge[comp_e].v2 : me->medge[comp_e].v1;
+                       for (int e_l = 0; e_l < r2_tot; e_l ++) {
+                               if (me->medge[sil->fillet_ring_new[r2_start + e_l]].v2 == comp_v2) {
+                                       return;
+                               }
+                       }
+               }
+       }
+       tmp_swap = *r11;
+       *r11 = *r12;
+       *r12 = tmp_swap;
+       return;
+}
+
+typedef enum MergeRingFlag {
+       ADDED_TO_MERGE = 1,
+} MergeRingFlag;
+
+
+typedef struct MergeRingInfo {
+       int r1;
+       int r2;
+       int r1_start;
+       int r2_start;
+       int r1_tot;
+       int r2_tot;
+       int r1_e_a;
+       int r1_e_b;
+       int r2_e_a;
+       int r2_e_b;
+       int flag;
+} MergeRingInfo;
+
+static void join_node_separated_rings(SilhouetteData *sil, Mesh *me, MeshElemMap *emap)
+{
+       MergeRingInfo *merge_info = NULL;
+       int *merged_to_one = NULL;
+       MEdge e1_c, e2_c;
+       MergeRingInfo t_m_info;
+
+       BLI_array_declare(merge_info);
+
+       printf("Joining rings. In total %i rings to check.\n", sil->num_rings);
+       for (int r1 = 0; r1 < sil->num_rings - 1; r1++) {
+               for (int r2 = r1 + 1; r2 < sil->num_rings; r2++) {
+                       if (bb_intersect(&sil->fillet_ring_bbs[r1], &sil->fillet_ring_bbs[r2])) {
+                               t_m_info.r1_start = sil->fillet_ring_new_start[r1];
+                               t_m_info.r2_start = sil->fillet_ring_new_start[r2];
+                               t_m_info.r1_tot = sil->fillet_ring_new_start[r1 + 1] - t_m_info.r1_start;
+                               t_m_info.r2_tot = r2 + 1 < sil->num_rings ? sil->fillet_ring_new_start[r2 + 1] - t_m_info.r2_start : sil->fillet_ring_tot - t_m_info.r2_start;
+                               t_m_info.r1_e_a = -1, t_m_info.r1_e_b = -1, t_m_info.r2_e_a = -1, t_m_info.r2_e_b = -1;
+                               for (int e1 = 0; e1 < t_m_info.r1_tot; e1++) {
+                                       e1_c = me->medge[sil->fillet_ring_new[t_m_info.r1_start + e1]];
+                                       for (int e2 = 0; e2 < t_m_info.r2_tot; e2++) {
+                                               e2_c = me->medge[sil->fillet_ring_new[t_m_info.r2_start + e2]];
+                                               if (e1_c.v1 == e2_c.v1 || e1_c.v1 == e2_c.v2 || e1_c.v2 == e2_c.v1 || e1_c.v2 == e2_c.v2) {
+                                                       if (t_m_info.r1_e_a == -1) {
+                                                               t_m_info.r1_e_a = e1;
+                                                               t_m_info.r2_e_a = e2;
+                                                       } else {
+                                                               if (abs(t_m_info.r1_e_a - e1) > 3) {
+                                                                       t_m_info.r1_e_b = e1;
+                                                                       t_m_info.r2_e_b = e2;
+                                                                       /* Found start and endpoint of the two ring intersections */
+                                                                       order_positive_is_inside(me, sil, emap, &t_m_info.r1_e_a, &t_m_info.r1_e_b, t_m_info.r1_start, t_m_info.r1_tot, t_m_info.r2_start, t_m_info.r2_tot);
+                                                                       order_positive_is_inside(me, sil, emap, &t_m_info.r2_e_a, &t_m_info.r2_e_b, t_m_info.r2_start, t_m_info.r2_tot, t_m_info.r1_start, t_m_info.r1_tot);
+
+                                                                       BLI_array_append(merge_info, t_m_info);
+#ifdef DEBUG_DRAW
+                                                                       bl_debug_color_set(0xffffff);
+                                                                       bl_debug_draw_point(me->mvert[me->medge[sil->fillet_ring_new[t_m_info.r1_start + t_m_info.r1_e_a]].v1].co, 0.2f);
+                                                                       bl_debug_color_set(0x000000);
+                                                                       bl_debug_draw_point(me->mvert[me->medge[sil->fillet_ring_new[t_m_info.r1_start + t_m_info.r1_e_b]].v1].co, 0.3f);
+                                                                       bl_debug_color_set(0x000000);
+
+                                                                       bl_debug_color_set(0x00ff00);
+                                                                       for (int e_ins = 0; e_ins < t_m_info.r1_tot; e_ins ++) {
+                                                                               if((t_m_info.r1_e_a + e_ins) % t_m_info.r1_tot == t_m_info.r1_e_b) {
+                                                                                       bl_debug_color_set(0x000000);
+                                                                                       break;
+                                                                               }
+                                                                               bl_debug_draw_medge_add(me, sil->fillet_ring_new[t_m_info.r1_start + (t_m_info.r1_e_a + e_ins) % t_m_info.r1_tot]);
+                                                                       }
+                                                                       bl_debug_color_set(0x000000);
+#endif 
+                                                                       /* TODO: Is this a bad coding practise?
+                                                                        * Maybe:
+                                                                        * e1 = r1_tot;
+                                                                        * e2 = r2_tot;
+                                                                        * r2++;
+                                                                        */
+                                                                       goto next_ring;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       /* Continue with the next ring */
+                       next_ring:;
+               }
+       }
+
+       BLI_array_declare(merged_to_one);
+       for (int i = 0; i < BLI_array_count(merge_info); i++) {
+               if (!merge_info[i].flag & ADDED_TO_MERGE) {
+                       BLI_array_append(merged_to_one, merge_info[0].r1);
+                       merge_info[0].flag |= ADDED_TO_MERGE;
+                       for (int j = i; j < BLI_array_count(merge_info); j++) {
+                               for (int k = 0; k < BLI_array_count(merged_to_one); k++) {
+
+                               }
+                       }
+               }
+       }
+       BLI_array_free(merged_to_one);
+       BLI_array_free(merge_info);
+}
+
+static void prep_int_shared_mem(int **mem, int *r_num, int *r_start, int len, const char *str)
+{
+       if (!mem) {
+               *r_start = 0;
+               *mem = MEM_callocN(sizeof(int) * len, str);
+               *r_num = len;
+       } else {
+               *r_start = *r_num;
+               *r_num = *r_num + len;
+               *mem = MEM_reallocN(*mem, sizeof(int) * (*r_num));
+       }
+}
+
+/* Calculate the intersections with existing geometry. Used to connect the new Silhouette to the old mesh
+ * Fillets are the smooth transition from one part to another.
+ */
+static void do_calc_fillet_line_task_cb_ex(void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+       SculptThreadedTaskData *data = userdata;
+       SculptSession *ss = data->ob->sculpt;
+       SilhouetteData *sil = data->sil;
+       Mesh *me = data->ob->data;
+       PBVHNode *curr_node = data->nodes[n];
+
+       PBVHVertexIter vd;
+       float point[2];
+       float sil_plane[4];
+       float fuzz;
+       MEdge e_comp;
+       int v_i, vd_i;
+       GHash *vert_hash = BLI_ghash_int_new("vertices within intersection");
+       GHash *edge_hash = BLI_ghash_int_new("edges on the intersection");
+       int *edge_ring_fillet = NULL;
+       int *ring_start = NULL;
+       int v_rm_start_in_shared_arr = 0, int_e_start_in_shared_arr = 0, fillet_edge_ring_start_shared_arr = 0, fillet_ring_start_start_shared_arr = 0;
+       int r_size;
+       BLI_array_declare(edge_ring_fillet);
+       BLI_array_declare(ring_start);
+       int comp_v, idx;
+
+       /*GHashIterState state;*/
+       GHashIterator gh_iter;
+       int curr_edge = -1, last_edge = -1, start_edge = -1, tmp_curr_edge = -1;
+
+       plane_from_point_normal_v3(sil_plane, sil->anchor, sil->z_vec);
+
+       /* TODO: Is this a unique vert iteration? If not edges might be added twice by different threads */
+       BKE_pbvh_vertex_iter_begin(ss->pbvh, curr_node, vd, PBVH_ITER_UNIQUE)
+       {
+               /* get the interior vertices of the 2d drawn silhouette and all relevant vertices 
+                * Ignores smoothness, assuming the smoothness blures the fillets anyways it should be ok. */
+               fuzz = SIL_FILLET_BLUR_MIN + sil->smoothness * 0.01f * SIL_FILLET_BLUR_MAX;
+               if (dist_squared_to_plane_v3(vd.co, sil_plane) <= sil->depth + fuzz) {
+                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]))) {
+                               ED_view3d_project_float_v2_m4(sil->ar, vd.co, point, data->mat);
+                               if (isect_point_poly_v2(point, (float(*)[2])sil->current_stroke->points_v2, sil->current_stroke->totvert, false)){
+                                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]))) {
+                                               BLI_ghash_insert(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]), SET_INT_IN_POINTER(vd.vert_indices[vd.i]));
+                                               vd_i = vd.vert_indices[vd.i];
+                                               for (int e = 0; e < sil->emap[vd_i].count; e++){
+                                                       e_comp = me->medge[sil->emap[vd_i].indices[e]];
+                                                       v_i = e_comp.v1 == vd_i ? e_comp.v2 : e_comp.v1;
+                                                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_i)))
+                                                       {
+                                                               ED_view3d_project_float_v2_m4(sil->ar, me->mvert[v_i].co, point, data->mat);
+                                                               if (!isect_point_poly_v2(point, (float(*)[2])sil->current_stroke->points_v2, sil->current_stroke->totvert, false) || dist_squared_to_plane_v3(me->mvert[v_i].co, sil_plane) > sil->depth + fuzz) {
+                                                                       BLI_ghash_insert(edge_hash, SET_INT_IN_POINTER(sil->emap[vd_i].indices[e]), SET_INT_IN_POINTER(sil->emap[vd_i].indices[e]));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       BKE_pbvh_vertex_iter_end;
+
+       /* Finished writing all vertices which are within the intersection and need to be removed.
+        * write them to the shared array. Lock the mutex to avoid collisions */
+       BLI_mutex_lock(&data->mutex);
+       prep_int_shared_mem(&data->v_to_rm, &data->num_v_to_rm, &v_rm_start_in_shared_arr, BLI_ghash_size(vert_hash), "verts to remove");
+       prep_int_shared_mem(&sil->inter_edges, &sil->num_inter_edges, &int_e_start_in_shared_arr, BLI_ghash_size(edge_hash), "edges on transition");
+
+       /* Copy vertice data over.*/
+       GHASH_ITER_INDEX (gh_iter, vert_hash, idx) {
+               data->v_to_rm[v_rm_start_in_shared_arr + idx] = BLI_ghashIterator_getKey(&gh_iter);
+       }
+
+       /* Copy edge data over. */
+       GHASH_ITER_INDEX (gh_iter, edge_hash, idx) {
+               sil->inter_edges[int_e_start_in_shared_arr + idx] = BLI_ghashIterator_getKey(&gh_iter);
+       }
+       BLI_mutex_unlock(&data->mutex);
+
+       /* TODO: Workaround, do a BLI_ghash_pop style while loop
+        * TODO: A adjacency search might fail if there is not a single path to be searched, shouldn't be a problem on first thought though.
+        * Breaker is a anti crash method in case the algorithm gets caught in an endless loop. Shouldn't happen!*/
+       int breaker;
+       int debug_test_v;
+       do {
+               breaker = me->totedge;
+               BLI_ghashIterator_init(&gh_iter, edge_hash);
+               if(!BLI_ghashIterator_done(&gh_iter)){
+                       start_edge = BLI_ghashIterator_getValue(&gh_iter);
+                       BLI_ghash_remove(edge_hash, start_edge, NULL, NULL);
+                       comp_v = BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(me->medge[start_edge].v1)) ? me->medge[start_edge].v2 : me->medge[start_edge].v1;
+                       debug_test_v = comp_v;
+                       BLI_assert(!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(comp_v)));
+                       start_edge = get_adjacent_edge(me, sil->emap, start_edge, comp_v, edge_hash, vert_hash);
+                       if(start_edge >= 0) {
+                               BLI_array_append(ring_start, BLI_array_count(edge_ring_fillet));
+                               curr_edge = start_edge;
+                               last_edge = -1;
+
+                               while(!(curr_edge == start_edge && last_edge != -1) && curr_edge != -1 && breaker > 0) {
+                                       BLI_array_append(edge_ring_fillet, curr_edge);
+                                       if(last_edge == -1) {
+                                               comp_v = me->medge[start_edge].v1;
+                                       } else {
+                                               if (me->medge[curr_edge].v1 == me->medge[last_edge].v1 || me->medge[curr_edge].v1 == me->medge[last_edge].v2) {
+                                                       comp_v = me->medge[curr_edge].v2;
+                                               } else {
+                                                       comp_v = me->medge[curr_edge].v1;
+                                               }
+                                       }
+                                       remove_connected_from_edgehash(sil->emap, edge_hash, comp_v);
+                                       tmp_curr_edge = get_adjacent_edge(me, sil->emap, curr_edge, comp_v, edge_hash, vert_hash);
+                                       last_edge = curr_edge;
+                                       curr_edge = tmp_curr_edge;
+                                       breaker --;
+                               }
+                               printf("Found a cut loop!\n");
+                               BLI_assert(breaker > 0);
+                               /* TODO: Bug shouldn't reach but does on some occasion.*/
+                               if (breaker == 0) {
+                                       BLI_array_empty(edge_ring_fillet);
+#ifdef DEBUG_DRAW
+
+                                       bl_debug_color_set(0x00ff00);
+                                       bl_debug_draw_point(me->mvert[debug_test_v].co, 0.2f);
+                                       bl_debug_draw_medge_add(me, start_edge);
+                                       bl_debug_color_set(0x000000);
+#endif
+                               }
+                       }
+               }
+       } while (!BLI_ghashIterator_done(&gh_iter));
+
+       /* Prep ring memory*/
+       BLI_mutex_lock(&data->mutex);
+       prep_int_shared_mem(&sil->fillet_ring_new, &sil->fillet_ring_tot, &fillet_edge_ring_start_shared_arr, BLI_array_count(edge_ring_fillet), "edges on transition");
+       prep_int_shared_mem(&sil->fillet_ring_new_start, &sil->num_rings, &fillet_ring_start_start_shared_arr, BLI_array_count(ring_start), "start of individual rings");
+
+       /* Copy ring memory */
+       for (int i = 0; i < BLI_array_count(edge_ring_fillet); i++) {
+               sil->fillet_ring_new[fillet_edge_ring_start_shared_arr + i] = edge_ring_fillet[i];
+       }
+       /* Offset start pointers to account chunks beforehand */
+       for (int i = 0; i < BLI_array_count(ring_start); i++) {
+               sil->fillet_ring_new_start[fillet_ring_start_start_shared_arr + i] = ring_start[i] + fillet_edge_ring_start_shared_arr;
+       }
+       BLI_mutex_unlock(&data->mutex);
+
+       /*TODO: merge rings from multiple threads / nodes*/
+#ifdef DEBUG_DRAW
+       for(int r = 0; r < BLI_array_count(ring_start); r++) {
+               r_size = r < BLI_array_count(ring_start) - 1 ? ring_start[r + 1] - ring_start[r] : BLI_array_count(edge_ring_fillet) - ring_start[r];
+               for(int i = 0; i < r_size; i++) {
+                       if(i == 0){
+                               bl_debug_color_set(0x00ffff);
+                       } else {
+                               bl_debug_color_set(0xff00ff);
+                       }
+                       bl_debug_draw_medge_add(me, edge_ring_fillet[ring_start[r] + i]);
+                       bl_debug_color_set(0x000000);
+               }
+       }
+#endif
+       BLI_array_free(ring_start);
+       BLI_array_free(edge_ring_fillet);
+       BLI_ghash_free(vert_hash, NULL, NULL);
+       BLI_ghash_free(edge_hash, NULL, NULL);
+}
+
+static void do_calc_fillet_line(Object *ob, SilhouetteData *silhouette, PBVHNode **nodes, int totnode)
+{
+       Mesh *me = ob->data;
+       float projmat[4][4];
+       MeshElemMap *emap;
+       int *emap_mem;
+       int *v_remove = NULL;
+       RegionView3D *rv3d;
+       View3D *v3d;
+       /*rctf viewplane;
+       float clipend;
+       float clipnear;*/
+
+       rv3d = silhouette->ar->regiondata;
+       v3d = silhouette->vc.v3d;
+
+       BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
+       silhouette->emap = emap;
+       /* calc the projection matrix used to convert 3d vertice in 2d space */
+       mul_m4_m4m4(projmat, (float (*)[4])rv3d->persmat, ob->obmat);
+       /* TODO: Orthographic projection:
+       ED_view3d_ob_project_mat_get(silhouette->ar->regiondata, ob, projmat);
+
+       float vmat[4][4], winmat[4][4];;
+
+
+       mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
+       mul_m4_m4m4(projmat, (float (*)[4])rv3d->persmat, ob->obmat);
+
+       ED_view3d_viewplane_get(v3d, rv3d, silhouette->ar->winx, silhouette->ar->winy, &viewplane, &clipnear, &clipend, NULL);
+       orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
+
+       mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
+       mul_m4_m4m4(projmat, winmat, vmat);*/
+
+       /* threaded loop over nodes */
+       SculptThreadedTaskData data = {
+               .ob = ob, .nodes = nodes,
+               .sil = silhouette, .mat = projmat, .v_to_rm = v_remove
+       };
+
+       BLI_task_parallel_range_ex(
+                                                          0, totnode, &data, NULL, 0, do_calc_fillet_line_task_cb_ex,
+                                                          (totnode > SCULPT_THREADED_LIMIT), false);
+
+       v_remove = data.v_to_rm;
+
+       calc_ring_bbs(silhouette, me);
+
+#ifdef DEBUG_DRAW
+       for (int r = 0; r < silhouette->num_rings; r ++) {
+               bl_debug_draw_BB_add(&silhouette->fillet_ring_bbs[r], 0x0000ff);
+       }
+#endif
+
+       /*TODO: Join multiple parts together when totnode > 1.*/
+       join_node_separated_rings(silhouette, me, emap);
+
+       if (v_remove) {
+               printf("Removing vertices/edges/loops/polys from mesh.\n");
+               remove_verts_from_mesh(me, v_remove, data.num_v_to_rm);
+               MEM_freeN(v_remove);
+       }
+
+       MEM_freeN(emap);
+       MEM_freeN(emap_mem);
+}
+
 static void sculpt_silhouette_calc_mesh(bContext *C, wmOperator *op)
 {
        /*finalize stroke*/
        Object *ob = CTX_data_active_object(C);
        SilhouetteData *sil = op->customdata;
        Mesh *me = ob->data;
+       /*Sculpt *sd = CTX_data_tool_settings(C)->sculpt;*/
+       SculptSession *ss = ob->sculpt;
+       SculptSearchBBData data;
+       PBVHNode **nodes = NULL;
 
        SilhouetteStroke *stroke = sil->current_stroke;
 
-       stroke_smooth_cap(stroke, 0.3f);
+       stroke_smooth_cap(sil, stroke, 10.0f);
+
+       int totnode;
+
+       data.ss = ss;
+       data.bb_target = &stroke->bb;
+       /* get the pbvh nodes intersecting the silhouette BB */
+       BKE_pbvh_search_gather(ss->pbvh, sculpt_search_BB_cb, &data, &nodes, &totnode);
+
+       /* Only act if some verts are inside the silhouette drawn */
+       if (totnode) {
+               printf("Connect to geometry\n");
+               do_calc_fillet_line(ob, sil, nodes, totnode);
+       }
 
        silhouette_create_shape_mesh(C, me, sil, stroke);
 
        /* Rebuild mesh caches
         * TODO: Proper PBVH etc. */
+
+       BKE_mesh_calc_edges(me, false, true);
+       BKE_mesh_tessface_clear(me);
+       BKE_mesh_calc_normals(me);
+       DAG_id_tag_update(&me->id, 0);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
        BKE_object_free_derived_caches(ob);
 }
 
@@ -6917,8 +7929,9 @@ static int sculpt_silhouette_exec(bContext *C, wmOperator *op)
                op->customdata = sil;
        }
 
+       /*TODO: Add undo for fillets etc*/
        if (sil->current_stroke->totvert > 3) {
-               sculpt_undo_push_begin("draw Silhouette");
+               /*sculpt_undo_push_begin("draw Silhouette");*/
                v_start = me->totvert;
                e_start = me->totedge;
                l_start = me->totloop;
@@ -6926,8 +7939,8 @@ static int sculpt_silhouette_exec(bContext *C, wmOperator *op)
                sculpt_silhouette_calc_mesh(C, op);
                sculpt_silhouette_stroke_done(C, op);
 
-               sculpt_undo_silhouette_push(ob, v_start, e_start, l_start, p_start);
-               sculpt_undo_push_end(C);
+               /*sculpt_undo_silhouette_push(ob, v_start, e_start, l_start, p_start);
+               sculpt_undo_push_end(C);*/
        }
 
        return OPERATOR_FINISHED;