static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst) { Heap *heap; int i, vert_curr; int totu = nu->pntsu; int totv = nu->pntsv; int vert_num = totu * totv; /* custom data */ struct PointAdj { int vert, vert_prev; float cost; } *data; /* init connectivity data */ data = MEM_mallocN(sizeof(*data) * vert_num, __func__); for (i = 0; i < vert_num; i++) { data[i].vert = i; data[i].vert_prev = -1; data[i].cost = FLT_MAX; } /* init heap */ heap = BLI_heap_new(); BLI_heap_insert(heap, 0.0f, &data[vert_src].vert); data[vert_src].cost = 0.0f; data[vert_src].vert_prev = vert_src; /* nop */ while (!BLI_heap_is_empty(heap)) { int axis, sign; int u, v; vert_curr = *((int *)BLI_heap_popmin(heap)); if (vert_curr == vert_dst) { break; } BKE_nurb_index_to_uv(nu, vert_curr, &u, &v); /* loop over 4 adjacent verts */ for (sign = -1; sign != 3; sign += 2) { for (axis = 0; axis != 2; axis += 1) { int uv_other[2] = {u, v}; int vert_other; uv_other[axis] += sign; vert_other = BKE_nurb_index_from_uv(nu, uv_other[0], uv_other[1]); if (vert_other != -1) { const float dist = data[vert_curr].cost + curve_calc_dist_pair(nu, vert_curr, vert_other); if (data[vert_other].cost > dist) { data[vert_other].cost = dist; if (data[vert_other].vert_prev == -1) { BLI_heap_insert(heap, data[vert_other].cost, &data[vert_other].vert); } data[vert_other].vert_prev = vert_curr; } } } } } BLI_heap_free(heap, NULL); if (vert_curr == vert_dst) { i = 0; while (vert_curr != vert_src && i++ < vert_num) { if (nu->type == CU_BEZIER) { select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN); } else { select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN); } vert_curr = data[vert_curr].vert_prev; } } MEM_freeN(data); }
int seam_shortest_path(int source, int target) { Heap *heap; EdgeHash *ehash; float *cost; MEdge *med; int a, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0; TFace *tf; MFace *mf; Mesh* me = &gCloseMesh; /* mark hidden edges as done, so we don't use them */ ehash = BLI_edgehash_new(); for (a=0, mf=me->mface, tf=me->tface; a<me->totface; a++, tf++, mf++) { if (!(tf->flag & TF_HIDE)) { BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL); BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL); if (mf->v4) { BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL); BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL); } else BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL); } } for (a=0, med=me->medge; a<me->totedge; a++, med++) { if (!BLI_edgehash_haskey(ehash, med->v1, med->v2)) { med->flag |= ME_SEAM_DONE; } } BLI_edgehash_free(ehash, NULL); /* alloc */ nedges = (int*)MEM_callocN(sizeof(*nedges)*me->totvert+1, "SeamPathNEdges"); edges = (int*)MEM_mallocN(sizeof(*edges)*me->totedge*2, "SeamPathEdges"); prevedge = (int*)MEM_mallocN(sizeof(*prevedge)*me->totedge, "SeamPathPrevious"); cost = (float*)MEM_mallocN(sizeof(*cost)*me->totedge, "SeamPathCost"); /* count edges, compute adjacent edges offsets and fill adjacent edges */ for (a=0, med=me->medge; a<me->totedge; a++, med++) { nedges[med->v1+1]++; nedges[med->v2+1]++; } for (a=1; a<me->totvert; a++) { int newswap = nedges[a+1]; nedges[a+1] = nedgeswap + nedges[a]; nedgeswap = newswap; } nedges[0] = nedges[1] = 0; for (a=0, med=me->medge; a<me->totedge; a++, med++) { edges[nedges[med->v1+1]++] = a; edges[nedges[med->v2+1]++] = a; cost[a] = 1e20f; prevedge[a] = -1; } /* regular dijkstra shortest path, but over edges instead of vertices */ heap = BLI_heap_new(); BLI_heap_insert(heap, 0.0f, (void*)source); cost[source] = 0.0f; while (!BLI_heap_empty(heap)) { mednum = (int)BLI_heap_popmin(heap); med = me->medge + mednum; if (mednum == target) break; if (med->flag & ME_SEAM_DONE) continue; med->flag |= ME_SEAM_DONE; seam_add_adjacent(me, heap, mednum, med->v1, nedges, edges, prevedge, cost, target); seam_add_adjacent(me, heap, mednum, med->v2, nedges, edges, prevedge, cost, target); } MEM_freeN(nedges); MEM_freeN(edges); MEM_freeN(cost); BLI_heap_free(heap, NULL); for (a=0, med=me->medge; a<me->totedge; a++, med++) { med->flag &= ~ME_SEAM_DONE; } if (mednum != target) { MEM_freeN(prevedge); return 0; } /* follow path back to source and mark as seam */ if (mednum == target) { short allseams = 1; mednum = target; do { med = me->medge + mednum; if (!(med->flag & ME_SEAM)) { allseams = 0; break; } mednum = prevedge[mednum]; } while (mednum != source); mednum = target; do { med = me->medge + mednum; if (allseams) med->flag &= ~ME_SEAM; else med->flag |= ME_SEAM; mednum = prevedge[mednum]; } while (mednum != -1); } MEM_freeN(prevedge); return 1; }