/** * The intention is that this calculates the output of #BLI_polyfill_calc * * * \note assumes the \a coords form a boundary, * so any edges running along contiguous (wrapped) indices, * are ignored since the edges wont share 2 faces. */ void BLI_polyfill_beautify( const float (*coords)[2], const unsigned int coords_tot, unsigned int (*tris)[3], /* structs for reuse */ MemArena *arena, Heap *eheap, EdgeHash *ehash) { const unsigned int coord_last = coords_tot - 1; const unsigned int tris_tot = coords_tot - 2; /* internal edges only (between 2 tris) */ const unsigned int edges_tot = tris_tot - 1; unsigned int edges_tot_used = 0; unsigned int i; HeapNode **eheap_table; struct PolyEdge *edges = BLI_memarena_alloc(arena, edges_tot * sizeof(*edges)); BLI_assert(BLI_heap_size(eheap) == 0); BLI_assert(BLI_edgehash_size(ehash) == 0); /* first build edges */ for (i = 0; i < tris_tot; i++) { unsigned int j_prev, j_curr, j_next; j_prev = 2; j_next = 1; for (j_curr = 0; j_curr < 3; j_next = j_prev, j_prev = j_curr++) { int e_index; unsigned int e_pair[2] = { tris[i][j_prev], tris[i][j_curr], }; if (e_pair[0] > e_pair[1]) { SWAP(unsigned int, e_pair[0], e_pair[1]); e_index = 1; } else { e_index = 0; } if (!is_boundary_edge(e_pair[0], e_pair[1], coord_last)) { struct PolyEdge *e; void **val_p; if (!BLI_edgehash_ensure_p(ehash, e_pair[0], e_pair[1], &val_p)) { e = &edges[edges_tot_used++]; *val_p = e; memcpy(e->verts, e_pair, sizeof(e->verts)); #ifndef NDEBUG e->faces[!e_index] = (unsigned int)-1; #endif } else { e = *val_p; /* ensure each edge only ever has 2x users */ #ifndef NDEBUG BLI_assert(e->faces[e_index] == (unsigned int)-1); BLI_assert((e->verts[0] == e_pair[0]) && (e->verts[1] == e_pair[1])); #endif } e->faces[e_index] = i; e->faces_other_v[e_index] = j_next; } } } /* now perform iterative rotations */ eheap_table = BLI_memarena_alloc(arena, sizeof(HeapNode *) * (size_t)edges_tot); // for (i = 0; i < tris_tot; i++) { polyfill_validate_tri(tris, i, eh); } /* build heap */ for (i = 0; i < edges_tot; i++) { struct PolyEdge *e = &edges[i]; const float cost = polyedge_rotate_beauty_calc(coords, (const unsigned int (*)[3])tris, e); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } else { eheap_table[i] = NULL; } } while (BLI_heap_is_empty(eheap) == false) { struct PolyEdge *e = BLI_heap_popmin(eheap); i = (unsigned int)(e - edges); eheap_table[i] = NULL; polyedge_rotate(tris, e, ehash); /* recalculate faces connected on the heap */ polyedge_beauty_cost_update( coords, (const unsigned int (*)[3])tris, edges, e, eheap, eheap_table, ehash); } BLI_heap_clear(eheap, NULL); BLI_edgehash_clear_ex(ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE); /* MEM_freeN(eheap_table); */ /* arena */ }
static void colorband_init_from_table_rgba_resample( ColorBand *coba, const float (*array)[4], const int array_len, bool filter_samples) { BLI_assert(array_len >= 2); const float eps_2x = ((1.0f / 255.0f) + 1e-6f); struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__); int carr_len = array_len; c = carr; { const float step_size = 1.0f / (float)(array_len - 1); for (int i = 0; i < array_len; i++, c++) { copy_v4_v4(carr[i].rgba, array[i]); c->next = c + 1; c->prev = c - 1; c->pos = i * step_size; } } carr[0].prev = NULL; carr[array_len - 1].next = NULL; /* -2 to remove endpoints. */ Heap *heap = BLI_heap_new_ex(array_len - 2); c = carr; for (int i = 0; i < array_len; i++, c++) { float cost = color_sample_remove_cost(c); if (cost != -1.0f) { c->node = BLI_heap_insert(heap, cost, c); } else { c->node = NULL; } } while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) { c = BLI_heap_pop_min(heap); struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; c_prev->next = c_next; c_next->prev = c_prev; /* Clear data (not essential, avoid confusion). */ c->prev = c->next = NULL; c->node = NULL; /* Update adjacent */ for (int i = 0; i < 2; i++) { struct ColorResampleElem *c_other = i ? c_next : c_prev; if (c_other->node != NULL) { const float cost = color_sample_remove_cost(c_other); if (cost != -1.0) { BLI_heap_node_value_update(heap, c_other->node, cost); } else { BLI_heap_remove(heap, c_other->node); c_other->node = NULL; } } } carr_len -= 1; } BLI_heap_free(heap, NULL); /* First member is never removed. */ int i = 0; BLI_assert(carr_len < MAXCOLORBAND); if (filter_samples == false) { for (c = carr; c != NULL; c = c->next, i++) { copy_v4_v4(&coba->data[i].r, c->rgba); coba->data[i].pos = c->pos; coba->data[i].cur = i; } } else { for (c = carr; c != NULL; c = c->next, i++) { const int steps_prev = c->prev ? (c - c->prev) - 1 : 0; const int steps_next = c->next ? (c->next - c) - 1 : 0; if (steps_prev == 0 && steps_next == 0) { copy_v4_v4(&coba->data[i].r, c->rgba); } else { float rgba[4]; float rgba_accum = 1; copy_v4_v4(rgba, c->rgba); if (steps_prev) { const float step_size = 1.0 / (float)(steps_prev + 1); int j = steps_prev; for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) { const float step_pos = (float)j * step_size; BLI_assert(step_pos > 0.0f && step_pos < 1.0f); const float f = filter_gauss(step_pos); madd_v4_v4fl(rgba, c_other->rgba, f); rgba_accum += f; } } if (steps_next) { const float step_size = 1.0 / (float)(steps_next + 1); int j = steps_next; for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) { const float step_pos = (float)j * step_size; BLI_assert(step_pos > 0.0f && step_pos < 1.0f); const float f = filter_gauss(step_pos); madd_v4_v4fl(rgba, c_other->rgba, f); rgba_accum += f; } } mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum); } coba->data[i].pos = c->pos; coba->data[i].cur = i; } } BLI_assert(i == carr_len); coba->tot = i; coba->cur = 0; MEM_freeN(carr); }
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); }
/** * \note This function sets the edge indices to invalid values. */ void BM_mesh_beautify_fill( BMesh *bm, BMEdge **edge_array, const int edge_array_len, const short flag, const short method, const short oflag_edge, const short oflag_face) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__); BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP); int i; #ifdef DEBUG_TIME TIMEIT_START(beautify_fill); #endif eheap = BLI_heap_new_ex((uint)edge_array_len); eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__); /* build heap */ for (i = 0; i < edge_array_len; i++) { BMEdge *e = edge_array[i]; const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } else { eheap_table[i] = NULL; } BM_elem_index_set(e, i); /* set_dirty */ } bm->elem_index_dirty |= BM_EDGE; while (BLI_heap_is_empty(eheap) == false) { BMEdge *e = BLI_heap_popmin(eheap); i = BM_elem_index_get(e); eheap_table[i] = NULL; BLI_assert(BM_edge_face_count_is_equal(e, 2)); e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS); BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2)); if (LIKELY(e)) { GSet *e_state_set = edge_state_arr[i]; /* add the new state into the set so we don't move into this state again * note: we could add the previous state too but this isn't essential) * for avoiding eternal loops */ EdRotState *e_state = BLI_mempool_alloc(edge_state_pool); erot_state_current(e, e_state); if (UNLIKELY(e_state_set == NULL)) { edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */ } BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false); BLI_gset_insert(e_state_set, e_state); // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)); /* maintain the index array */ edge_array[i] = e; BM_elem_index_set(e, i); /* recalculate faces connected on the heap */ bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr, (const BMEdge **)edge_array, edge_array_len, flag, method); /* update flags */ if (oflag_edge) { BMO_edge_flag_enable(bm, e, oflag_edge); } if (oflag_face) { BMO_face_flag_enable(bm, e->l->f, oflag_face); BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face); } } } BLI_heap_free(eheap, NULL); MEM_freeN(eheap_table); for (i = 0; i < edge_array_len; i++) { if (edge_state_arr[i]) { BLI_gset_free(edge_state_arr[i], NULL); } } MEM_freeN(edge_state_arr); BLI_mempool_destroy(edge_state_pool); #ifdef DEBUG_TIME TIMEIT_END(beautify_fill); #endif }