uv edge based stitch. Useful to disambiguate betwen islands
authorAntony Riakiotakis <kalast@gmail.com>
Mon, 17 Dec 2012 20:14:07 +0000 (20:14 +0000)
committerAntony Riakiotakis <kalast@gmail.com>
Mon, 17 Dec 2012 20:14:07 +0000 (20:14 +0000)
 when uvs are shared by more than two islands. Uv edges
 usually belong to only two islands, making for much cleaner
 stitches. To change between stitch modes, press TAB.
 Initial mode depends on the selection mode of the image
 editor. Documentation can also be found on the release wiki

source/blender/blenkernel/BKE_mesh.h
source/blender/editors/mesh/editmesh_utils.c
source/blender/editors/uvedit/uvedit_smart_stitch.c

index e53d0efffbdc302350ef9da44ff6b0786ae2d5fc..3fc1b7d613607c8f06a8c42f217a6c04ed28ab66 100644 (file)
@@ -229,8 +229,6 @@ typedef struct UvElement {
        /* Next UvElement corresponding to same vertex */
        struct UvElement *next;
        /* Face the element belongs to */
-       struct BMFace *face;
-       /* Index in the editFace of the uv */
        struct BMLoop *l;
        /* index in loop. */
        unsigned short tfindex;
index cbb7262beb2829d30672f11efdf20c7db5d4dc9d..b1094c75f2725969dd4810486bb07d6ea3070765 100644 (file)
@@ -876,7 +876,6 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
                if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
                        BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
                                buf->l = l;
-                               buf->face = efa;
                                buf->separate = 0;
                                buf->island = INVALID_ISLAND;
                                buf->tfindex = i;
@@ -948,7 +947,7 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
                for (i = 0; i < totuv; i++) {
                        if (element_map->buf[i].island == INVALID_ISLAND) {
                                element_map->buf[i].island = nislands;
-                               stack[0] = element_map->buf[i].face;
+                               stack[0] = element_map->buf[i].l->f;
                                island_number[BM_elem_index_get(stack[0])] = nislands;
                                stacksize = 1;
 
@@ -962,12 +961,11 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
                                                        if (element->separate)
                                                                initelement = element;
 
-                                                       if (element->face == efa) {
+                                                       if (element->l->f == efa) {
                                                                /* found the uv corresponding to our face and vertex. Now fill it to the buffer */
                                                                element->island = nislands;
                                                                map[element - element_map->buf] = islandbufsize;
                                                                islandbuf[islandbufsize].l = element->l;
-                                                               islandbuf[islandbufsize].face = element->face;
                                                                islandbuf[islandbufsize].separate = element->separate;
                                                                islandbuf[islandbufsize].tfindex = element->tfindex;
                                                                islandbuf[islandbufsize].island =  nislands;
@@ -977,9 +975,9 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
                                                                        if (element->separate && element != initelement)
                                                                                break;
 
-                                                                       if (island_number[BM_elem_index_get(element->face)] == INVALID_ISLAND) {
-                                                                               stack[stacksize++] = element->face;
-                                                                               island_number[BM_elem_index_get(element->face)] = nislands;
+                                                                       if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
+                                                                               stack[stacksize++] = element->l->f;
+                                                                               island_number[BM_elem_index_get(element->l->f)] = nislands;
                                                                        }
                                                                }
                                                                break;
@@ -1060,7 +1058,7 @@ UvElement *ED_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
        element = map->vert[BM_elem_index_get(l->v)];
 
        for (; element; element = element->next)
-               if (element->face == efa)
+               if (element->l->f == efa)
                        return element;
 
        return NULL;
index 9c99eb196c2b08f39de0baf5df5f5f1da9e53608..280b6f0703d1bb04166b4e28c48b922384970206 100644 (file)
 
 /* ********************** smart stitch operator *********************** */
 
-/* object that stores display data for previewing before accepting stitching */
+/* object that stores display data for previewing before confirming stitching */
 typedef struct StitchPreviewer {
-       /* here we'll store the preview triangle indices of the mesh */
-       float *preview_polys;
-       /* uvs per polygon. */
-       unsigned int *uvs_per_polygon;
-       /*number of preview polygons */
-       unsigned int num_polys;
-       /* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
-       float *preview_stitchable;
-       float *preview_unstitchable;
-       /* here we'll store the number of elements to be drawn */
-       unsigned int num_stitchable;
-       unsigned int num_unstitchable;
-       unsigned int preview_uvs;
-       /* ...and here we'll store the triangles*/
-       float *static_tris;
-       unsigned int num_static_tris;
+               /* here we'll store the preview triangle indices of the mesh */
+               float *preview_polys;
+               /* uvs per polygon. */
+               unsigned int *uvs_per_polygon;
+               /*number of preview polygons */
+               unsigned int num_polys;
+               /* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
+               float *preview_stitchable;
+               float *preview_unstitchable;
+               /* here we'll store the number of elements to be drawn */
+               unsigned int num_stitchable;
+               unsigned int num_unstitchable;
+               unsigned int preview_uvs;
+               /* ...and here we'll store the static island triangles*/
+               float *static_tris;
+               unsigned int num_static_tris;
 } StitchPreviewer;
 
 
@@ -98,85 +98,96 @@ struct IslandStitchData;
 /* This is a straightforward implementation, count the uv's in the island that will move and take the mean displacement/rotation and apply it to all
  * elements of the island except from the stitchable */
 typedef struct IslandStitchData {
-       /* rotation can be used only for edges, for vertices there is no such notion */
-       float rotation;
-       float translation[2];
-       /* Used for rotation, the island will rotate around this point */
-       float medianPoint[2];
-       int numOfElements;
-       int num_rot_elements;
-       /* flag to remember if island has been added for preview */
-       char addedForPreview;
-       /* flag an island to be considered for determining static island */
-       char stitchableCandidate;
-       /* if edge rotation is used, flag so that vertex rotation is not used */
-       char use_edge_rotation;
+               /* rotation can be used only for edges, for vertices there is no such notion */
+               float rotation;
+               float translation[2];
+               /* Used for rotation, the island will rotate around this point */
+               float medianPoint[2];
+               int numOfElements;
+               int num_rot_elements;
+               /* flag to remember if island has been added for preview */
+               char addedForPreview;
+               /* flag an island to be considered for determining static island */
+               char stitchableCandidate;
+               /* if edge rotation is used, flag so that vertex rotation is not used */
+               char use_edge_rotation;
 } IslandStitchData;
 
 /* just for averaging UVs */
 typedef struct UVVertAverage {
-       float uv[2];
-       unsigned short count;
+               float uv[2];
+               unsigned short count;
 } UVVertAverage;
 
 typedef struct UvEdge {
-       /* index to uv buffer */
-       unsigned int uv1;
-       unsigned int uv2;
-       /* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
-       char flag;
-       /* element that guarantees element->face has the face on element->tfindex and element->tfindex+1 is the second uv */
-       UvElement *element;
+               /* index to uv buffer */
+               unsigned int uv1;
+               unsigned int uv2;
+               /* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
+               unsigned char flag;
+               /* element that guarantees element->face has the edge on element->tfindex and element->tfindex+1 is the second uv */
+               UvElement *element;
+               /* next uv edge with the same exact vertices as this one.. Calculated at startup to save time */
+               struct UvEdge *next;
+               /* point to first of common edges. Needed for iteration */
+               struct UvEdge *first;
 } UvEdge;
 
 
 /* stitch state object */
 typedef struct StitchState {
-       /* use limit flag */
-       char use_limit;
-       /* limit to operator, same as original operator */
-       float limit_dist;
-       /* snap uv islands together during stitching */
-       char snap_islands;
-       /* stich at midpoints or at islands */
-       char midpoints;
-       /* editmesh, cached for use in modal handler */
-       BMEditMesh *em;
-       /* clear seams of stitched edges after stitch */
-       char clear_seams;
-       /* element map for getting info about uv connectivity */
-       UvElementMap *element_map;
-       /* edge container */
-       UvEdge *uvedges;
-       /* container of first of a group of coincident uvs, these will be operated upon */
-       UvElement **uvs;
-       /* maps uvelements to their first coincident uv */
-       int *map;
-       /* 2D normals per uv to calculate rotation for snapping */
-       float *normals;
-       /* edge storage */
-       UvEdge *edges;
-
-       /* count of separate uvs and edges */
-       int total_boundary_edges;
-       int total_separate_uvs;
-       /* hold selection related information */
-       UvElement **selection_stack;
-       int selection_size;
-       /* island that stays in place */
-       int static_island;
-       /* store number of primitives per face so that we can allocate the active island buffer later */
-       unsigned int *tris_per_island;
-
-       void *draw_handle;
+               /* use limit flag */
+               char use_limit;
+               /* limit to operator, same as original operator */
+               float limit_dist;
+               /* snap uv islands together during stitching */
+               char snap_islands;
+               /* stich at midpoints or at islands */
+               char midpoints;
+               /* editmesh, cached for use in modal handler */
+               BMEditMesh *em;
+               /* clear seams of stitched edges after stitch */
+               char clear_seams;
+               /* element map for getting info about uv connectivity */
+               UvElementMap *element_map;
+               /* edge container */
+               UvEdge *uvedges;
+               /* container of first of a group of coincident uvs, these will be operated upon */
+               UvElement **uvs;
+               /* maps uvelements to their first coincident uv */
+               int *map;
+               /* 2D normals per uv to calculate rotation for snapping */
+               float *normals;
+               /* edge storage */
+               UvEdge *edges;
+               /* hash for quick lookup of edges */
+               GHash *edge_hash;
+
+               /* count of separate uvs and edges */
+               int total_separate_edges;
+               int total_separate_uvs;
+               /* hold selection related information */
+               void **selection_stack;
+               int selection_size;
+               /* island that stays in place */
+               int static_island;
+               /* store number of primitives per face so that we can allocate the active island buffer later */
+               unsigned int *tris_per_island;
+
+               /* vert or edge mode used for stitching */
+               char mode;
+               /* handle for drawing */
+               void *draw_handle;
+               /* preview data */
+               StitchPreviewer *stitch_preview;
 } StitchState;
 
 typedef struct PreviewPosition {
-       int data_position;
-       int polycount_position;
+               int data_position;
+               int polycount_position;
 } PreviewPosition;
 /*
- * defines for UvElement flags
+ * defines for UvElement/UcEdge flags
  */
 #define STITCH_SELECTED 1
 #define STITCH_STITCHABLE 2
@@ -186,83 +197,79 @@ typedef struct PreviewPosition {
 
 #define STITCH_NO_PREVIEW -1
 
-/* previewer stuff (see uvedit_intern.h for more info) */
-static StitchPreviewer *_stitch_preview;
+enum StitchModes {
+       STITCH_VERT,
+       STITCH_EDGE
+};
 
 /* constructor */
 static StitchPreviewer *stitch_preview_init(void)
 {
-       _stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
-       _stitch_preview->preview_polys = NULL;
-       _stitch_preview->preview_stitchable = NULL;
-       _stitch_preview->preview_unstitchable = NULL;
-       _stitch_preview->uvs_per_polygon = NULL;
+       StitchPreviewer *stitch_preview;
+
+       stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
+       stitch_preview->preview_polys = NULL;
+       stitch_preview->preview_stitchable = NULL;
+       stitch_preview->preview_unstitchable = NULL;
+       stitch_preview->uvs_per_polygon = NULL;
 
-       _stitch_preview->preview_uvs = 0;
-       _stitch_preview->num_polys = 0;
-       _stitch_preview->num_stitchable = 0;
-       _stitch_preview->num_unstitchable = 0;
+       stitch_preview->preview_uvs = 0;
+       stitch_preview->num_polys = 0;
+       stitch_preview->num_stitchable = 0;
+       stitch_preview->num_unstitchable = 0;
 
-       _stitch_preview->static_tris = NULL;
+       stitch_preview->static_tris = NULL;
 
-       _stitch_preview->num_static_tris = 0;
+       stitch_preview->num_static_tris = 0;
 
-       return _stitch_preview;
+       return stitch_preview;
 }
 
 /* destructor...yeah this should be C++ :) */
-static void stitch_preview_delete(void)
+static void stitch_preview_delete(StitchPreviewer *stitch_preview)
 {
-       if (_stitch_preview) {
-               if (_stitch_preview->preview_polys) {
-                       MEM_freeN(_stitch_preview->preview_polys);
-                       _stitch_preview->preview_polys = NULL;
+       if (stitch_preview) {
+               if (stitch_preview->preview_polys) {
+                       MEM_freeN(stitch_preview->preview_polys);
+                       stitch_preview->preview_polys = NULL;
                }
-               if (_stitch_preview->uvs_per_polygon) {
-                       MEM_freeN(_stitch_preview->uvs_per_polygon);
-                       _stitch_preview->uvs_per_polygon = NULL;
+               if (stitch_preview->uvs_per_polygon) {
+                       MEM_freeN(stitch_preview->uvs_per_polygon);
+                       stitch_preview->uvs_per_polygon = NULL;
                }
-               if (_stitch_preview->preview_stitchable) {
-                       MEM_freeN(_stitch_preview->preview_stitchable);
-                       _stitch_preview->preview_stitchable = NULL;
+               if (stitch_preview->preview_stitchable) {
+                       MEM_freeN(stitch_preview->preview_stitchable);
+                       stitch_preview->preview_stitchable = NULL;
                }
-               if (_stitch_preview->preview_unstitchable) {
-                       MEM_freeN(_stitch_preview->preview_unstitchable);
-                       _stitch_preview->preview_unstitchable = NULL;
+               if (stitch_preview->preview_unstitchable) {
+                       MEM_freeN(stitch_preview->preview_unstitchable);
+                       stitch_preview->preview_unstitchable = NULL;
                }
-               if (_stitch_preview->static_tris) {
-                       MEM_freeN(_stitch_preview->static_tris);
-                       _stitch_preview->static_tris = NULL;
+               if (stitch_preview->static_tris) {
+                       MEM_freeN(stitch_preview->static_tris);
+                       stitch_preview->static_tris = NULL;
                }
-
-               MEM_freeN(_stitch_preview);
-               _stitch_preview = NULL;
+               MEM_freeN(stitch_preview);
        }
 }
 
-
-/* "getter method" */
-static StitchPreviewer *uv_get_stitch_previewer(void)
-{
-       return _stitch_preview;
-}
-
 #define HEADER_LENGTH 256
 
 /* This function updates the header of the UV editor when the stitch tool updates its settings */
-static void stitch_update_header(StitchState *stitch_state, bContext *C)
+static void stitch_update_header(StitchState *state, bContext *C)
 {
-       static char str[] = "(S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
+       static char str[] = "Mode(TAB) %s, (S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
 
        char msg[HEADER_LENGTH];
        ScrArea *sa = CTX_wm_area(C);
 
        if (sa) {
                BLI_snprintf(msg, HEADER_LENGTH, str,
-                            stitch_state->snap_islands ? "On" : "Off",
-                            stitch_state->midpoints    ? "On" : "Off",
-                            stitch_state->limit_dist,
-                            stitch_state->use_limit    ? "On" : "Off");
+                            state->mode == STITCH_VERT ? "Vertex" : "Edge",
+                            state->snap_islands ? "On" : "Off",
+                            state->midpoints    ? "On" : "Off",
+                            state->limit_dist,
+                            state->use_limit    ? "On" : "Off");
 
                ED_area_headerprint(sa, msg);
        }
@@ -292,30 +299,29 @@ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2])
        uv[1] = uv_rotation_result[1] + medianPoint[1];
 }
 
+/* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */
 static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
 {
        float limit;
-       int do_limit;
 
        if (element_iter == element) {
                return 0;
        }
 
        limit = state->limit_dist;
-       do_limit = state->use_limit;
 
-       if (do_limit) {
-               MLoopUV *luv_orig, *luv_iter;
-               BMLoop *l_orig, *l_iter;
+       if (state->use_limit) {
+               MLoopUV *luv, *luv_iter;
+               BMLoop *l;
 
 
-               l_orig = element->l;
-               luv_orig = CustomData_bmesh_get(&state->em->bm->ldata, l_orig->head.data, CD_MLOOPUV);
-               l_iter = element_iter->l;
-               luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l_iter->head.data, CD_MLOOPUV);
+               l = element->l;
+               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+               l = element_iter->l;
+               luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
 
-               if (fabsf(luv_orig->uv[0] - luv_iter->uv[0]) < limit &&
-                   fabsf(luv_orig->uv[1] - luv_iter->uv[1]) < limit)
+               if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
+                   fabsf(luv->uv[1] - luv_iter->uv[1]) < limit)
                {
                        return 1;
                }
@@ -328,6 +334,46 @@ static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_it
        }
 }
 
+static int stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+{
+       float limit;
+
+       if (edge_iter == edge) {
+               return 0;
+       }
+
+       limit = state->limit_dist;
+
+       if(state->use_limit) {
+               BMLoop *l;
+               MLoopUV *luv_orig1, *luv_iter1;
+               MLoopUV *luv_orig2, *luv_iter2;
+
+               l = state->uvs[edge->uv1]->l;
+               luv_orig1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+               l = state->uvs[edge_iter->uv1]->l;
+               luv_iter1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+               l = state->uvs[edge->uv2]->l;
+               luv_orig2 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+               l = state->uvs[edge_iter->uv2]->l;
+               luv_iter2 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+               if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit &&
+                   fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit &&
+                   fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit &&
+                   fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit)
+               {
+                       return 1;
+               }
+               else {
+                       return 0;
+               }
+       }
+       else {
+               return 1;
+       }
+}
 
 static int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
 {
@@ -341,6 +387,17 @@ static int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *elem
 }
 
 
+static int stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+{
+       if ((state->snap_islands && edge->element->island == edge_iter->element->island) ||
+           (!state->midpoints && edge->element->island == edge_iter->element->island))
+       {
+               return 0;
+       }
+
+       return stitch_check_edges_stitchable(edge, edge_iter, state);
+}
+
 /* calculate snapping for islands */
 static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final)
 {
@@ -378,7 +435,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
                                        }
 
                                        else {
-                                               int face_preview_pos = preview_position[BM_elem_index_get(element->face)].data_position;
+                                               int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position;
 
                                                stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint,
                                                                 preview->preview_polys + face_preview_pos + 2 * element->tfindex);
@@ -414,9 +471,13 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
        l2 = element2->l;
        luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV);
 
-       index1 = uvfinal_map[element1 - state->element_map->buf];
-       index2 = uvfinal_map[element2 - state->element_map->buf];
-
+       if (state->mode == STITCH_VERT) {
+               index1 = uvfinal_map[element1 - state->element_map->buf];
+               index2 = uvfinal_map[element2 - state->element_map->buf];
+       } else {
+               index1 = edge->uv1;
+               index2 = edge->uv2;
+       }
        /* the idea here is to take the directions of the edges and find the rotation between final and initial
         * direction. This, using inner and outer vector products, gives the angle. Directions are differences so... */
        uv1[0] = luv2->uv[0] - luv1->uv[0];
@@ -461,7 +522,10 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
                if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, state)) {
                        int index_tmp1, index_tmp2;
                        float normal[2];
-                       /* easily possible*/
+
+                       /* only calculate rotation against static island uv verts */
+                       if(!state->midpoints && element_iter->island != state->static_island)
+                               continue;
 
                        index_tmp1 = element_iter - state->element_map->buf;
                        index_tmp1 = state->map[index_tmp1];
@@ -482,34 +546,112 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
 }
 
 
-static void stitch_state_delete(StitchState *stitch_state)
+static void state_delete(StitchState *state)
 {
-       if (stitch_state) {
-               if (stitch_state->element_map) {
-                       EDBM_uv_element_map_free(stitch_state->element_map);
+       if (state) {
+               if (state->element_map) {
+                       EDBM_uv_element_map_free(state->element_map);
                }
-               if (stitch_state->uvs) {
-                       MEM_freeN(stitch_state->uvs);
+               if (state->uvs) {
+                       MEM_freeN(state->uvs);
                }
-               if (stitch_state->selection_stack) {
-                       MEM_freeN(stitch_state->selection_stack);
+               if (state->selection_stack) {
+                       MEM_freeN(state->selection_stack);
                }
-               if (stitch_state->tris_per_island) {
-                       MEM_freeN(stitch_state->tris_per_island);
+               if (state->tris_per_island) {
+                       MEM_freeN(state->tris_per_island);
                }
-               if (stitch_state->map) {
-                       MEM_freeN(stitch_state->map);
+               if (state->map) {
+                       MEM_freeN(state->map);
                }
-               if (stitch_state->normals) {
-                       MEM_freeN(stitch_state->normals);
+               if (state->normals) {
+                       MEM_freeN(state->normals);
                }
-               if (stitch_state->edges) {
-                       MEM_freeN(stitch_state->edges);
+               if (state->edges) {
+                       MEM_freeN(state->edges);
                }
-               MEM_freeN(stitch_state);
+               if (state->stitch_preview) {
+                       stitch_preview_delete(state->stitch_preview);
+               }
+               if (state->edge_hash) {
+                       BLI_ghash_free(state->edge_hash, NULL, NULL);
+               }
+               MEM_freeN(state);
        }
 }
 
+static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
+{
+       UvEdge *edges = state->edges;
+       int *map = state->map;
+       UvElementMap *element_map = state->element_map;
+       UvElement *first_element = element_map->buf;
+       int i;
+
+       for (i = 0; i < state->total_separate_edges; i++) {
+               UvEdge *edge = edges + i;
+
+               if(edge->first)
+                       continue;
+
+               /* only boundary edges can be stitched. Yes. Sorry about that :p */
+               if(edge->flag & STITCH_BOUNDARY) {
+                       UvElement *element1 = state->uvs[edge->uv1];
+                       UvElement *element2 = state->uvs[edge->uv2];
+
+                       /* Now iterate through all faces and try to find edges sharing the same vertices */
+                       UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
+                       UvEdge *last_set = edge;
+                       int elemindex2 = BM_elem_index_get(element2->l->v);
+
+                       edge->first = edge;
+
+                       for (; iter1; iter1 = iter1->next) {
+                               UvElement *iter2 = NULL;
+
+                               /* check to see if other vertex of edge belongs to same vertex as */
+                               if(BM_elem_index_get(iter1->l->next->v) == elemindex2)
+                                       iter2 = ED_uv_element_get(element_map, iter1->l->f, iter1->l->next);
+                               else if(BM_elem_index_get(iter1->l->prev->v) == elemindex2)
+                                       iter2 = ED_uv_element_get(element_map, iter1->l->f, iter1->l->prev);
+
+                               if(iter2) {
+                                       int index1 = map[iter1 - first_element];
+                                       int index2 = map[iter2 - first_element];
+
+                                       /* make certain we do not have the same edge! */
+                                       if(state->uvs[index2] != element2 && state->uvs[index1] != element1) {
+                                               UvEdge edgetmp;
+                                               UvEdge *edge2;
+
+
+                                               /* make sure the indices are well behaved */
+                                               if(index1 < index2) {
+                                                       edgetmp.uv1 = index1;
+                                                       edgetmp.uv2 = index2;
+                                               } else {
+                                                       edgetmp.uv1 = index2;
+                                                       edgetmp.uv2 = index1;
+                                               }
+
+                                               /* get the edge from the hash */
+                                               edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
+
+                                               /* here I am taking care of non manifold case, assuming more than two matching edges.
+                                                        * I am not too sure we want this though */
+                                               last_set->next = edge2;
+                                               last_set = edge2;
+                                               /* set first, similarly to uv elements. Now we can iterate among common edges easily */
+                                               edge2->first = edge;
+                                       }
+                               }
+                       }
+               } else {
+                       /* so stitchability code works */
+                       edge->first = edge;
+               }
+       }
+}
 
 
 /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
@@ -526,9 +668,6 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
 
        for (; element_iter; element_iter = element_iter->next) {
                if (element_iter->separate) {
-                       if (element_iter == element) {
-                               continue;
-                       }
                        if (stitch_check_uvs_stitchable(element, element_iter, state)) {
                                island_stitch_data[element_iter->island].stitchableCandidate = 1;
                                island_stitch_data[element->island].stitchableCandidate = 1;
@@ -538,6 +677,19 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
        }
 }
 
+static void determine_uv_edge_stitchability(UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data)
+{
+       UvEdge *edge_iter = edge->first;
+
+       for (; edge_iter; edge_iter = edge_iter->next) {
+               if(stitch_check_edges_stitchable(edge, edge_iter, state)) {
+                       island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
+                       island_stitch_data[edge->element->island].stitchableCandidate = 1;
+                       edge->flag |= STITCH_STITCHABLE_CANDIDATE;
+               }
+       }
+}
+
 
 /* set preview buffer position of UV face in editface->tmp.l */
 static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
@@ -555,7 +707,7 @@ static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer
 /* setup face preview for all coincident uvs and their faces */
 static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
                                                    PreviewPosition *preview_position) {
-       StitchPreviewer *preview = uv_get_stitch_previewer();
+       StitchPreviewer *preview = state->stitch_preview;
 
        /* static island does not change so returning immediately */
        if (state->snap_islands && !state->midpoints && state->static_island == element->island)
@@ -566,17 +718,17 @@ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta
        }
 
        do {
-               stitch_set_face_preview_buffer_position(element->face, preview, preview_position);
+               stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
                element = element->next;
        } while (element && !element->separate);
 }
 
 
 /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
-static void stitch_validate_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+static void stitch_validate_uv_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
                                          PreviewPosition *preview_position) {
        UvElement *element_iter;
-       StitchPreviewer *preview;
+       StitchPreviewer *preview = state->stitch_preview;
        int vert_index;
        BMLoop *l;
 
@@ -584,7 +736,6 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state,
 
        vert_index = BM_elem_index_get(l->v);
 
-       preview = uv_get_stitch_previewer();
        element_iter = state->element_map->vert[vert_index];
 
        for (; element_iter; element_iter = element_iter->next) {
@@ -608,6 +759,72 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state,
        }
 }
 
+
+static void stitch_validate_edge_stichability(UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
+                                         PreviewPosition *preview_position) {
+       UvEdge *edge_iter = edge->first;
+       StitchPreviewer *preview = state->stitch_preview;
+
+       for (; edge_iter; edge_iter = edge_iter->next) {
+               if (edge_iter == edge)
+                       continue;
+               if (stitch_check_edges_state_stitchable(edge, edge_iter, state)) {
+                       if ((edge_iter->element->island == state->static_island) || (edge->element->island == state->static_island)) {
+                                       edge->flag |= STITCH_STITCHABLE;
+                                       preview->num_stitchable++;
+                                       stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], state, island_stitch_data, preview_position);
+                                       stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], state, island_stitch_data, preview_position);
+                                       return;
+                       }
+               }
+       }
+
+       /* this can happen if the uvs to be stitched are not on a stitchable island */
+       if (!(edge->flag & STITCH_STITCHABLE)) {
+               preview->num_unstitchable++;
+       }
+}
+
+
+static void stitch_propagate_uv_final_position (UvElement *element, int index, PreviewPosition *preview_position, UVVertAverage *final_position, StitchState *state, char final, Scene* scene)
+{
+       StitchPreviewer *preview = state->stitch_preview;
+
+       if (element->flag & STITCH_STITCHABLE) {
+               UvElement *element_iter = element;
+               /* propagate to coincident uvs */
+               do {
+                       BMLoop *l;
+                       MLoopUV *luv;
+
+                       l = element_iter->l;
+                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+                       element_iter->flag |= STITCH_PROCESSED;
+                       /* either flush to preview or to the MTFace, if final */
+                       if (final) {
+                               copy_v2_v2(luv->uv, final_position[index].uv);
+
+                               uvedit_uv_select_enable(state->em, scene, l, FALSE);
+                       }
+                       else {
+                               int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
+                               if (face_preview_pos != STITCH_NO_PREVIEW) {
+                                       copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->tfindex,
+                                                  final_position[index].uv);
+                               }
+                       }
+
+                       /* end of calculations, keep only the selection flag */
+                       if ( (!state->snap_islands) || ((!state->midpoints) && (element_iter->island == state->static_island))) {
+                               element_iter->flag &= STITCH_SELECTED;
+                       }
+
+                       element_iter = element_iter->next;
+               } while (element_iter && !element_iter->separate);
+       }
+}
+
 /* main processing function. It calculates preview and final positions. */
 static int stitch_process_data(StitchState *state, Scene *scene, int final)
 {
@@ -618,6 +835,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
        BMFace *efa;
        BMIter iter;
        UVVertAverage *final_position;
+
        char stitch_midpoints = state->midpoints;
        /* used to map uv indices to uvaverage indices for selection */
        unsigned int *uvfinal_map;
@@ -625,8 +843,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
        PreviewPosition *preview_position;
 
        /* cleanup previous preview */
-       stitch_preview_delete();
-       preview = stitch_preview_init();
+       stitch_preview_delete(state->stitch_preview);
+       preview = state->stitch_preview = stitch_preview_init();
        if (preview == NULL)
                return 0;
 
@@ -649,8 +867,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
         *****************************************/
 
        for (i = 0; i < state->selection_size; i++) {
-               UvElement *element = state->selection_stack[i];
-               determine_uv_stitchability(element, state, island_stitch_data);
+               if(state->mode == STITCH_VERT) {
+                       UvElement *element = (UvElement *)state->selection_stack[i];
+                       determine_uv_stitchability(element, state, island_stitch_data);
+               } else {
+                       UvEdge *edge = (UvEdge *)state->selection_stack[i];
+                       determine_uv_edge_stitchability(edge, state, island_stitch_data);
+               }
        }
 
        /* set static island to one that is added for preview */
@@ -664,14 +887,25 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
        }
 
        for (i = 0; i < state->selection_size; i++) {
-               UvElement *element = state->selection_stack[i];
-               if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
-                       element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
-                       stitch_validate_stichability(element, state, island_stitch_data, preview_position);
-               }
-               else {
-                       /* add to preview for unstitchable */
-                       preview->num_unstitchable++;
+               if(state->mode == STITCH_VERT) {
+                       UvElement *element = (UvElement *)state->selection_stack[i];
+                       if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
+                               element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+                               stitch_validate_uv_stichability(element, state, island_stitch_data, preview_position);
+                       }
+                       else {
+                               /* add to preview for unstitchable */
+                               preview->num_unstitchable++;
+                       }
+               } else {
+                       UvEdge *edge = (UvEdge *)state->selection_stack[i];
+                       if(edge->flag & STITCH_STITCHABLE_CANDIDATE) {
+                               edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+                               stitch_validate_edge_stichability(edge, state, island_stitch_data, preview_position);
+                       }
+                       else {
+                               preview->num_unstitchable++;
+                       }
                }
        }
 
@@ -686,7 +920,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
                                numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
                                element = &state->element_map->buf[state->element_map->islandIndices[i]];
                                for (j = 0; j < numOfIslandUVs; j++, element++) {
-                                       stitch_set_face_preview_buffer_position(element->face, preview, preview_position);
+                                       stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
                                }
                        }
                }
@@ -701,11 +935,12 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
                MLoopUV *luv;
                unsigned int buffer_index = 0;
                int stitchBufferIndex = 0, unstitchBufferIndex = 0;
+               int preview_size = (state->mode == STITCH_VERT) ? 2 : 4;
                /* initialize the preview buffers */
                preview->preview_polys = (float *)MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
                preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), "tri_uv_stitch_prev");
-               preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * 2, "stitch_preview_stichable_data");
-               preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * 2, "stitch_preview_unstichable_data");
+               preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stichable_data");
+               preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstichable_data");
 
                preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island] * sizeof(float) * 6, "static_island_preview_tris");
 
@@ -715,7 +950,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
                        return 0;
                }
 
-               /* copy data from MTFaces to the preview display buffers */
+               /* copy data from MLoopUVs to the preview display buffers */
                BM_ITER_MESH (efa, &iter, state->em->bm, BM_FACES_OF_MESH) {
                        /* just to test if face was added for processing. uvs of inselected vertices will return NULL */
                        UvElement *element = ED_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
@@ -757,22 +992,54 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
                }
 
                /* fill the appropriate preview buffers */
-               for (i = 0; i < state->total_separate_uvs; i++) {
-                       UvElement *element = (UvElement *)state->uvs[i];
-                       if (element->flag & STITCH_STITCHABLE) {
-                               l = element->l;
-                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+               if(state->mode == STITCH_VERT) {
+                       for (i = 0; i < state->total_separate_uvs; i++) {
+                               UvElement *element = (UvElement *)state->uvs[i];
+                               if (element->flag & STITCH_STITCHABLE) {
+                                       l = element->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
 
-                               copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
+                                       copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
 
-                               stitchBufferIndex++;
+                                       stitchBufferIndex++;
+                               }
+                               else if (element->flag & STITCH_SELECTED) {
+                                       l = element->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+                                       copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
+                                       unstitchBufferIndex++;
+                               }
                        }
-                       else if (element->flag & STITCH_SELECTED) {
-                               l = element->l;
-                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+               } else {
+                       for (i = 0; i < state->total_separate_edges; i++) {
+                               UvEdge *edge = state->edges + i;
+                               UvElement *element1 = state->uvs[edge->uv1];
+                               UvElement *element2 = state->uvs[edge->uv2];
+
+                               if(edge->flag & STITCH_STITCHABLE) {
+                                       l = element1->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                       copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
 
-                               copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
-                               unstitchBufferIndex++;
+                                       l = element2->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                       copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
+
+                                       stitchBufferIndex++;
+                                       BLI_assert(stitchBufferIndex <= preview->num_stitchable);
+                               } else if (edge->flag & STITCH_SELECTED) {
+                                       l = element1->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                       copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
+
+                                       l = element2->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                       copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
+
+                                       unstitchBufferIndex++;
+                                       BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
+                               }
                        }
                }
        }
@@ -781,141 +1048,215 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
         * Here we calculate the final coordinates of the uvs *
         ******************************************************/
 
-       final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average");
-       uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map");
+       if (state->mode == STITCH_VERT) {
+               final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average");
+               uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map");
+       } else {
+               final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), "stitch_uv_average");
+       }
 
        /* first pass, calculate final position for stitchable uvs of the static island */
        for (i = 0; i < state->selection_size; i++) {
-               UvElement *element = state->selection_stack[i];
-               if (element->flag & STITCH_STITCHABLE) {
-                       BMLoop *l;
-                       MLoopUV *luv;
-                       UvElement *element_iter;
+               if (state->mode == STITCH_VERT) {
+                       UvElement *element = state->selection_stack[i];
 
-                       l = element->l;
-                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                       if (element->flag & STITCH_STITCHABLE) {
+                               BMLoop *l;
+                               MLoopUV *luv;
+                               UvElement *element_iter;
 
+                               l = element->l;
+                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
 
-                       uvfinal_map[element - state->element_map->buf] = i;
+                               uvfinal_map[element - state->element_map->buf] = i;
 
-                       copy_v2_v2(final_position[i].uv, luv->uv);
-                       final_position[i].count = 1;
+                               copy_v2_v2(final_position[i].uv, luv->uv);
+                               final_position[i].count = 1;
 
-                       if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
-                               continue;
+                               if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
+                                       continue;
 
-                       element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+                               element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+
+                               for ( ; element_iter; element_iter = element_iter->next) {
+                                       if (element_iter->separate) {
+                                               if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
+                                                       l = element_iter->l;
+                                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                                       if (stitch_midpoints) {
+                                                               add_v2_v2(final_position[i].uv, luv->uv);
+                                                               final_position[i].count++;
+                                                       }
+                                                       else if (element_iter->island == state->static_island) {
+                                                               /* if multiple uvs on the static island exist,
+                                                                * last checked remains. to disambiguate we need to limit or use
+                                                                * edge stitch */
+                                                               copy_v2_v2(final_position[i].uv, luv->uv);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if (stitch_midpoints) {
+                               final_position[i].uv[0] /= final_position[i].count;
+                               final_position[i].uv[1] /= final_position[i].count;
+                       }
+               } else {
+                       UvEdge *edge = state->selection_stack[i];
 
-                       for ( ; element_iter; element_iter = element_iter->next) {
-                               if (element_iter->separate) {
-                                       if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
-                                               l = element_iter->l;
-                                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
-                                               if (stitch_midpoints) {
-                                                       add_v2_v2(final_position[i].uv, luv->uv);
-                                                       final_position[i].count++;
+                       if (edge->flag & STITCH_STITCHABLE) {
+                               MLoopUV *luv2, *luv1;
+                               BMLoop *l;
+                               UvEdge *edge_iter;
+
+                               l = state->uvs[edge->uv1]->l;
+                               luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                               l = state->uvs[edge->uv2]->l;
+                               luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+                               copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+                               copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
+                               final_position[edge->uv1].count = 1;
+                               final_position[edge->uv2].count = 1;
+
+                               state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
+                               state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
+
+                               if (state->snap_islands && edge->element->island == state->static_island && !stitch_midpoints)
+                                       continue;
+
+                               for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
+                                       if (stitch_check_edges_state_stitchable (edge, edge_iter, state)) {
+                                               l = state->uvs[edge_iter->uv1]->l;
+                                               luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                                               l = state->uvs[edge_iter->uv2]->l;
+                                               luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+                                               if(stitch_midpoints) {
+                                                       add_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+                                                       final_position[edge->uv1].count++;
+                                                       add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
+                                                       final_position[edge->uv2].count++;
                                                }
-                                               else if (element_iter->island == state->static_island) {
-                                                       /* if multiple uvs on the static island exist,
-                                                        * last checked remains. to disambiguate we need to limit or use
-                                                        * edge stitch */
-                                                       copy_v2_v2(final_position[i].uv, luv->uv);
+                                               else if (edge_iter->element->island == state->static_island) {
+                                                       copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+                                                       copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
                                                }
                                        }
                                }
                        }
                }
-               if (stitch_midpoints) {
-                       final_position[i].uv[0] /= final_position[i].count;
-                       final_position[i].uv[1] /= final_position[i].count;
-               }
        }
 
        /* second pass, calculate island rotation and translation before modifying any uvs */
        if (state->snap_islands) {
-               for (i = 0; i < state->selection_size; i++) {
-                       UvElement *element = state->selection_stack[i];
-                       if (element->flag & STITCH_STITCHABLE) {
-                               BMLoop *l;
-                               MLoopUV *luv;
+               if (state->mode == STITCH_VERT) {
+                       for (i = 0; i < state->selection_size; i++) {
+                               UvElement *element = state->selection_stack[i];
 
-                               l = element->l;
-                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                               if (element->flag & STITCH_STITCHABLE) {
+                                       BMLoop *l;
+                                       MLoopUV *luv;
 
-                               /* accumulate each islands' translation from stitchable elements. it is important to do here
-                                * because in final pass MTFaces get modified and result is zero. */
-                               island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
-                               island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
-                               island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
-                               island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
-                               island_stitch_data[element->island].numOfElements++;
-                       }
-               }
+                                       l = element->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
 
-               /* only calculate rotation when an edge has been fully selected */
-               for (i = 0; i < state->total_boundary_edges; i++) {
-                       UvEdge *edge = state->edges + i;
-                       if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
-                               stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
-                               island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
+                                       /* accumulate each islands' translation from stitchable elements. it is important to do here
+                                        * because in final pass MTFaces get modified and result is zero. */
+                                       island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
+                                       island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
+                                       island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
+                                       island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
+                                       island_stitch_data[element->island].numOfElements++;
+                               }
                        }
-               }
 
-               /* clear seams of stitched edges */
-               if (final && state->clear_seams) {
-                       for (i = 0; i < state->total_boundary_edges; i++) {
+                       /* only calculate rotation when an edge has been fully selected */
+                       for (i = 0; i < state->total_separate_edges; i++) {
                                UvEdge *edge = state->edges + i;
-                               if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
-                                       BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
+                               if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
+                                       stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
+                                       island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
+                               }
                        }
-               }
 
-               for (i = 0; i < state->selection_size; i++) {
-                       UvElement *element = state->selection_stack[i];
-                       if (!island_stitch_data[element->island].use_edge_rotation) {
-                               if (element->flag & STITCH_STITCHABLE) {
-                                       stitch_island_calculate_vert_rotation(element, state, island_stitch_data);
+                       /* clear seams of stitched edges */
+                       if (final && state->clear_seams) {
+                               for (i = 0; i < state->total_separate_edges; i++) {
+                                       UvEdge *edge = state->edges + i;
+                                       if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
+                                               BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
                                }
                        }
-               }
 
-       }
+                       for (i = 0; i < state->selection_size; i++) {
+                               UvElement *element = state->selection_stack[i];
+                               if (!island_stitch_data[element->island].use_edge_rotation) {
+                                       if (element->flag & STITCH_STITCHABLE) {
+                                               stitch_island_calculate_vert_rotation(element, state, island_stitch_data);
+                                       }
+                               }
+                       }
+               } else {
+                       for (i = 0; i < state->total_separate_uvs; i++) {
+                               UvElement *element = state->uvs[i];
 
-       /* third pass, propagate changes to coincident uvs */
-       for (i = 0; i < state->selection_size; i++) {
-               UvElement *element = state->selection_stack[i];
-               if (element->flag & STITCH_STITCHABLE) {
-                       UvElement *element_iter = element;
-                       /* propagate to coincident uvs */
-                       do {
-                               BMLoop *l;
-                               MLoopUV *luv;
+                               if (stitch_midpoints) {
+                                       final_position[i].uv[0] /= final_position[i].count;
+                                       final_position[i].uv[1] /= final_position[i].count;
+                               }
 
-                               l = element_iter->l;
-                               luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+                               if (element->flag & STITCH_STITCHABLE) {
+                                       BMLoop *l;
+                                       MLoopUV *luv;
 
-                               element_iter->flag |= STITCH_PROCESSED;
-                               /* either flush to preview or to the MTFace, if final */
-                               if (final) {
-                                       copy_v2_v2(luv->uv, final_position[i].uv);
+                                       l = element->l;
+                                       luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
 
-                                       uvedit_uv_select_enable(state->em, scene, l, FALSE);
+                                       /* accumulate each islands' translation from stitchable elements. it is important to do here
+                                        * because in final pass MTFaces get modified and result is zero. */
+                                       island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
+                                       island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
+                                       island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
+                                       island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
+                                       island_stitch_data[element->island].numOfElements++;
                                }
-                               else {
-                                       int face_preview_pos = preview_position[BM_elem_index_get(element_iter->face)].data_position;
-                                       if (face_preview_pos != STITCH_NO_PREVIEW) {
-                                               copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->tfindex,
-                                                          final_position[i].uv);
-                                       }
+                       }
+
+                       for (i = 0; i < state->selection_size; i++) {
+                               UvEdge *edge = state->selection_stack[i];
+
+                               if(edge->flag & STITCH_STITCHABLE) {
+                                       stitch_island_calculate_edge_rotation(edge, state, final_position, NULL, island_stitch_data);
+                                       island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
                                }
+                       }
 
-                               /* end of calculations, keep only the selection flag */
-                               if ( (!state->snap_islands) || ((!stitch_midpoints) && (element_iter->island == state->static_island))) {
-                                       element_iter->flag &= STITCH_SELECTED;
+                       /* clear seams of stitched edges */
+                       if (final && state->clear_seams) {
+                               for (i = 0; i < state->selection_size; i++) {
+                                       UvEdge *edge = state->selection_stack[i];
+                                       if(edge->flag & STITCH_STITCHABLE) {
+                                               BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
+                                       }
                                }
+                       }
+               }
+       }
+
+       /* third pass, propagate changes to coincident uvs */
+       for (i = 0; i < state->selection_size; i++) {
+               if (state->mode == STITCH_VERT) {
+                       UvElement *element = state->selection_stack[i];
+
+                       stitch_propagate_uv_final_position (element, i, preview_position, final_position, state, final, scene);
+               }  else {
+                       UvEdge *edge = state->selection_stack[i];
+
+                       stitch_propagate_uv_final_position (state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final, scene);
+                       stitch_propagate_uv_final_position (state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final, scene);
 
-                               element_iter = element_iter->next;
-                       } while (element_iter && !element_iter->separate);
+                       edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
                }
        }
 
@@ -925,7 +1266,9 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
        }
 
        MEM_freeN(final_position);
-       MEM_freeN(uvfinal_map);
+       if (state->mode == STITCH_VERT) {
+               MEM_freeN(uvfinal_map);
+       }
        MEM_freeN(island_stitch_data);
        MEM_freeN(preview_position);
 
@@ -937,8 +1280,8 @@ static unsigned int uv_edge_hash(const void *key)
 {
        UvEdge *edge = (UvEdge *)key;
        return
-           BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
-           BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
 }
 
 static int uv_edge_compare(const void *a, const void *b)
@@ -952,13 +1295,41 @@ static int uv_edge_compare(const void *a, const void *b)
        return 1;
 }
 
+/* select all common edges */
+static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select)
+{
+       UvEdge *eiter;
+       UvEdge **selection_stack = (UvEdge **)state->selection_stack;
+
+       for (eiter = edge->first; eiter; eiter = eiter->next) {
+               if (eiter->flag & STITCH_SELECTED) {
+                       int i;
+                       if (always_select)
+                               continue;
+
+                       eiter->flag &= ~STITCH_SELECTED;
+                       for (i = 0; i < state->selection_size; i++) {
+                               if (selection_stack[i] == eiter) {
+                                       (state->selection_size)--;
+                                       selection_stack[i] = selection_stack[state->selection_size];
+                                       break;
+                               }
+                       }
+               }
+               else {
+                       eiter->flag |= STITCH_SELECTED;
+                       selection_stack[state->selection_size++] = eiter;
+               }
+       }
+}
+
 
 /* Select all common uvs */
 static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
 {
        BMLoop *l;
        UvElement *element_iter;
-       UvElement **selection_stack = state->selection_stack;
+       UvElement **selection_stack = (UvElement **)state->selection_stack;
 
        l = element->l;
 
@@ -989,6 +1360,54 @@ static void stitch_select_uv(UvElement *element, StitchState *state, int always_
        }
 }
 
+static void stitch_switch_selection_mode(StitchState *state)
+{
+       void **old_selection_stack = state->selection_stack;
+       int old_selection_size = state->selection_size;
+       state->selection_size = 0;
+
+       if (state->mode == STITCH_VERT) {
+               int i;
+               state->selection_stack = MEM_mallocN(state->total_separate_edges*sizeof(*state->selection_stack),
+                                                    "stitch_new_edge_selection_stack");
+
+               /* check if both elements of an edge are selected */
+               for (i = 0; i < state->total_separate_edges; i++) {
+                       UvEdge *edge = state->edges + i;
+                       UvElement *element1 = state->uvs[edge->uv1];
+                       UvElement *element2 = state->uvs[edge->uv2];
+
+                       if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED))
+                               stitch_select_edge(edge, state, TRUE);
+               }
+
+               /* unselect selected uvelements */
+               for (i = 0; i < old_selection_size; i++) {
+                       UvElement *element = old_selection_stack[i];
+
+                       element->flag &= ~STITCH_SELECTED;
+               }
+               state->mode = STITCH_EDGE;
+       } else {
+               int i;
+               state->selection_stack = MEM_mallocN(state->total_separate_uvs*sizeof(*state->selection_stack),
+                                                    "stitch_new_vert_selection_stack");
+
+               for (i = 0; i < old_selection_size; i++) {
+                       UvEdge *edge = old_selection_stack[i];
+                       UvElement *element1 = state->uvs[edge->uv1];
+                       UvElement *element2 = state->uvs[edge->uv2];
+
+                       stitch_select_uv(element1, state, TRUE);
+                       stitch_select_uv(element2, state, TRUE);
+
+                       edge->flag &= ~STITCH_SELECTED;
+               }
+               state->mode = STITCH_VERT;
+       }
+       MEM_freeN(old_selection_stack);
+}
+
 static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal)
 {
        BMLoop *l1 = edge->element->l;
@@ -1007,11 +1426,12 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
        normalize_v2(normal);
 }
 
-static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *UNUSED(arg))
+static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
 {
        int i, index = 0;
        float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
-       StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
+       StitchState *state = (StitchState *)arg;
+       StitchPreviewer *stitch_preview = state->stitch_preview;
 
        glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
        glEnableClientState(GL_VERTEX_ARRAY);
@@ -1042,24 +1462,56 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *UN
        glDisable(GL_BLEND);
 
        /* draw vert preview */
-       glPointSize(pointsize * 2.0f);
-       UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
-       glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
-       glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
-
-       UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
-       glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
-       glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+       if(state->mode == STITCH_VERT) {
+               glPointSize(pointsize * 2.0f);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
+               glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
+
+               UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
+               glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+       } else {
+               UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
+               glDrawArrays(GL_LINES, 0, 2*stitch_preview->num_stitchable);
+
+               UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
+               glDrawArrays(GL_LINES, 0, 2*stitch_preview->num_unstitchable);
+       }
 
        glPopClientAttrib();
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 
+       glPointSize(1.0);
+}
+
+static UvEdge *uv_edge_get (BMLoop *l, StitchState *state)
+{
+       UvEdge tmp_edge;
+
+       UvElement *element1 = ED_uv_element_get(state->element_map, l->f, l);
+       UvElement *element2 = ED_uv_element_get(state->element_map, l->f, l->next);
+
+       int uv1 = state->map[element1 - state->element_map->buf];
+       int uv2 = state->map[element2 - state->element_map->buf];
+
+       if(uv1 < uv2) {
+               tmp_edge.uv1 = uv1;
+               tmp_edge.uv2 = uv2;
+       } else {
+               tmp_edge.uv1 = uv2;
+               tmp_edge.uv2 = uv1;
+       }
+
+       return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
 }
 
 static int stitch_init(bContext *C, wmOperator *op)
 {
        /* for fast edge lookup... */
-       GHash *edgeHash;
+       GHash *edge_hash;
        /* ...and actual edge storage */
        UvEdge *edges;
        int total_edges;
@@ -1097,21 +1549,38 @@ static int stitch_init(bContext *C, wmOperator *op)
        state->static_island = RNA_int_get(op->ptr, "static_island");
        state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
        state->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
-       state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, NULL, REGION_DRAW_POST_VIEW);
+       if (RNA_struct_property_is_set(op->ptr, "mode")) {
+               state->mode = RNA_enum_get(op->ptr, "mode");
+       } else {
+               if (ts->uv_flag & UV_SYNC_SELECTION) {
+                       if (ts->selectmode & SCE_SELECT_VERTEX)
+                               state->mode = STITCH_VERT;
+                       else
+                               state->mode = STITCH_EDGE;
+               } else {
+                       if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+                               state->mode = STITCH_VERT;
+                       } else {
+                               state->mode = STITCH_EDGE;
+                       }
+               }
+       }
+
+       state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, state, REGION_DRAW_POST_VIEW);
        /* in uv synch selection, all uv's are visible */
        if (ts->uv_flag & UV_SYNC_SELECTION) {
-               state->element_map = EDBM_uv_element_map_create(state->em, 0, 1);
+               state->element_map = EDBM_uv_element_map_create(state->em, FALSE, TRUE);
        }
        else {
-               state->element_map = EDBM_uv_element_map_create(state->em, 1, 1);
+               state->element_map = EDBM_uv_element_map_create(state->em, TRUE, TRUE);
        }
        if (!state->element_map) {
-               stitch_state_delete(state);
+               state_delete(state);
                return 0;
        }
 
        /* Entirely possible if redoing last operator that static island is bigger than total number of islands.
-        * This ensures we get no hang in the island checking code in stitch_process_data. */
+        * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */
        state->static_island %= state->element_map->totalIslands;
 
        /* Count 'unique' uvs */
@@ -1121,22 +1590,21 @@ static int stitch_init(bContext *C, wmOperator *op)
                }
        }
 
+       /* explicitly set preview to NULL, to avoid deleting an invalid pointer on stitch_process_data */
+       state->stitch_preview = NULL;
        /* Allocate the unique uv buffers */
        state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
        /* internal uvs need no normals but it is hard and slow to keep a map of
         * normals only for boundary uvs, so allocating for all uvs */
        state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
        state->total_separate_uvs = counter;
-       /* we can at most have totalUVs edges or uvs selected. Actually they are less, considering we store only
-        * unique uvs for processing but I am accounting for all bizarre cases, especially for edges, this way */
-       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * counter, "uv_stitch_selection_stack");
        state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map");
        /* Allocate the edge stack */
-       edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+       edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
        all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "stitch_all_edges");
 
-       if (!state->selection_stack || !state->uvs || !map || !edgeHash || !all_edges) {
-               stitch_state_delete(state);
+       if (!state->uvs || !map || !edge_hash || !all_edges) {
+               state_delete(state);
                return 0;
        }
 
@@ -1169,6 +1637,8 @@ static int stitch_init(bContext *C, wmOperator *op)
                        offset1 = map[itmp1];
                        offset2 = map[itmp2];
 
+                       all_edges[counter].next = NULL;
+                       all_edges[counter].first = NULL;
                        all_edges[counter].flag = 0;
                        all_edges[counter].element = element;
                        /* using an order policy, sort uvs according to address space. This avoids
@@ -1182,12 +1652,12 @@ static int stitch_init(bContext *C, wmOperator *op)
                                all_edges[counter].uv2 = offset1;
                        }
 
-                       if (BLI_ghash_haskey(edgeHash, &all_edges[counter])) {
-                               char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]);
-                               *flag = 0;
+                       if (BLI_ghash_haskey(edge_hash, &all_edges[counter])) {
+                               UvEdge *edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
+                               edge->flag = 0;
                        }
                        else {
-                               BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag));
+                               BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
                                all_edges[counter].flag = STITCH_BOUNDARY;
                        }
                        counter++;
@@ -1195,55 +1665,55 @@ static int stitch_init(bContext *C, wmOperator *op)
        }
 
 
-       ghi = BLI_ghashIterator_new(edgeHash);
-       total_edges = 0;
-       /* fill the edges with data */
-       for (; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
-               UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
-               if (edge->flag & STITCH_BOUNDARY) {
-                       total_edges++;
-               }
-       }
+       ghi = BLI_ghashIterator_new(edge_hash);
+       total_edges = BLI_ghash_size(edge_hash);
        state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
-       if (!ghi || !edges) {
-               MEM_freeN(all_edges);
-               stitch_state_delete(state);
+
+       /* I assume any system will be able to at least allocate an iterator :p */
+       if (!edges) {
+               BLI_ghashIterator_free(ghi);
+               state_delete(state);
                return 0;
        }
 
-       state->total_boundary_edges = total_edges;
+       state->total_separate_edges = total_edges;
 
        /* fill the edges with data */
-       for (i = 0, BLI_ghashIterator_init(ghi, edgeHash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
-               UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
-               if (edge->flag & STITCH_BOUNDARY) {
-                       edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
-               }
+       for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
+               edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
        }
 
        /* cleanup temporary stuff */
        BLI_ghashIterator_free(ghi);
        MEM_freeN(all_edges);
 
-       /* refill hash with new pointers to cleanup duplicates */
-       BLI_ghash_free(edgeHash, NULL, NULL);
+       BLI_ghash_free(edge_hash, NULL, NULL);
+
+       /* refill an edge hash to create edge connnectivity data */
+       state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+       for (i = 0; i < total_edges; i++) {
+               BLI_ghash_insert(edge_hash, edges + i, edges + i);
+       }
+       stitch_uv_edge_generate_linked_edges(edge_hash, state);
 
        /***** calculate 2D normals for boundary uvs *****/
 
        /* we use boundary edges to calculate 2D normals.
         * to disambiguate the direction of the normal, we also need
         * a point "inside" the island, that can be provided by
-        * the opposite uv for a quad, or the next uv for a triangle. */
+        * the winding of the polygon (assuming counter-clockwise flow). */
 
        for (i = 0; i < total_edges; i++) {
                float normal[2];
-               stitch_calculate_edge_normal(em, edges + i, normal);
+               if (edges[i].flag & STITCH_BOUNDARY) {
+                       stitch_calculate_edge_normal(em, edges + i, normal);
 
-               add_v2_v2(state->normals + edges[i].uv1 * 2, normal);
-               add_v2_v2(state->normals + edges[i].uv2 * 2, normal);
+                       add_v2_v2(state->normals + edges[i].uv1 * 2, normal);
+                       add_v2_v2(state->normals + edges[i].uv2 * 2, normal);
 
-               normalize_v2(state->normals + edges[i].uv1 * 2);
-               normalize_v2(state->normals + edges[i].uv2 * 2);
+                       normalize_v2(state->normals + edges[i].uv1 * 2);
+                       normalize_v2(state->normals + edges[i].uv2 * 2);
+               }
        }
 
 
@@ -1255,30 +1725,86 @@ static int stitch_init(bContext *C, wmOperator *op)
        if (RNA_struct_property_is_set(op->ptr, "selection")) {
                int faceIndex, elementIndex;
                UvElement *element;
+               enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
 
                EDBM_index_arrays_ensure(em, BM_FACE);
 
-               RNA_BEGIN (op->ptr, itemptr, "selection")
-               {
-                       faceIndex = RNA_int_get(&itemptr, "face_index");
-                       elementIndex = RNA_int_get(&itemptr, "element_index");
-                       efa = EDBM_face_at_index(em, faceIndex);
-                       element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
-                       stitch_select_uv(element, state, 1);
-               }
-               RNA_END;
+               if(stored_mode == STITCH_VERT) {
+                       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
 
+                       RNA_BEGIN (op->ptr, itemptr, "selection")
+                       {
+                               faceIndex = RNA_int_get(&itemptr, "face_index");
+                               elementIndex = RNA_int_get(&itemptr, "element_index");
+                               efa = EDBM_face_at_index(em, faceIndex);
+                               element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+                               stitch_select_uv(element, state, 1);
+                       }
+                       RNA_END;
+               } else {
+                       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
+
+                       RNA_BEGIN (op->ptr, itemptr, "selection")
+                       {
+                               UvEdge tmp_edge, *edge;
+                               int uv1, uv2;
+                               faceIndex = RNA_int_get(&itemptr, "face_index");
+                               elementIndex = RNA_int_get(&itemptr, "element_index");
+                               efa = EDBM_face_at_index(em, faceIndex);
+                               element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+                               uv1 = map[element - state->element_map->buf];
+
+                               element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex+1)%efa->len));
+                               uv2 = map[element - state->element_map->buf];
+
+                               if(uv1 < uv2) {
+                                       tmp_edge.uv1 = uv1;
+                                       tmp_edge.uv2 = uv2;
+                               } else {
+                                       tmp_edge.uv1 = uv2;
+                                       tmp_edge.uv2 = uv1;
+                               }
+
+                               edge = BLI_ghash_lookup(edge_hash, &tmp_edge);
+
+                               stitch_select_edge(edge, state, TRUE);
+                       }
+                       RNA_END;
+               }
+               /* if user has switched the operator mode after operation, we need to convert
+                * the stored format */
+               if (state->mode != stored_mode) {
+                       state->mode = stored_mode;
+                       stitch_switch_selection_mode(state);
+               }
                /* Clear the selection */
                RNA_collection_clear(op->ptr, "selection");
 
        }
        else {
-               BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
-                       BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-                               if (uvedit_uv_select_test(em, scene, l)) {
-                                       UvElement *element = ED_uv_element_get(state->element_map, efa, l);
-                                       if (element) {
-                                               stitch_select_uv(element, state, 1);
+               if(state->mode == STITCH_VERT) {
+                       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
+
+                       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+                               BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+                                       if (uvedit_uv_select_test(em, scene, l)) {
+                                               UvElement *element = ED_uv_element_get(state->element_map, efa, l);
+                                               if (element) {
+                                                       stitch_select_uv(element, state, 1);
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
+
+                       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+                               BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+                                       if(uvedit_edge_select_test(em, scene, l)) {
+                                               UvEdge *edge = uv_edge_get(l, state);
+                                               if(edge) {
+                                                       stitch_select_edge(edge, state, TRUE);
+                                               }
                                        }
                                }
                        }
@@ -1301,8 +1827,9 @@ static int stitch_init(bContext *C, wmOperator *op)
                }
        }
 
-       if (!stitch_process_data(state, scene, 0)) {
-               stitch_state_delete(state);
+       if (!stitch_process_data(state, scene, FALSE)) {
+
+               state_delete(state);
                return 0;
        }
 
@@ -1323,7 +1850,7 @@ static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
 static void stitch_exit(bContext *C, wmOperator *op, int finished)
 {
-       StitchState *stitch_state;
+       StitchState *state;
        Scene *scene;
        SpaceImage *sima;
        ScrArea *sa = CTX_wm_area(C);
@@ -1333,45 +1860,47 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
        obedit = CTX_data_edit_object(C);
        sima = CTX_wm_space_image(C);
 
-       stitch_state = (StitchState *)op->customdata;
+       state = (StitchState *)op->customdata;
 
        if (finished) {
                int i;
 
-               RNA_float_set(op->ptr, "limit", stitch_state->limit_dist);
-               RNA_boolean_set(op->ptr, "use_limit", stitch_state->use_limit);
-               RNA_boolean_set(op->ptr, "snap_islands", stitch_state->snap_islands);
-               RNA_int_set(op->ptr, "static_island", stitch_state->static_island);
-               RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoints);
+               RNA_float_set(op->ptr, "limit", state->limit_dist);
+               RNA_boolean_set(op->ptr, "use_limit", state->use_limit);
+               RNA_boolean_set(op->ptr, "snap_islands", state->snap_islands);
+               RNA_int_set(op->ptr, "static_island", state->static_island);
+               RNA_boolean_set(op->ptr, "midpoint_snap", state->midpoints);
+               RNA_enum_set(op->ptr, "mode", state->mode);
+               RNA_enum_set(op->ptr, "stored_mode", state->mode);
 
                /* Store selection for re-execution of stitch */
-               for (i = 0; i < stitch_state->selection_size; i++) {
+               for (i = 0; i < state->selection_size; i++) {
+                       UvElement *element;
                        PointerRNA itemptr;
-                       UvElement *element = stitch_state->selection_stack[i];
-
+                       if (state->mode == STITCH_VERT) {
+                               element = state->selection_stack[i];
+                       } else {
+                               element = ((UvEdge *)state->selection_stack[i])->element;
+                       }
                        RNA_collection_add(op->ptr, "selection", &itemptr);
 
-                       RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->face));
-
+                       RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
                        RNA_int_set(&itemptr, "element_index", element->tfindex);
                }
 
-
                uvedit_live_unwrap_update(sima, scene, obedit);
        }
 
        if (sa)
                ED_area_headerprint(sa, NULL);
 
-       ED_region_draw_cb_exit(CTX_wm_region(C)->type, stitch_state->draw_handle);
+       ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle);
 
        DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
 
-       stitch_state_delete(stitch_state);
+       state_delete(state);
        op->customdata = NULL;
-
-       stitch_preview_delete();
 }
 
 
@@ -1397,7 +1926,7 @@ static int stitch_exec(bContext *C, wmOperator *op)
        }
 }
 
-static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *stitch_state)
+static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *state)
 {
        /* add uv under mouse to processed uv's */
        float co[2];
@@ -1406,42 +1935,52 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState
        Image *ima = CTX_data_edit_image(C);
 
        UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
-       uv_find_nearest_vert(scene, ima, stitch_state->em, co, NULL, &hit);
 
-       if (hit.efa) {
-               /* Add vertex to selection, deselect all common uv's of vert other
-                * than selected and update the preview. This behavior was decided so that
-                * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
+       if(state->mode == STITCH_VERT) {
+               uv_find_nearest_vert(scene, ima, state->em, co, NULL, &hit);
 
-               /* This works due to setting of tmp in find nearest uv vert */
-               UvElement *element = ED_uv_element_get(stitch_state->element_map, hit.efa, hit.l);
-               stitch_select_uv(element, stitch_state, 0);
+               if (hit.efa) {
+                       /* Add vertex to selection, deselect all common uv's of vert other
+                        * than selected and update the preview. This behavior was decided so that
+                        * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
 
+                       /* This works due to setting of tmp in find nearest uv vert */
+                       UvElement *element = ED_uv_element_get(state->element_map, hit.efa, hit.l);
+                       stitch_select_uv(element, state, FALSE);
+
+               }
+       } else {
+               uv_find_nearest_edge(scene, ima, state->em, co, &hit);
+
+               if(hit.efa) {
+                       UvEdge *edge = uv_edge_get(hit.l, state);
+                       stitch_select_edge(edge, state, FALSE);
+               }
        }
 }
 
 static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
-       StitchState *stitch_state;
+       StitchState *state;
        Scene *scene = CTX_data_scene(C);
 
-       stitch_state = (StitchState *)op->customdata;
+       state = (StitchState *)op->customdata;
 
        switch (event->type) {
                case MIDDLEMOUSE:
                        return OPERATOR_PASS_THROUGH;
 
-               /* Cancel */
+                       /* Cancel */
                case ESCKEY:
                        return stitch_cancel(C, op);
 
 
                case LEFTMOUSE:
                        if (event->shift && (U.flag & USER_LMOUSESELECT)) {
-                               if (event->val == KM_RELEASE) {
-                                       stitch_select(C, scene, event, stitch_state);
+                               if (event->val == KM_PRESS) {
+                                       stitch_select(C, scene, event, state);
 
-                                       if (!stitch_process_data(stitch_state, scene, 0)) {
+                                       if (!stitch_process_data(state, scene, FALSE)) {
                                                return stitch_cancel(C, op);
                                        }
                                }
@@ -1450,7 +1989,7 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
                case PADENTER:
                case RETKEY:
                        if (event->val == KM_PRESS) {
-                               if (stitch_process_data(stitch_state, scene, 1)) {
+                               if (stitch_process_data(state, scene, TRUE)) {
                                        stitch_exit(C, op, 1);
                                        return OPERATOR_FINISHED;
                                }
@@ -1461,12 +2000,12 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
                        else {
                                return OPERATOR_PASS_THROUGH;
                        }
-               /* Increase limit */
+                       /* Increase limit */
                case PADPLUSKEY:
                case WHEELUPMOUSE:
                        if (event->val == KM_PRESS && event->alt) {
-                               stitch_state->limit_dist += 0.01f;
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               state->limit_dist += 0.01f;
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
@@ -1474,13 +2013,13 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
                        else {
                                return OPERATOR_PASS_THROUGH;
                        }
-               /* Decrease limit */
+                       /* Decrease limit */
                case PADMINUS:
                case WHEELDOWNMOUSE:
                        if (event->val == KM_PRESS && event->alt) {
-                               stitch_state->limit_dist -= 0.01f;
-                               stitch_state->limit_dist = MAX2(0.01f, stitch_state->limit_dist);
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               state->limit_dist -= 0.01f;
+                               state->limit_dist = MAX2(0.01f, state->limit_dist);
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
@@ -1489,11 +2028,11 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
                                return OPERATOR_PASS_THROUGH;
                        }
 
-               /* Use Limit (Default off)*/
+                       /* Use Limit (Default off)*/
                case LKEY:
                        if (event->val == KM_PRESS) {
-                               stitch_state->use_limit = !stitch_state->use_limit;
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               state->use_limit = !state->use_limit;
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
@@ -1502,10 +2041,10 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
 
                case IKEY:
                        if (event->val == KM_PRESS) {
-                               stitch_state->static_island++;
-                               stitch_state->static_island %= stitch_state->element_map->totalIslands;
+                               state->static_island++;
+                               state->static_island %= state->element_map->totalIslands;
 
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
@@ -1514,33 +2053,33 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
 
                case MKEY:
                        if (event->val == KM_PRESS) {
-                               stitch_state->midpoints = !stitch_state->midpoints;
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               state->midpoints = !state->midpoints;
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                        }
                        break;
 
-               /* Select geometry*/
+                       /* Select geometry*/
                case RIGHTMOUSE:
                        if (!event->shift) {
                                return stitch_cancel(C, op);
                        }
-                       if (event->val == KM_RELEASE && !(U.flag & USER_LMOUSESELECT)) {
-                               stitch_select(C, scene, event, stitch_state);
+                       if (event->val == KM_PRESS && !(U.flag & USER_LMOUSESELECT)) {
+                               stitch_select(C, scene, event, state);
 
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
                        }
                        return OPERATOR_RUNNING_MODAL;
 
-               /* snap islands on/off */
+                       /* snap islands on/off */
                case SKEY:
                        if (event->val == KM_PRESS) {
-                               stitch_state->snap_islands = !stitch_state->snap_islands;
-                               if (!stitch_process_data(stitch_state, scene, 0)) {
+                               state->snap_islands = !state->snap_islands;
+                               if (!stitch_process_data(state, scene, FALSE)) {
                                        return stitch_cancel(C, op);
                                }
                                break;
@@ -1549,12 +2088,23 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
                                return OPERATOR_RUNNING_MODAL;
                        }
 
+                       /* switch between edge/vertex mode */
+               case TABKEY:
+                       if (event->val == KM_PRESS) {
+                               stitch_switch_selection_mode(state);
+
+                               if (!stitch_process_data(state, scene, FALSE)) {
+                                       return stitch_cancel(C, op);
+                               }
+                       }
+                       break;
+
                default:
                        return OPERATOR_RUNNING_MODAL;
        }
 
        /* if updated settings, renew feedback message */
-       stitch_update_header(stitch_state, C);
+       stitch_update_header(state, C);
        ED_region_tag_redraw(CTX_wm_region(C));
        return OPERATOR_RUNNING_MODAL;
 }
@@ -1563,6 +2113,12 @@ void UV_OT_stitch(wmOperatorType *ot)
 {
        PropertyRNA *prop;
 
+       static EnumPropertyItem stitch_modes[] = {
+           {STITCH_VERT, "VERTEX", 0, "Vertex", ""},
+           {STITCH_EDGE, "EDGE", 0, "Edge", ""},
+           {0, NULL, 0, NULL, NULL}
+       };
+
        /* identifiers */
        ot->name = "Stitch";
        ot->description = "Stitch selected UV vertices by proximity";
@@ -1589,6 +2145,11 @@ void UV_OT_stitch(wmOperatorType *ot)
                        "UVs are stitched at midpoint instead of at static island");
        RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams",
                        "Clear seams of stitched edges");
+       RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode",
+                    "Use vertex or edge stitching");
+       prop =  RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode",
+                            "Use vertex or edge stitching");
+       RNA_def_property_flag(prop, PROP_HIDDEN);
        prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
        /* Selection should not be editable or viewed in toolbar */
        RNA_def_property_flag(prop, PROP_HIDDEN);