From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- source/blender/blenkernel/intern/mesh_remap.c | 4308 +++++++++++++------------ 1 file changed, 2270 insertions(+), 2038 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh_remap.c') diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 7219332774a..b43339bf73f 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -42,7 +42,7 @@ #include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" -#include "BKE_mesh_remap.h" /* own include */ +#include "BKE_mesh_remap.h" /* own include */ #include "BKE_mesh_runtime.h" #include "BLI_strict_flags.h" @@ -53,55 +53,63 @@ static CLG_LogRef LOG = {"bke.mesh"}; /** \name Some generic helpers. * \{ */ -static bool mesh_remap_bvhtree_query_nearest( - BVHTreeFromMesh *treedata, BVHTreeNearest *nearest, - const float co[3], const float max_dist_sq, float *r_hit_dist) +static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata, + BVHTreeNearest *nearest, + const float co[3], + const float max_dist_sq, + float *r_hit_dist) { - /* Use local proximity heuristics (to reduce the nearest search). */ - if (nearest->index != -1) { - nearest->dist_sq = min_ff(len_squared_v3v3(co, nearest->co), max_dist_sq); - } - else { - nearest->dist_sq = max_dist_sq; - } - /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */ - BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata); - - if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) { - *r_hit_dist = sqrtf(nearest->dist_sq); - return true; - } - else { - return false; - } + /* Use local proximity heuristics (to reduce the nearest search). */ + if (nearest->index != -1) { + nearest->dist_sq = min_ff(len_squared_v3v3(co, nearest->co), max_dist_sq); + } + else { + nearest->dist_sq = max_dist_sq; + } + /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */ + BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata); + + if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) { + *r_hit_dist = sqrtf(nearest->dist_sq); + return true; + } + else { + return false; + } } -static bool mesh_remap_bvhtree_query_raycast( - BVHTreeFromMesh *treedata, BVHTreeRayHit *rayhit, - const float co[3], const float no[3], const float radius, const float max_dist, float *r_hit_dist) +static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata, + BVHTreeRayHit *rayhit, + const float co[3], + const float no[3], + const float radius, + const float max_dist, + float *r_hit_dist) { - BVHTreeRayHit rayhit_tmp; - float inv_no[3]; - - rayhit->index = -1; - rayhit->dist = max_dist; - BLI_bvhtree_ray_cast(treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata); - - /* Also cast in the other direction! */ - rayhit_tmp = *rayhit; - negate_v3_v3(inv_no, no); - BLI_bvhtree_ray_cast(treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata); - if (rayhit_tmp.dist < rayhit->dist) { - *rayhit = rayhit_tmp; - } - - if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) { - *r_hit_dist = rayhit->dist; - return true; - } - else { - return false; - } + BVHTreeRayHit rayhit_tmp; + float inv_no[3]; + + rayhit->index = -1; + rayhit->dist = max_dist; + BLI_bvhtree_ray_cast( + treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata); + + /* Also cast in the other direction! */ + rayhit_tmp = *rayhit; + negate_v3_v3(inv_no, no); + BLI_bvhtree_ray_cast( + treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata); + if (rayhit_tmp.dist < rayhit->dist) { + *rayhit = rayhit_tmp; + } + + if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) { + *r_hit_dist = rayhit->dist; + return true; + } + else { + return false; + } } /** \} */ @@ -120,43 +128,45 @@ static bool mesh_remap_bvhtree_query_raycast( * In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight * in final result, which allows to reduce influence of a few high differences, in favor of a global good matching. */ -float BKE_mesh_remap_calc_difference_from_mesh( - const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src) +float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform, + const MVert *verts_dst, + const int numverts_dst, + Mesh *me_src) { - BVHTreeFromMesh treedata = {NULL}; - BVHTreeNearest nearest = {0}; - float hit_dist; + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + float hit_dist; - float result = 0.0f; - int i; + float result = 0.0f; + int i; - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); - nearest.index = -1; + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); + nearest.index = -1; - for (i = 0; i < numverts_dst; i++) { - float tmp_co[3]; + for (i = 0; i < numverts_dst; i++) { + float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[i].co); + copy_v3_v3(tmp_co, verts_dst[i].co); - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) { - result += 1.0f / (hit_dist + 1.0f); - } - else { - /* No source for this dest vertex! */ - result += 1e-18f; - } - } + if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) { + result += 1.0f / (hit_dist + 1.0f); + } + else { + /* No source for this dest vertex! */ + result += 1e-18f; + } + } - result = ((float)numverts_dst / result) - 1.0f; + result = ((float)numverts_dst / result) - 1.0f; -// printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result); + // printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result); - return result; + return result; } /* This helper computes the eigen values & vectors for covariance matrix of all given vertices coordinates. @@ -169,133 +179,139 @@ float BKE_mesh_remap_calc_difference_from_mesh( * three identical ones, etc.), since you cannot really define all axes in those cases. We default to dummy * generated orthogonal vectors in this case, instead of using eigen vectors. */ -static void mesh_calc_eigen_matrix( - const MVert *verts, const float (*vcos)[3], const int numverts, float r_mat[4][4]) +static void mesh_calc_eigen_matrix(const MVert *verts, + const float (*vcos)[3], + const int numverts, + float r_mat[4][4]) { - float center[3], covmat[3][3]; - float eigen_val[3], eigen_vec[3][3]; - float (*cos)[3] = NULL; - - bool eigen_success; - int i; - - if (verts) { - const MVert *mv; - float (*co)[3]; - - cos = MEM_mallocN(sizeof(*cos) * (size_t)numverts, __func__); - for (i = 0, co = cos, mv = verts; i < numverts; i++, co++, mv++) { - copy_v3_v3(*co, mv->co); - } - /* TODO(sergey): For until we officially drop all compilers which - * doesn't handle casting correct we use workaround to avoid explicit - * cast here. - */ - vcos = (void *)cos; - } - unit_m4(r_mat); - - /* Note: here we apply sample correction to covariance matrix, since we consider the vertices as a sample - * of the whole 'surface' population of our mesh... */ - BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center); - - if (cos) { - MEM_freeN(cos); - } - - eigen_success = BLI_eigen_solve_selfadjoint_m3((const float (*)[3])covmat, eigen_val, eigen_vec); - BLI_assert(eigen_success); - UNUSED_VARS_NDEBUG(eigen_success); - - /* Special handling of cases where some eigen values are (nearly) identical. */ - if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) { - if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) { - /* No preferred direction, that set of vertices has a spherical average, - * so we simply returned scaled/translated identity matrix (with no rotation). */ - unit_m3(eigen_vec); - } - else { - /* Ellipsoid defined by eigen values/vectors has a spherical section, - * we can only define one axis from eigen_vec[2] (two others computed eigen vecs - * are not so nice for us here, they tend to 'randomly' rotate around valid one). - * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */ - ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]); - } - } - else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) { - /* Same as above, but with eigen_vec[1] as valid axis. */ - ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]); - } - else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) { - /* Same as above, but with eigen_vec[0] as valid axis. */ - ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]); - } - - for (i = 0; i < 3; i++) { - float evi = eigen_val[i]; - - /* Protect against 1D/2D degenerated cases! */ - /* Note: not sure why we need square root of eigen values here (which are equivalent to singular values, - * as far as I have understood), but it seems to heavily reduce (if not completely nullify) - * the error due to non-uniform scalings... */ - evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi); - mul_v3_fl(eigen_vec[i], evi); - } - - copy_m4_m3(r_mat, eigen_vec); - copy_v3_v3(r_mat[3], center); + float center[3], covmat[3][3]; + float eigen_val[3], eigen_vec[3][3]; + float(*cos)[3] = NULL; + + bool eigen_success; + int i; + + if (verts) { + const MVert *mv; + float(*co)[3]; + + cos = MEM_mallocN(sizeof(*cos) * (size_t)numverts, __func__); + for (i = 0, co = cos, mv = verts; i < numverts; i++, co++, mv++) { + copy_v3_v3(*co, mv->co); + } + /* TODO(sergey): For until we officially drop all compilers which + * doesn't handle casting correct we use workaround to avoid explicit + * cast here. + */ + vcos = (void *)cos; + } + unit_m4(r_mat); + + /* Note: here we apply sample correction to covariance matrix, since we consider the vertices as a sample + * of the whole 'surface' population of our mesh... */ + BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center); + + if (cos) { + MEM_freeN(cos); + } + + eigen_success = BLI_eigen_solve_selfadjoint_m3((const float(*)[3])covmat, eigen_val, eigen_vec); + BLI_assert(eigen_success); + UNUSED_VARS_NDEBUG(eigen_success); + + /* Special handling of cases where some eigen values are (nearly) identical. */ + if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) { + if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) { + /* No preferred direction, that set of vertices has a spherical average, + * so we simply returned scaled/translated identity matrix (with no rotation). */ + unit_m3(eigen_vec); + } + else { + /* Ellipsoid defined by eigen values/vectors has a spherical section, + * we can only define one axis from eigen_vec[2] (two others computed eigen vecs + * are not so nice for us here, they tend to 'randomly' rotate around valid one). + * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */ + ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]); + } + } + else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) { + /* Same as above, but with eigen_vec[1] as valid axis. */ + ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]); + } + else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) { + /* Same as above, but with eigen_vec[0] as valid axis. */ + ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]); + } + + for (i = 0; i < 3; i++) { + float evi = eigen_val[i]; + + /* Protect against 1D/2D degenerated cases! */ + /* Note: not sure why we need square root of eigen values here (which are equivalent to singular values, + * as far as I have understood), but it seems to heavily reduce (if not completely nullify) + * the error due to non-uniform scalings... */ + evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi); + mul_v3_fl(eigen_vec[i], evi); + } + + copy_m4_m3(r_mat, eigen_vec); + copy_v3_v3(r_mat[3], center); } /** * Set r_space_transform so that best bbox of dst matches best bbox of src. */ -void BKE_mesh_remap_find_best_match_from_mesh( - const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform) +void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst, + const int numverts_dst, + Mesh *me_src, + SpaceTransform *r_space_transform) { - /* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */ - const float mirrors[][3] = { - {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */ - { 1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */ - { 1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */ - { 1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */ - {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */ - { 1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */ - { 1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */ - {0.0f, 0.0f, 0.0f}, - }; - const float (*mirr)[3]; - - float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4]; - float best_match = FLT_MAX, match; - - const int numverts_src = me_src->totvert; - float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - - mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src); - mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst); - - BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); - match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src); - best_match = match; - copy_m4_m4(best_mat_dst, mat_dst); - - /* And now, we have to check the other sixth possible mirrored versions... */ - for (mirr = mirrors; (*mirr)[0]; mirr++) { - mul_v3_fl(mat_dst[0], (*mirr)[0]); - mul_v3_fl(mat_dst[1], (*mirr)[1]); - mul_v3_fl(mat_dst[2], (*mirr)[2]); - - BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); - match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src); - if (match < best_match) { - best_match = match; - copy_m4_m4(best_mat_dst, mat_dst); - } - } - - BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src); - - MEM_freeN(vcos_src); + /* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */ + const float mirrors[][3] = { + {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */ + {1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */ + {1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */ + {1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */ + {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */ + {1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */ + {1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */ + {0.0f, 0.0f, 0.0f}, + }; + const float(*mirr)[3]; + + float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4]; + float best_match = FLT_MAX, match; + + const int numverts_src = me_src->totvert; + float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); + + mesh_calc_eigen_matrix(NULL, (const float(*)[3])vcos_src, numverts_src, mat_src); + mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst); + + BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); + match = BKE_mesh_remap_calc_difference_from_mesh( + r_space_transform, verts_dst, numverts_dst, me_src); + best_match = match; + copy_m4_m4(best_mat_dst, mat_dst); + + /* And now, we have to check the other sixth possible mirrored versions... */ + for (mirr = mirrors; (*mirr)[0]; mirr++) { + mul_v3_fl(mat_dst[0], (*mirr)[0]); + mul_v3_fl(mat_dst[1], (*mirr)[1]); + mul_v3_fl(mat_dst[2], (*mirr)[2]); + + BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); + match = BKE_mesh_remap_calc_difference_from_mesh( + r_space_transform, verts_dst, numverts_dst, me_src); + if (match < best_match) { + best_match = match; + copy_m4_m4(best_mat_dst, mat_dst); + } + } + + BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src); + + MEM_freeN(vcos_src); } /** \} */ @@ -303,121 +319,139 @@ void BKE_mesh_remap_find_best_match_from_mesh( /** \name Mesh to mesh mapping * \{ */ -void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes( - const int UNUSED(vert_mode), const int UNUSED(edge_mode), const int loop_mode, const int UNUSED(poly_mode), - CustomData_MeshMasks *cddata_mask) +void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(vert_mode), + const int UNUSED(edge_mode), + const int loop_mode, + const int UNUSED(poly_mode), + CustomData_MeshMasks *cddata_mask) { - /* vert, edge and poly mapping modes never need extra cddata from source object. */ - const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL); - const bool need_pnors_src = need_lnors_src || ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL)); - - if (need_lnors_src) { - cddata_mask->lmask |= CD_MASK_NORMAL; - } - if (need_pnors_src) { - cddata_mask->pmask |= CD_MASK_NORMAL; - } + /* vert, edge and poly mapping modes never need extra cddata from source object. */ + const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL); + const bool need_pnors_src = need_lnors_src || + ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL)); + + if (need_lnors_src) { + cddata_mask->lmask |= CD_MASK_NORMAL; + } + if (need_pnors_src) { + cddata_mask->pmask |= CD_MASK_NORMAL; + } } void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num) { - MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - BKE_mesh_remap_free(map); + BKE_mesh_remap_free(map); - map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num); - map->items_num = items_num; + map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num); + map->items_num = items_num; - map->mem = mem; + map->mem = mem; } void BKE_mesh_remap_free(MeshPairRemap *map) { - if (map->mem) { - BLI_memarena_free((MemArena *)map->mem); - } + if (map->mem) { + BLI_memarena_free((MemArena *)map->mem); + } - map->items_num = 0; - map->items = NULL; - map->mem = NULL; + map->items_num = 0; + map->items = NULL; + map->mem = NULL; } -static void mesh_remap_item_define( - MeshPairRemap *map, const int index, const float UNUSED(hit_dist), const int island, - const int sources_num, const int *indices_src, const float *weights_src) +static void mesh_remap_item_define(MeshPairRemap *map, + const int index, + const float UNUSED(hit_dist), + const int island, + const int sources_num, + const int *indices_src, + const float *weights_src) { - MeshPairRemapItem *mapit = &map->items[index]; - MemArena *mem = map->mem; - - if (sources_num) { - mapit->sources_num = sources_num; - mapit->indices_src = BLI_memarena_alloc(mem, sizeof(*mapit->indices_src) * (size_t)sources_num); - memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num); - mapit->weights_src = BLI_memarena_alloc(mem, sizeof(*mapit->weights_src) * (size_t)sources_num); - memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num); - } - else { - mapit->sources_num = 0; - mapit->indices_src = NULL; - mapit->weights_src = NULL; - } - /* UNUSED */ - // mapit->hit_dist = hit_dist; - mapit->island = island; + MeshPairRemapItem *mapit = &map->items[index]; + MemArena *mem = map->mem; + + if (sources_num) { + mapit->sources_num = sources_num; + mapit->indices_src = BLI_memarena_alloc(mem, + sizeof(*mapit->indices_src) * (size_t)sources_num); + memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num); + mapit->weights_src = BLI_memarena_alloc(mem, + sizeof(*mapit->weights_src) * (size_t)sources_num); + memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num); + } + else { + mapit->sources_num = 0; + mapit->indices_src = NULL; + mapit->weights_src = NULL; + } + /* UNUSED */ + // mapit->hit_dist = hit_dist; + mapit->island = island; } void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index) { - mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL); + mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL); } -static int mesh_remap_interp_poly_data_get( - const MPoly *mp, MLoop *mloops, const float (*vcos_src)[3], const float point[3], - size_t *buff_size, float (**vcos)[3], const bool use_loops, int **indices, float **weights, - const bool do_weights, int *r_closest_index) +static int mesh_remap_interp_poly_data_get(const MPoly *mp, + MLoop *mloops, + const float (*vcos_src)[3], + const float point[3], + size_t *buff_size, + float (**vcos)[3], + const bool use_loops, + int **indices, + float **weights, + const bool do_weights, + int *r_closest_index) { - MLoop *ml; - float (*vco)[3]; - float ref_dist_sq = FLT_MAX; - int *index; - const int sources_num = mp->totloop; - int i; - - if ((size_t)sources_num > *buff_size) { - *buff_size = (size_t)sources_num; - *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size); - *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size); - if (do_weights) { - *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size); - } - } - - for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num; i++, ml++, vco++, index++) { - *index = use_loops ? (int)mp->loopstart + i : (int)ml->v; - copy_v3_v3(*vco, vcos_src[ml->v]); - if (r_closest_index) { - /* Find closest vert/loop in this case. */ - const float dist_sq = len_squared_v3v3(point, *vco); - if (dist_sq < ref_dist_sq) { - ref_dist_sq = dist_sq; - *r_closest_index = *index; - } - } - } - - if (do_weights) { - interp_weights_poly_v3(*weights, *vcos, sources_num, point); - } - - return sources_num; + MLoop *ml; + float(*vco)[3]; + float ref_dist_sq = FLT_MAX; + int *index; + const int sources_num = mp->totloop; + int i; + + if ((size_t)sources_num > *buff_size) { + *buff_size = (size_t)sources_num; + *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size); + *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size); + if (do_weights) { + *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size); + } + } + + for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num; + i++, ml++, vco++, index++) { + *index = use_loops ? (int)mp->loopstart + i : (int)ml->v; + copy_v3_v3(*vco, vcos_src[ml->v]); + if (r_closest_index) { + /* Find closest vert/loop in this case. */ + const float dist_sq = len_squared_v3v3(point, *vco); + if (dist_sq < ref_dist_sq) { + ref_dist_sq = dist_sq; + *r_closest_index = *index; + } + } + } + + if (do_weights) { + interp_weights_poly_v3(*weights, *vcos, sources_num, point); + } + + return sources_num; } /* Little helper when dealing with source islands */ typedef struct IslandResult { - float factor; /* A factor, based on which best island for a given set of elements will be selected. */ - int index_src; /* Index of the source. */ - float hit_dist; /* The actual hit distance. */ - float hit_point[3]; /* The hit point, if relevant. */ + float + factor; /* A factor, based on which best island for a given set of elements will be selected. */ + int index_src; /* Index of the source. */ + float hit_dist; /* The actual hit distance. */ + float hit_point[3]; /* The hit point, if relevant. */ } IslandResult; /* Note about all bvh/raycasting stuff below: @@ -444,644 +478,722 @@ typedef struct IslandResult { /* Will be enough in 99% of cases. */ #define MREMAP_DEFAULT_BUFSIZE 32 -void BKE_mesh_remap_calc_verts_from_mesh( - const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, - const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src, - MeshPairRemap *r_map) +void BKE_mesh_remap_calc_verts_from_mesh(const int mode, + const SpaceTransform *space_transform, + const float max_dist, + const float ray_radius, + const MVert *verts_dst, + const int numverts_dst, + const bool UNUSED(dirty_nors_dst), + Mesh *me_src, + MeshPairRemap *r_map) { - const float full_weight = 1.0f; - const float max_dist_sq = max_dist * max_dist; - int i; - - BLI_assert(mode & MREMAP_MODE_VERT); - - BKE_mesh_remap_init(r_map, numverts_dst); - - if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numverts_dst == me_src->totvert); - for (i = 0; i < numverts_dst; i++) { - mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); - } - } - else { - BVHTreeFromMesh treedata = {NULL}; - BVHTreeNearest nearest = {0}; - BVHTreeRayHit rayhit = {0}; - float hit_dist; - float tmp_co[3], tmp_no[3]; - - if (mode == MREMAP_MODE_VERT_NEAREST) { - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); - nearest.index = -1; - - for (i = 0; i < numverts_dst; i++) { - copy_v3_v3(tmp_co, verts_dst[i].co); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); - } - else { - /* No source for this dest vertex! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) { - MEdge *edges_src = me_src->medge; - float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); - nearest.index = -1; - - for (i = 0; i < numverts_dst; i++) { - copy_v3_v3(tmp_co, verts_dst[i].co); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - MEdge *me = &edges_src[nearest.index]; - const float *v1cos = vcos_src[me->v1]; - const float *v2cos = vcos_src[me->v2]; - - if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) { - const float dist_v1 = len_squared_v3v3(tmp_co, v1cos); - const float dist_v2 = len_squared_v3v3(tmp_co, v2cos); - const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1); - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); - } - else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) { - int indices[2]; - float weights[2]; - - indices[0] = (int)me->v1; - indices[1] = (int)me->v2; - - /* Weight is inverse of point factor here... */ - weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos); - CLAMP(weights[0], 0.0f, 1.0f); - weights[1] = 1.0f - weights[0]; - - mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights); - } - } - else { - /* No source for this dest vertex! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - - MEM_freeN(vcos_src); - } - else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST, - MREMAP_MODE_VERT_POLYINTERP_VNORPROJ)) - { - MPoly *polys_src = me_src->mpoly; - MLoop *loops_src = me_src->mloop; - float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - - size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE; - float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__); - int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__); - float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__); - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); - - if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) { - for (i = 0; i < numverts_dst; i++) { - copy_v3_v3(tmp_co, verts_dst[i].co); - normal_short_to_float_v3(tmp_no, verts_dst[i].no); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - BLI_space_transform_apply_normal(space_transform, tmp_no); - } - - if (mesh_remap_bvhtree_query_raycast( - &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) - { - const MLoopTri *lt = &treedata.looptri[rayhit.index]; - MPoly *mp_src = &polys_src[lt->poly]; - const int sources_num = mesh_remap_interp_poly_data_get( - mp_src, loops_src, (const float (*)[3])vcos_src, rayhit.co, - &tmp_buff_size, &vcos, false, &indices, &weights, true, NULL); - - mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); - } - else { - /* No source for this dest vertex! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - else { - nearest.index = -1; - - for (i = 0; i < numverts_dst; i++) { - copy_v3_v3(tmp_co, verts_dst[i].co); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - const MLoopTri *lt = &treedata.looptri[nearest.index]; - MPoly *mp = &polys_src[lt->poly]; - - if (mode == MREMAP_MODE_VERT_POLY_NEAREST) { - int index; - mesh_remap_interp_poly_data_get( - mp, loops_src, (const float (*)[3])vcos_src, nearest.co, - &tmp_buff_size, &vcos, false, &indices, &weights, false, - &index); - - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); - } - else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) { - const int sources_num = mesh_remap_interp_poly_data_get( - mp, loops_src, (const float (*)[3])vcos_src, nearest.co, - &tmp_buff_size, &vcos, false, &indices, &weights, true, - NULL); - - mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); - } - } - else { - /* No source for this dest vertex! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - - MEM_freeN(vcos_src); - MEM_freeN(vcos); - MEM_freeN(indices); - MEM_freeN(weights); - } - else { - CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode); - memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst); - } - - free_bvhtree_from_mesh(&treedata); - } + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + int i; + + BLI_assert(mode & MREMAP_MODE_VERT); + + BKE_mesh_remap_init(r_map, numverts_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numverts_dst == me_src->totvert); + for (i = 0; i < numverts_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + float tmp_co[3], tmp_no[3]; + + if (mode == MREMAP_MODE_VERT_NEAREST) { + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + copy_v3_v3(tmp_co, verts_dst[i].co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) { + MEdge *edges_src = me_src->medge; + float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + copy_v3_v3(tmp_co, verts_dst[i].co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + MEdge *me = &edges_src[nearest.index]; + const float *v1cos = vcos_src[me->v1]; + const float *v2cos = vcos_src[me->v2]; + + if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) { + const float dist_v1 = len_squared_v3v3(tmp_co, v1cos); + const float dist_v2 = len_squared_v3v3(tmp_co, v2cos); + const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1); + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); + } + else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) { + int indices[2]; + float weights[2]; + + indices[0] = (int)me->v1; + indices[1] = (int)me->v2; + + /* Weight is inverse of point factor here... */ + weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos); + CLAMP(weights[0], 0.0f, 1.0f); + weights[1] = 1.0f - weights[0]; + + mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights); + } + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + } + else if (ELEM(mode, + MREMAP_MODE_VERT_POLY_NEAREST, + MREMAP_MODE_VERT_POLYINTERP_NEAREST, + MREMAP_MODE_VERT_POLYINTERP_VNORPROJ)) { + MPoly *polys_src = me_src->mpoly; + MLoop *loops_src = me_src->mloop; + float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); + + size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE; + float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__); + int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__); + float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__); + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); + + if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) { + for (i = 0; i < numverts_dst; i++) { + copy_v3_v3(tmp_co, verts_dst[i].co); + normal_short_to_float_v3(tmp_no, verts_dst[i].no); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[rayhit.index]; + MPoly *mp_src = &polys_src[lt->poly]; + const int sources_num = mesh_remap_interp_poly_data_get(mp_src, + loops_src, + (const float(*)[3])vcos_src, + rayhit.co, + &tmp_buff_size, + &vcos, + false, + &indices, + &weights, + true, + NULL); + + mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else { + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + copy_v3_v3(tmp_co, verts_dst[i].co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[nearest.index]; + MPoly *mp = &polys_src[lt->poly]; + + if (mode == MREMAP_MODE_VERT_POLY_NEAREST) { + int index; + mesh_remap_interp_poly_data_get(mp, + loops_src, + (const float(*)[3])vcos_src, + nearest.co, + &tmp_buff_size, + &vcos, + false, + &indices, + &weights, + false, + &index); + + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); + } + else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) { + const int sources_num = mesh_remap_interp_poly_data_get(mp, + loops_src, + (const float(*)[3])vcos_src, + nearest.co, + &tmp_buff_size, + &vcos, + false, + &indices, + &weights, + true, + NULL); + + mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); + } + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + + MEM_freeN(vcos_src); + MEM_freeN(vcos); + MEM_freeN(indices); + MEM_freeN(weights); + } + else { + CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst); + } + + free_bvhtree_from_mesh(&treedata); + } } -void BKE_mesh_remap_calc_edges_from_mesh( - const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, - const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst, - const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map) +void BKE_mesh_remap_calc_edges_from_mesh(const int mode, + const SpaceTransform *space_transform, + const float max_dist, + const float ray_radius, + const MVert *verts_dst, + const int numverts_dst, + const MEdge *edges_dst, + const int numedges_dst, + const bool UNUSED(dirty_nors_dst), + Mesh *me_src, + MeshPairRemap *r_map) { - const float full_weight = 1.0f; - const float max_dist_sq = max_dist * max_dist; - int i; - - BLI_assert(mode & MREMAP_MODE_EDGE); - - BKE_mesh_remap_init(r_map, numedges_dst); - - if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numedges_dst == me_src->totedge); - for (i = 0; i < numedges_dst; i++) { - mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); - } - } - else { - BVHTreeFromMesh treedata = {NULL}; - BVHTreeNearest nearest = {0}; - BVHTreeRayHit rayhit = {0}; - float hit_dist; - float tmp_co[3], tmp_no[3]; - - if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) { - const int num_verts_src = me_src->totvert; - const int num_edges_src = me_src->totedge; - MEdge *edges_src = me_src->medge; - float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - - MeshElemMap *vert_to_edge_src_map; - int *vert_to_edge_src_map_mem; - - struct { - float hit_dist; - int index; - } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst, __func__); - - for (i = 0; i < numverts_dst; i++) { - v_dst_to_src_map[i].hit_dist = -1.0f; - } - - BKE_mesh_vert_edge_map_create( - &vert_to_edge_src_map, &vert_to_edge_src_map_mem, - edges_src, num_verts_src, num_edges_src); - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); - nearest.index = -1; - - for (i = 0; i < numedges_dst; i++) { - const MEdge *e_dst = &edges_dst[i]; - float best_totdist = FLT_MAX; - int best_eidx_src = -1; - int j = 2; - - while (j--) { - const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; - - /* Compute closest verts only once! */ - if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) { - copy_v3_v3(tmp_co, verts_dst[vidx_dst].co); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - v_dst_to_src_map[vidx_dst].hit_dist = hit_dist; - v_dst_to_src_map[vidx_dst].index = nearest.index; - } - else { - /* No source for this dest vert! */ - v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX; - } - } - } - - /* Now, check all source edges of closest sources vertices, and select the one giving the smallest - * total verts-to-verts distance. */ - for (j = 2; j--;) { - const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; - const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist; - const int vidx_src = v_dst_to_src_map[vidx_dst].index; - int *eidx_src, k; - - if (vidx_src < 0) { - continue; - } - - eidx_src = vert_to_edge_src_map[vidx_src].indices; - k = vert_to_edge_src_map[vidx_src].count; - - for (; k--; eidx_src++) { - MEdge *e_src = &edges_src[*eidx_src]; - const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)]; - const float *other_co_dst = verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co; - const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst); - - if (totdist < best_totdist) { - best_totdist = totdist; - best_eidx_src = *eidx_src; - } - } - } - - if (best_eidx_src >= 0) { - const float *co1_src = vcos_src[edges_src[best_eidx_src].v1]; - const float *co2_src = vcos_src[edges_src[best_eidx_src].v2]; - const float *co1_dst = verts_dst[e_dst->v1].co; - const float *co2_dst = verts_dst[e_dst->v2].co; - float co_src[3], co_dst[3]; - - /* TODO: would need an isect_seg_seg_v3(), actually! */ - const int isect_type = isect_line_line_v3(co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst); - if (isect_type != 0) { - const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src); - const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst); - if (fac_src < 0.0f) { - copy_v3_v3(co_src, co1_src); - } - else if (fac_src > 1.0f) { - copy_v3_v3(co_src, co2_src); - } - if (fac_dst < 0.0f) { - copy_v3_v3(co_dst, co1_dst); - } - else if (fac_dst > 1.0f) { - copy_v3_v3(co_dst, co2_dst); - } - } - hit_dist = len_v3v3(co_dst, co_src); - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); - } - else { - /* No source for this dest edge! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - - MEM_freeN(vcos_src); - MEM_freeN(v_dst_to_src_map); - MEM_freeN(vert_to_edge_src_map); - MEM_freeN(vert_to_edge_src_map_mem); - } - else if (mode == MREMAP_MODE_EDGE_NEAREST) { - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); - nearest.index = -1; - - for (i = 0; i < numedges_dst; i++) { - interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); - } - else { - /* No source for this dest edge! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) { - MEdge *edges_src = me_src->medge; - MPoly *polys_src = me_src->mpoly; - MLoop *loops_src = me_src->mloop; - float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); - - for (i = 0; i < numedges_dst; i++) { - interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - const MLoopTri *lt = &treedata.looptri[nearest.index]; - MPoly *mp_src = &polys_src[lt->poly]; - MLoop *ml_src = &loops_src[mp_src->loopstart]; - int nloops = mp_src->totloop; - float best_dist_sq = FLT_MAX; - int best_eidx_src = -1; - - for (; nloops--; ml_src++) { - MEdge *med_src = &edges_src[ml_src->e]; - float *co1_src = vcos_src[med_src->v1]; - float *co2_src = vcos_src[med_src->v2]; - float co_src[3]; - float dist_sq; - - interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f); - dist_sq = len_squared_v3v3(tmp_co, co_src); - if (dist_sq < best_dist_sq) { - best_dist_sq = dist_sq; - best_eidx_src = (int)ml_src->e; - } - } - if (best_eidx_src >= 0) { - mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); - } - } - else { - /* No source for this dest edge! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - - MEM_freeN(vcos_src); - } - else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) { - const int num_rays_min = 5, num_rays_max = 100; - const int numedges_src = me_src->totedge; - - /* Subtleness - this one we can allocate only max number of cast rays per edges! */ - int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__); - /* Here it's simpler to just allocate for all edges :/ */ - float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__); - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); - - for (i = 0; i < numedges_dst; i++) { - /* For each dst edge, we sample some rays from it (interpolated from its vertices) - * and use their hits to interpolate from source edges. */ - const MEdge *me = &edges_dst[i]; - float v1_co[3], v2_co[3]; - float v1_no[3], v2_no[3]; - - int grid_size; - float edge_dst_len; - float grid_step; - - float totweights = 0.0f; - float hit_dist_accum = 0.0f; - int sources_num = 0; - int j; - - copy_v3_v3(v1_co, verts_dst[me->v1].co); - copy_v3_v3(v2_co, verts_dst[me->v2].co); - - normal_short_to_float_v3(v1_no, verts_dst[me->v1].no); - normal_short_to_float_v3(v2_no, verts_dst[me->v2].no); - - /* We do our transform here, allows to interpolate from normals already in src space. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, v1_co); - BLI_space_transform_apply(space_transform, v2_co); - BLI_space_transform_apply_normal(space_transform, v1_no); - BLI_space_transform_apply_normal(space_transform, v2_no); - } - - copy_vn_fl(weights, (int)numedges_src, 0.0f); - - /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), - * with lower/upper bounds. */ - edge_dst_len = len_v3v3(v1_co, v2_co); - - grid_size = (int)((edge_dst_len / ray_radius) + 0.5f); - CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */ - - grid_step = 1.0f / (float)grid_size; /* Not actual distance here, rather an interp fac... */ - - /* And now we can cast all our rays, and see what we get! */ - for (j = 0; j < grid_size; j++) { - const float fac = grid_step * (float)j; - - int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; - float w = 1.0f; - - interp_v3_v3v3(tmp_co, v1_co, v2_co, fac); - interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac); - - while (n--) { - if (mesh_remap_bvhtree_query_raycast( - &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) - { - weights[rayhit.index] += w; - totweights += w; - hit_dist_accum += hit_dist; - break; - } - /* Next iteration will get bigger radius but smaller weight! */ - w /= MREMAP_RAYCAST_APPROXIMATE_FAC; - } - } - /* A sampling is valid (as in, its result can be considered as valid sources) only if at least - * half of the rays found a source! */ - if (totweights > ((float)grid_size / 2.0f)) { - for (j = 0; j < (int)numedges_src; j++) { - if (!weights[j]) { - continue; - } - /* Note: sources_num is always <= j! */ - weights[sources_num] = weights[j] / totweights; - indices[sources_num] = j; - sources_num++; - } - mesh_remap_item_define( - r_map, i, hit_dist_accum / totweights, 0, - sources_num, indices, weights); - } - else { - /* No source for this dest edge! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - - MEM_freeN(indices); - MEM_freeN(weights); - } - else { - CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode); - memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst); - } - - free_bvhtree_from_mesh(&treedata); - } + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + int i; + + BLI_assert(mode & MREMAP_MODE_EDGE); + + BKE_mesh_remap_init(r_map, numedges_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numedges_dst == me_src->totedge); + for (i = 0; i < numedges_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + float tmp_co[3], tmp_no[3]; + + if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) { + const int num_verts_src = me_src->totvert; + const int num_edges_src = me_src->totedge; + MEdge *edges_src = me_src->medge; + float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); + + MeshElemMap *vert_to_edge_src_map; + int *vert_to_edge_src_map_mem; + + struct { + float hit_dist; + int index; + } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst, + __func__); + + for (i = 0; i < numverts_dst; i++) { + v_dst_to_src_map[i].hit_dist = -1.0f; + } + + BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map, + &vert_to_edge_src_map_mem, + edges_src, + num_verts_src, + num_edges_src); + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); + nearest.index = -1; + + for (i = 0; i < numedges_dst; i++) { + const MEdge *e_dst = &edges_dst[i]; + float best_totdist = FLT_MAX; + int best_eidx_src = -1; + int j = 2; + + while (j--) { + const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; + + /* Compute closest verts only once! */ + if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) { + copy_v3_v3(tmp_co, verts_dst[vidx_dst].co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + v_dst_to_src_map[vidx_dst].hit_dist = hit_dist; + v_dst_to_src_map[vidx_dst].index = nearest.index; + } + else { + /* No source for this dest vert! */ + v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX; + } + } + } + + /* Now, check all source edges of closest sources vertices, and select the one giving the smallest + * total verts-to-verts distance. */ + for (j = 2; j--;) { + const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; + const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist; + const int vidx_src = v_dst_to_src_map[vidx_dst].index; + int *eidx_src, k; + + if (vidx_src < 0) { + continue; + } + + eidx_src = vert_to_edge_src_map[vidx_src].indices; + k = vert_to_edge_src_map[vidx_src].count; + + for (; k--; eidx_src++) { + MEdge *e_src = &edges_src[*eidx_src]; + const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)]; + const float *other_co_dst = + verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co; + const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst); + + if (totdist < best_totdist) { + best_totdist = totdist; + best_eidx_src = *eidx_src; + } + } + } + + if (best_eidx_src >= 0) { + const float *co1_src = vcos_src[edges_src[best_eidx_src].v1]; + const float *co2_src = vcos_src[edges_src[best_eidx_src].v2]; + const float *co1_dst = verts_dst[e_dst->v1].co; + const float *co2_dst = verts_dst[e_dst->v2].co; + float co_src[3], co_dst[3]; + + /* TODO: would need an isect_seg_seg_v3(), actually! */ + const int isect_type = isect_line_line_v3( + co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst); + if (isect_type != 0) { + const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src); + const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst); + if (fac_src < 0.0f) { + copy_v3_v3(co_src, co1_src); + } + else if (fac_src > 1.0f) { + copy_v3_v3(co_src, co2_src); + } + if (fac_dst < 0.0f) { + copy_v3_v3(co_dst, co1_dst); + } + else if (fac_dst > 1.0f) { + copy_v3_v3(co_dst, co2_dst); + } + } + hit_dist = len_v3v3(co_dst, co_src); + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + MEM_freeN(v_dst_to_src_map); + MEM_freeN(vert_to_edge_src_map); + MEM_freeN(vert_to_edge_src_map_mem); + } + else if (mode == MREMAP_MODE_EDGE_NEAREST) { + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); + nearest.index = -1; + + for (i = 0; i < numedges_dst; i++) { + interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) { + MEdge *edges_src = me_src->medge; + MPoly *polys_src = me_src->mpoly; + MLoop *loops_src = me_src->mloop; + float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); + + for (i = 0; i < numedges_dst; i++) { + interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[nearest.index]; + MPoly *mp_src = &polys_src[lt->poly]; + MLoop *ml_src = &loops_src[mp_src->loopstart]; + int nloops = mp_src->totloop; + float best_dist_sq = FLT_MAX; + int best_eidx_src = -1; + + for (; nloops--; ml_src++) { + MEdge *med_src = &edges_src[ml_src->e]; + float *co1_src = vcos_src[med_src->v1]; + float *co2_src = vcos_src[med_src->v2]; + float co_src[3]; + float dist_sq; + + interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f); + dist_sq = len_squared_v3v3(tmp_co, co_src); + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + best_eidx_src = (int)ml_src->e; + } + } + if (best_eidx_src >= 0) { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); + } + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + } + else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) { + const int num_rays_min = 5, num_rays_max = 100; + const int numedges_src = me_src->totedge; + + /* Subtleness - this one we can allocate only max number of cast rays per edges! */ + int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), + __func__); + /* Here it's simpler to just allocate for all edges :/ */ + float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__); + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); + + for (i = 0; i < numedges_dst; i++) { + /* For each dst edge, we sample some rays from it (interpolated from its vertices) + * and use their hits to interpolate from source edges. */ + const MEdge *me = &edges_dst[i]; + float v1_co[3], v2_co[3]; + float v1_no[3], v2_no[3]; + + int grid_size; + float edge_dst_len; + float grid_step; + + float totweights = 0.0f; + float hit_dist_accum = 0.0f; + int sources_num = 0; + int j; + + copy_v3_v3(v1_co, verts_dst[me->v1].co); + copy_v3_v3(v2_co, verts_dst[me->v2].co); + + normal_short_to_float_v3(v1_no, verts_dst[me->v1].no); + normal_short_to_float_v3(v2_no, verts_dst[me->v2].no); + + /* We do our transform here, allows to interpolate from normals already in src space. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, v1_co); + BLI_space_transform_apply(space_transform, v2_co); + BLI_space_transform_apply_normal(space_transform, v1_no); + BLI_space_transform_apply_normal(space_transform, v2_no); + } + + copy_vn_fl(weights, (int)numedges_src, 0.0f); + + /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), + * with lower/upper bounds. */ + edge_dst_len = len_v3v3(v1_co, v2_co); + + grid_size = (int)((edge_dst_len / ray_radius) + 0.5f); + CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */ + + grid_step = 1.0f / + (float)grid_size; /* Not actual distance here, rather an interp fac... */ + + /* And now we can cast all our rays, and see what we get! */ + for (j = 0; j < grid_size; j++) { + const float fac = grid_step * (float)j; + + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + interp_v3_v3v3(tmp_co, v1_co, v2_co, fac); + interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac); + + while (n--) { + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) { + weights[rayhit.index] += w; + totweights += w; + hit_dist_accum += hit_dist; + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + } + /* A sampling is valid (as in, its result can be considered as valid sources) only if at least + * half of the rays found a source! */ + if (totweights > ((float)grid_size / 2.0f)) { + for (j = 0; j < (int)numedges_src; j++) { + if (!weights[j]) { + continue; + } + /* Note: sources_num is always <= j! */ + weights[sources_num] = weights[j] / totweights; + indices[sources_num] = j; + sources_num++; + } + mesh_remap_item_define( + r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(indices); + MEM_freeN(weights); + } + else { + CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst); + } + + free_bvhtree_from_mesh(&treedata); + } } -#define POLY_UNSET 0 +#define POLY_UNSET 0 #define POLY_CENTER_INIT 1 -#define POLY_COMPLETE 2 - -static void mesh_island_to_astar_graph_edge_process( - MeshIslandStore *islands, const int island_index, BLI_AStarGraph *as_graph, - MVert *verts, MPoly *polys, MLoop *loops, - const int edge_idx, BLI_bitmap *done_edges, MeshElemMap *edge_to_poly_map, const bool is_edge_innercut, - int *poly_island_index_map, float (*poly_centers)[3], unsigned char *poly_status) +#define POLY_COMPLETE 2 + +static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, + const int island_index, + BLI_AStarGraph *as_graph, + MVert *verts, + MPoly *polys, + MLoop *loops, + const int edge_idx, + BLI_bitmap *done_edges, + MeshElemMap *edge_to_poly_map, + const bool is_edge_innercut, + int *poly_island_index_map, + float (*poly_centers)[3], + unsigned char *poly_status) { - int *poly_island_indices = BLI_array_alloca(poly_island_indices, (size_t)edge_to_poly_map[edge_idx].count); - int i, j; - - for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) { - const int pidx = edge_to_poly_map[edge_idx].indices[i]; - MPoly *mp = &polys[pidx]; - const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx; - void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1); - - if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) { - /* poly not in current island, happens with border edges... */ - poly_island_indices[i] = -1; - continue; - } - - if (poly_status[pidx_isld] == POLY_COMPLETE) { - poly_island_indices[i] = pidx_isld; - continue; - } - - if (poly_status[pidx_isld] == POLY_UNSET) { - BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]); - BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]); - poly_status[pidx_isld] = POLY_CENTER_INIT; - } - - for (j = i; j--;) { - float dist_cost; - const int pidx_isld_other = poly_island_indices[j]; - - if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) { - /* If the other poly is complete, that link has already been added! */ - continue; - } - dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]); - BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data); - } - - poly_island_indices[i] = pidx_isld; - } - - BLI_BITMAP_ENABLE(done_edges, edge_idx); + int *poly_island_indices = BLI_array_alloca(poly_island_indices, + (size_t)edge_to_poly_map[edge_idx].count); + int i, j; + + for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) { + const int pidx = edge_to_poly_map[edge_idx].indices[i]; + MPoly *mp = &polys[pidx]; + const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx; + void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1); + + if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) { + /* poly not in current island, happens with border edges... */ + poly_island_indices[i] = -1; + continue; + } + + if (poly_status[pidx_isld] == POLY_COMPLETE) { + poly_island_indices[i] = pidx_isld; + continue; + } + + if (poly_status[pidx_isld] == POLY_UNSET) { + BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]); + BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]); + poly_status[pidx_isld] = POLY_CENTER_INIT; + } + + for (j = i; j--;) { + float dist_cost; + const int pidx_isld_other = poly_island_indices[j]; + + if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) { + /* If the other poly is complete, that link has already been added! */ + continue; + } + dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]); + BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data); + } + + poly_island_indices[i] = pidx_isld; + } + + BLI_BITMAP_ENABLE(done_edges, edge_idx); } -static void mesh_island_to_astar_graph( - MeshIslandStore *islands, const int island_index, - MVert *verts, MeshElemMap *edge_to_poly_map, const int numedges, MLoop *loops, MPoly *polys, const int numpolys, - BLI_AStarGraph *r_as_graph) +static void mesh_island_to_astar_graph(MeshIslandStore *islands, + const int island_index, + MVert *verts, + MeshElemMap *edge_to_poly_map, + const int numedges, + MLoop *loops, + MPoly *polys, + const int numpolys, + BLI_AStarGraph *r_as_graph) { - MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL; - MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL; - - int *poly_island_index_map = NULL; - BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__); - - const int node_num = islands ? island_poly_map->count : numpolys; - unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__); - float (*poly_centers)[3]; - - int pidx_isld; - int i; - - BLI_astar_graph_init(r_as_graph, node_num, NULL); - /* poly_centers is owned by graph memarena. */ - poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num); - - if (islands) { - /* poly_island_index_map is owned by graph memarena. */ - poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_island_index_map) * (size_t)numpolys); - for (i = island_poly_map->count; i--;) { - poly_island_index_map[island_poly_map->indices[i]] = i; - } - - r_as_graph->custom_data = poly_island_index_map; - - for (i = island_einnercut_map->count; i--;) { - mesh_island_to_astar_graph_edge_process( - islands, island_index, r_as_graph, verts, polys, loops, - island_einnercut_map->indices[i], done_edges, edge_to_poly_map, true, - poly_island_index_map, poly_centers, poly_status); - } - } - - for (pidx_isld = node_num; pidx_isld--;) { - const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld; - MPoly *mp = &polys[pidx]; - int pl_idx, l_idx; - - if (poly_status[pidx_isld] == POLY_COMPLETE) { - continue; - } - - for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) { - MLoop *ml = &loops[l_idx]; - - if (BLI_BITMAP_TEST(done_edges, ml->e)) { - continue; - } - - mesh_island_to_astar_graph_edge_process( - islands, island_index, r_as_graph, verts, polys, loops, - (int)ml->e, done_edges, edge_to_poly_map, false, - poly_island_index_map, poly_centers, poly_status); - } - poly_status[pidx_isld] = POLY_COMPLETE; - } - - MEM_freeN(done_edges); - MEM_freeN(poly_status); + MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL; + MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL; + + int *poly_island_index_map = NULL; + BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__); + + const int node_num = islands ? island_poly_map->count : numpolys; + unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__); + float(*poly_centers)[3]; + + int pidx_isld; + int i; + + BLI_astar_graph_init(r_as_graph, node_num, NULL); + /* poly_centers is owned by graph memarena. */ + poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num); + + if (islands) { + /* poly_island_index_map is owned by graph memarena. */ + poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem, + sizeof(*poly_island_index_map) * (size_t)numpolys); + for (i = island_poly_map->count; i--;) { + poly_island_index_map[island_poly_map->indices[i]] = i; + } + + r_as_graph->custom_data = poly_island_index_map; + + for (i = island_einnercut_map->count; i--;) { + mesh_island_to_astar_graph_edge_process(islands, + island_index, + r_as_graph, + verts, + polys, + loops, + island_einnercut_map->indices[i], + done_edges, + edge_to_poly_map, + true, + poly_island_index_map, + poly_centers, + poly_status); + } + } + + for (pidx_isld = node_num; pidx_isld--;) { + const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld; + MPoly *mp = &polys[pidx]; + int pl_idx, l_idx; + + if (poly_status[pidx_isld] == POLY_COMPLETE) { + continue; + } + + for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) { + MLoop *ml = &loops[l_idx]; + + if (BLI_BITMAP_TEST(done_edges, ml->e)) { + continue; + } + + mesh_island_to_astar_graph_edge_process(islands, + island_index, + r_as_graph, + verts, + polys, + loops, + (int)ml->e, + done_edges, + edge_to_poly_map, + false, + poly_island_index_map, + poly_centers, + poly_status); + } + poly_status[pidx_isld] = POLY_COMPLETE; + } + + MEM_freeN(done_edges); + MEM_freeN(poly_status); } #undef POLY_UNSET @@ -1090,1145 +1202,1265 @@ static void mesh_island_to_astar_graph( /* Our 'f_cost' callback func, to find shortest poly-path between two remapped-loops. * Note we do not want to make innercuts 'walls' here, just detect when the shortest path goes by those. */ -static float mesh_remap_calc_loops_astar_f_cost( - BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, - const int node_idx_curr, const int node_idx_next, const int node_idx_dst) +static float mesh_remap_calc_loops_astar_f_cost(BLI_AStarGraph *as_graph, + BLI_AStarSolution *as_solution, + BLI_AStarGNLink *link, + const int node_idx_curr, + const int node_idx_next, + const int node_idx_dst) { - float *co_next, *co_dest; - - if (link && (POINTER_AS_INT(link->custom_data) != -1)) { - /* An innercut edge... We tag our solution as potentially crossing innercuts. - * Note it might not be the case in the end (AStar will explore around optimal path), but helps - * trimming off some processing later... */ - if (!POINTER_AS_INT(as_solution->custom_data)) { - as_solution->custom_data = POINTER_FROM_INT(true); - } - } - - /* Our heuristic part of current f_cost is distance from next node to destination one. - * It is guaranteed to be less than (or equal to) actual shortest poly-path between next node and destination one. - */ - co_next = (float *)as_graph->nodes[node_idx_next].custom_data; - co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data; - return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) + len_v3v3(co_next, co_dest); + float *co_next, *co_dest; + + if (link && (POINTER_AS_INT(link->custom_data) != -1)) { + /* An innercut edge... We tag our solution as potentially crossing innercuts. + * Note it might not be the case in the end (AStar will explore around optimal path), but helps + * trimming off some processing later... */ + if (!POINTER_AS_INT(as_solution->custom_data)) { + as_solution->custom_data = POINTER_FROM_INT(true); + } + } + + /* Our heuristic part of current f_cost is distance from next node to destination one. + * It is guaranteed to be less than (or equal to) actual shortest poly-path between next node and destination one. + */ + co_next = (float *)as_graph->nodes[node_idx_next].custom_data; + co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data; + return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) + + len_v3v3(co_next, co_dest); } #define ASTAR_STEPS_MAX 64 - -void BKE_mesh_remap_calc_loops_from_mesh( - const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, - MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst, - MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst, - CustomData *ldata_dst, CustomData *pdata_dst, - const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst, - Mesh *me_src, - MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map) +void BKE_mesh_remap_calc_loops_from_mesh(const int mode, + const SpaceTransform *space_transform, + const float max_dist, + const float ray_radius, + MVert *verts_dst, + const int numverts_dst, + MEdge *edges_dst, + const int numedges_dst, + MLoop *loops_dst, + const int numloops_dst, + MPoly *polys_dst, + const int numpolys_dst, + CustomData *ldata_dst, + CustomData *pdata_dst, + const bool use_split_nors_dst, + const float split_angle_dst, + const bool dirty_nors_dst, + Mesh *me_src, + MeshRemapIslandsCalc gen_islands_src, + const float islands_precision_src, + MeshPairRemap *r_map) { - const float full_weight = 1.0f; - const float max_dist_sq = max_dist * max_dist; - - int i; - - BLI_assert(mode & MREMAP_MODE_LOOP); - BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f)); - - BKE_mesh_remap_init(r_map, numloops_dst); - - if (mode == MREMAP_MODE_TOPOLOGY) { - /* In topology mapping, we assume meshes are identical, islands included! */ - BLI_assert(numloops_dst == me_src->totloop); - for (i = 0; i < numloops_dst; i++) { - mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); - } - } - else { - BVHTreeFromMesh *treedata = NULL; - BVHTreeNearest nearest = {0}; - BVHTreeRayHit rayhit = {0}; - int num_trees = 0; - float hit_dist; - float tmp_co[3], tmp_no[3]; - - const bool use_from_vert = (mode & MREMAP_USE_VERT); - - MeshIslandStore island_store = {0}; - bool use_islands = false; - - BLI_AStarGraph *as_graphdata = NULL; - BLI_AStarSolution as_solution = {0}; - const int isld_steps_src = ( - islands_precision_src ? - max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f), 1) : 0); - - float (*poly_nors_src)[3] = NULL; - float (*loop_nors_src)[3] = NULL; - float (*poly_nors_dst)[3] = NULL; - float (*loop_nors_dst)[3] = NULL; - - float (*poly_cents_src)[3] = NULL; - - MeshElemMap *vert_to_loop_map_src = NULL; - int *vert_to_loop_map_src_buff = NULL; - MeshElemMap *vert_to_poly_map_src = NULL; - int *vert_to_poly_map_src_buff = NULL; - MeshElemMap *edge_to_poly_map_src = NULL; - int *edge_to_poly_map_src_buff = NULL; - MeshElemMap *poly_to_looptri_map_src = NULL; - int *poly_to_looptri_map_src_buff = NULL; - - /* Unlike above, those are one-to-one mappings, simpler! */ - int *loop_to_poly_map_src = NULL; - - MVert *verts_src = me_src->mvert; - const int num_verts_src = me_src->totvert; - float (*vcos_src)[3] = NULL; - MEdge *edges_src = me_src->medge; - const int num_edges_src = me_src->totedge; - MLoop *loops_src = me_src->mloop; - const int num_loops_src = me_src->totloop; - MPoly *polys_src = me_src->mpoly; - const int num_polys_src = me_src->totpoly; - const MLoopTri *looptri_src = NULL; - int num_looptri_src = 0; - - size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE; - float (*vcos_interp)[3] = NULL; - int *indices_interp = NULL; - float *weights_interp = NULL; - - MLoop *ml_src, *ml_dst; - MPoly *mp_src, *mp_dst; - int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; - - IslandResult **islands_res; - size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE; - - if (!use_from_vert) { - vcos_src = BKE_mesh_vertexCos_get(me_src, NULL); - - vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__); - indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__); - weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__); - } - - { - const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL); - const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ); - const bool need_pnors_src = need_lnors_src || ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL)); - const bool need_pnors_dst = need_lnors_dst || need_pnors_src; - - if (need_pnors_dst) { - /* Cache poly nors into a temp CDLayer. */ - poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); - const bool do_poly_nors_dst = (poly_nors_dst == NULL); - if (!poly_nors_dst) { - poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); - CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } - if (dirty_nors_dst || do_poly_nors_dst) { - BKE_mesh_calc_normals_poly( - verts_dst, NULL, numverts_dst, loops_dst, polys_dst, - numloops_dst, numpolys_dst, poly_nors_dst, true); - } - } - if (need_lnors_dst) { - short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); - - /* Cache poly nors into a temp CDLayer. */ - loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); - const bool do_loop_nors_dst = (loop_nors_dst == NULL); - if (!loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); - CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } - if (dirty_nors_dst || do_loop_nors_dst) { - BKE_mesh_normals_loop_split( - verts_dst, numverts_dst, edges_dst, numedges_dst, - loops_dst, loop_nors_dst, numloops_dst, - polys_dst, (const float (*)[3])poly_nors_dst, numpolys_dst, - use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL); - } - } - if (need_pnors_src || need_lnors_src) { - if (need_pnors_src) { - poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL); - BLI_assert(poly_nors_src != NULL); - } - if (need_lnors_src) { - loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL); - BLI_assert(loop_nors_src != NULL); - } - } - } - - if (use_from_vert) { - BKE_mesh_vert_loop_map_create( - &vert_to_loop_map_src, &vert_to_loop_map_src_buff, - polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src); - if (mode & MREMAP_USE_POLY) { - BKE_mesh_vert_poly_map_create( - &vert_to_poly_map_src, &vert_to_poly_map_src_buff, - polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src); - } - } - - /* Needed for islands (or plain mesh) to AStar graph conversion. */ - BKE_mesh_edge_poly_map_create( - &edge_to_poly_map_src, &edge_to_poly_map_src_buff, - edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src); - if (use_from_vert) { - loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__); - poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__); - for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) { - ml_src = &loops_src[mp_src->loopstart]; - for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) { - loop_to_poly_map_src[lidx_src] = pidx_src; - } - BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]); - } - } - - /* Island makes things slightly more complex here. - * Basically, we: - * * Make one treedata for each island's elements. - * * Check all loops of a same dest poly against all treedata. - * * Choose the island's elements giving the best results. - */ - - /* First, generate the islands, if possible. */ - if (gen_islands_src) { - use_islands = gen_islands_src( - verts_src, num_verts_src, - edges_src, num_edges_src, - polys_src, num_polys_src, - loops_src, num_loops_src, - &island_store); - - num_trees = use_islands ? island_store.islands_num : 1; - treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__); - if (isld_steps_src) { - as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__); - } - - if (use_islands) { - /* We expect our islands to contain poly indices, with edge indices of 'inner cuts', - * and a mapping loops -> islands indices. - * This implies all loops of a same poly are in the same island. */ - BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) && - (island_store.island_type == MISLAND_TYPE_POLY) && - (island_store.innercut_type == MISLAND_TYPE_EDGE)); - } - } - else { - num_trees = 1; - treedata = MEM_callocN(sizeof(*treedata), __func__); - if (isld_steps_src) { - as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__); - } - } - - /* Build our AStar graphs. */ - if (isld_steps_src) { - for (tindex = 0; tindex < num_trees; tindex++) { - mesh_island_to_astar_graph( - use_islands ? &island_store : NULL, tindex, verts_src, edge_to_poly_map_src, num_edges_src, - loops_src, polys_src, num_polys_src, &as_graphdata[tindex]); - } - } - - /* Build our BVHtrees, either from verts or tessfaces. */ - if (use_from_vert) { - if (use_islands) { - BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__); - - for (tindex = 0; tindex < num_trees; tindex++) { - MeshElemMap *isld = island_store.islands[tindex]; - int num_verts_active = 0; - BLI_bitmap_set_all(verts_active, false, (size_t)num_verts_src); - for (i = 0; i < isld->count; i++) { - mp_src = &polys_src[isld->indices[i]]; - for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) { - const unsigned int vidx_src = loops_src[lidx_src].v; - if (!BLI_BITMAP_TEST(verts_active, vidx_src)) { - BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); - num_verts_active++; - } - } - } - bvhtree_from_mesh_verts_ex( - &treedata[tindex], verts_src, num_verts_src, false, - verts_active, num_verts_active, 0.0, 2, 6); - } - - MEM_freeN(verts_active); - } - else { - BLI_assert(num_trees == 1); - BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2); - } - } - else { /* We use polygons. */ - if (use_islands) { - /* bvhtree here uses looptri faces... */ - BLI_bitmap *looptri_active; - - looptri_src = BKE_mesh_runtime_looptri_ensure(me_src); - num_looptri_src = me_src->runtime.looptris.len; - looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); - - for (tindex = 0; tindex < num_trees; tindex++) { - int num_looptri_active = 0; - BLI_bitmap_set_all(looptri_active, false, (size_t)num_looptri_src); - for (i = 0; i < num_looptri_src; i++) { - mp_src = &polys_src[looptri_src[i].poly]; - if (island_store.items_to_islands[mp_src->loopstart] == tindex) { - BLI_BITMAP_ENABLE(looptri_active, i); - num_looptri_active++; - } - } - bvhtree_from_mesh_looptri_ex( - &treedata[tindex], - verts_src, false, - loops_src, false, - looptri_src, num_looptri_src, false, - looptri_active, num_looptri_active, 0.0, 2, 6); - } - - MEM_freeN(looptri_active); - } - else { - BLI_assert(num_trees == 1); - BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2); - } - } - - /* And check each dest poly! */ - islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__); - for (tindex = 0; tindex < num_trees; tindex++) { - islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); - } - - for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { - float pnor_dst[3]; - - /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which - * corner to use from normals only. */ - float pcent_dst[3]; - bool pcent_dst_valid = false; - - if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { - copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]); - if (space_transform) { - BLI_space_transform_apply_normal(space_transform, pnor_dst); - } - } - - if ((size_t)mp_dst->totloop > islands_res_buff_size) { - islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE; - for (tindex = 0; tindex < num_trees; tindex++) { - islands_res[tindex] = MEM_reallocN(islands_res[tindex], sizeof(**islands_res) * islands_res_buff_size); - } - } - - for (tindex = 0; tindex < num_trees; tindex++) { - BVHTreeFromMesh *tdata = &treedata[tindex]; - - ml_dst = &loops_dst[mp_dst->loopstart]; - for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { - if (use_from_vert) { - MeshElemMap *vert_to_refelem_map_src = NULL; - - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - nearest.index = -1; - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - float (*nor_dst)[3]; - float (*nors_src)[3]; - float best_nor_dot = -2.0f; - float best_sqdist_fallback = FLT_MAX; - int best_index_src = -1; - - if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { - copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); - if (space_transform) { - BLI_space_transform_apply_normal(space_transform, tmp_no); - } - nor_dst = &tmp_no; - nors_src = loop_nors_src; - vert_to_refelem_map_src = vert_to_loop_map_src; - } - else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ - nor_dst = &pnor_dst; - nors_src = poly_nors_src; - vert_to_refelem_map_src = vert_to_poly_map_src; - } - - for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { - const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; - BLI_assert(index_src != -1); - const float dot = dot_v3v3(nors_src[index_src], *nor_dst); - - pidx_src = ( - (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? - loop_to_poly_map_src[index_src] : index_src); - /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it - * to check we stay on current island (all loops from a given poly are - * on same island!). */ - lidx_src = ( - (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? - index_src : polys_src[pidx_src].loopstart); - - /* A same vert may be at the boundary of several islands! Hence, we have to ensure - * poly/loop we are currently considering *belongs* to current island! */ - if (use_islands && island_store.items_to_islands[lidx_src] != tindex) { - continue; - } - - if (dot > best_nor_dot - 1e-6f) { - /* We need something as fallback decision in case dest normal matches several - * source normals (see T44522), using distance between polys' centers here. */ - float *pcent_src; - float sqdist; - - mp_src = &polys_src[pidx_src]; - ml_src = &loops_src[mp_src->loopstart]; - - if (!pcent_dst_valid) { - BKE_mesh_calc_poly_center( - mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst); - pcent_dst_valid = true; - } - pcent_src = poly_cents_src[pidx_src]; - sqdist = len_squared_v3v3(pcent_dst, pcent_src); - - if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) { - best_nor_dot = dot; - best_sqdist_fallback = sqdist; - best_index_src = index_src; - } - } - } - if (best_index_src == -1) { - /* We found no item to map back from closest vertex... */ - best_nor_dot = -1.0f; - hit_dist = FLT_MAX; - } - else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { - /* Our best_index_src is a poly one for now! - * Have to find its loop matching our closest vertex. */ - mp_src = &polys_src[best_index_src]; - ml_src = &loops_src[mp_src->loopstart]; - for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { - if ((int)ml_src->v == nearest.index) { - best_index_src = plidx_src + mp_src->loopstart; - break; - } - } - } - best_nor_dot = (best_nor_dot + 1.0f) * 0.5f; - islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f; - islands_res[tindex][plidx_dst].hit_dist = hit_dist; - islands_res[tindex][plidx_dst].index_src = best_index_src; - } - else { - /* No source for this dest loop! */ - islands_res[tindex][plidx_dst].factor = 0.0f; - islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; - islands_res[tindex][plidx_dst].index_src = -1; - } - } - else if (mode & MREMAP_USE_NORPROJ) { - int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; - float w = 1.0f; - - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); - - /* We do our transform here, since we may do several raycast/nearest queries. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - BLI_space_transform_apply_normal(space_transform, tmp_no); - } - - while (n--) { - if (mesh_remap_bvhtree_query_raycast( - tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) - { - islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w; - islands_res[tindex][plidx_dst].hit_dist = hit_dist; - islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[rayhit.index].poly; - copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co); - break; - } - /* Next iteration will get bigger radius but smaller weight! */ - w /= MREMAP_RAYCAST_APPROXIMATE_FAC; - } - if (n == -1) { - /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to - * have only part of one dest face's loops to map to source. - * Note that since we give this a null weight, if whole weight for a given face - * is null, it means none of its loop mapped to this source island, hence we can skip it - * later. - */ - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - nearest.index = -1; - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - /* In any case, this fallback nearest hit should have no weight at all - * in 'best island' decision! */ - islands_res[tindex][plidx_dst].factor = 0.0f; - - if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - islands_res[tindex][plidx_dst].hit_dist = hit_dist; - islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly; - copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); - } - else { - /* No source for this dest loop! */ - islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; - islands_res[tindex][plidx_dst].index_src = -1; - } - } - } - else { /* Nearest poly either to use all its loops/verts or just closest one. */ - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - nearest.index = -1; - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f; - islands_res[tindex][plidx_dst].hit_dist = hit_dist; - islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly; - copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); - } - else { - /* No source for this dest loop! */ - islands_res[tindex][plidx_dst].factor = 0.0f; - islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; - islands_res[tindex][plidx_dst].index_src = -1; - } - } - } - } - - /* And now, find best island to use! */ - /* We have to first select the 'best source island' for given dst poly and its loops. - * Then, we have to check that poly does not 'spread' across some island's limits - * (like inner seams for UVs, etc.). - * Note we only still partially support that kind of situation here, i.e. polys spreading over actual cracks - * (like a narrow space without faces on src, splitting a 'tube-like' geometry). That kind of situation - * should be relatively rare, though. - */ - /* XXX This block in itself is big and complex enough to be a separate function but... it uses a bunch - * of locale vars. Not worth sending all that through parameters (for now at least). */ - { - BLI_AStarGraph *as_graph = NULL; - int *poly_island_index_map = NULL; - int pidx_src_prev = -1; - - MeshElemMap *best_island = NULL; - float best_island_fac = 0.0f; - int best_island_index = -1; - - for (tindex = 0; tindex < num_trees; tindex++) { - float island_fac = 0.0f; - - for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { - island_fac += islands_res[tindex][plidx_dst].factor; - } - island_fac /= (float)mp_dst->totloop; - - if (island_fac > best_island_fac) { - best_island_fac = island_fac; - best_island_index = tindex; - } - } - - if (best_island_index != -1 && isld_steps_src) { - best_island = use_islands ? island_store.islands[best_island_index] : NULL; - as_graph = &as_graphdata[best_island_index]; - poly_island_index_map = (int *)as_graph->custom_data; - BLI_astar_solution_init(as_graph, &as_solution, NULL); - } - - for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { - IslandResult *isld_res; - lidx_dst = plidx_dst + mp_dst->loopstart; - - if (best_island_index == -1) { - /* No source for any loops of our dest poly in any source islands. */ - BKE_mesh_remap_item_define_invalid(r_map, lidx_dst); - continue; - } - - as_solution.custom_data = POINTER_FROM_INT(false); - - isld_res = &islands_res[best_island_index][plidx_dst]; - if (use_from_vert) { - /* Indices stored in islands_res are those of loops, one per dest loop. */ - lidx_src = isld_res->index_src; - if (lidx_src >= 0) { - pidx_src = loop_to_poly_map_src[lidx_src]; - /* If prev and curr poly are the same, no need to do anything more!!! */ - if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { - int pidx_isld_src, pidx_isld_src_prev; - if (poly_island_index_map) { - pidx_isld_src = poly_island_index_map[pidx_src]; - pidx_isld_src_prev = poly_island_index_map[pidx_src_prev]; - } - else { - pidx_isld_src = pidx_src; - pidx_isld_src_prev = pidx_src_prev; - } - - BLI_astar_graph_solve( - as_graph, pidx_isld_src_prev, pidx_isld_src, - mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src); - if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) { - /* Find first 'cutting edge' on path, and bring back lidx_src on poly just - * before that edge. - * Note we could try to be much smarter (like e.g. storing a whole poly's indices, - * and making decision (on which side of cutting edge(s!) to be) on the end, - * but this is one more level of complexity, better to first see if - * simple solution works! - */ - int last_valid_pidx_isld_src = -1; - /* Note we go backward here, from dest to src poly. */ - for (i = as_solution.steps - 1; i--;) { - BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; - const int eidx = POINTER_AS_INT(as_link->custom_data); - pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; - BLI_assert(pidx_isld_src != -1); - if (eidx != -1) { - /* we are 'crossing' a cutting edge. */ - last_valid_pidx_isld_src = pidx_isld_src; - } - } - if (last_valid_pidx_isld_src != -1) { - /* Find a new valid loop in that new poly (nearest one for now). - * Note we could be much more subtle here, again that's for later... */ - int j; - float best_dist_sq = FLT_MAX; - - ml_dst = &loops_dst[lidx_dst]; - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - - /* We do our transform here, since we may do several raycast/nearest queries. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - pidx_src = ( - use_islands ? best_island->indices[last_valid_pidx_isld_src] : - last_valid_pidx_isld_src); - mp_src = &polys_src[pidx_src]; - ml_src = &loops_src[mp_src->loopstart]; - for (j = 0; j < mp_src->totloop; j++, ml_src++) { - const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co); - if (dist_sq < best_dist_sq) { - best_dist_sq = dist_sq; - lidx_src = mp_src->loopstart + j; - } - } - } - } - } - mesh_remap_item_define( - r_map, lidx_dst, isld_res->hit_dist, - best_island_index, 1, &lidx_src, &full_weight); - pidx_src_prev = pidx_src; - } - else { - /* No source for this loop in this island. */ - /* TODO: would probably be better to get a source at all cost in best island anyway? */ - mesh_remap_item_define( - r_map, lidx_dst, FLT_MAX, - best_island_index, 0, NULL, NULL); - } - } - else { - /* Else, we use source poly, indices stored in islands_res are those of polygons. */ - pidx_src = isld_res->index_src; - if (pidx_src >= 0) { - float *hit_co = isld_res->hit_point; - int best_loop_index_src; - - mp_src = &polys_src[pidx_src]; - /* If prev and curr poly are the same, no need to do anything more!!! */ - if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { - int pidx_isld_src, pidx_isld_src_prev; - if (poly_island_index_map) { - pidx_isld_src = poly_island_index_map[pidx_src]; - pidx_isld_src_prev = poly_island_index_map[pidx_src_prev]; - } - else { - pidx_isld_src = pidx_src; - pidx_isld_src_prev = pidx_src_prev; - } - - BLI_astar_graph_solve( - as_graph, pidx_isld_src_prev, pidx_isld_src, - mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src); - if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) { - /* Find first 'cutting edge' on path, and bring back lidx_src on poly just - * before that edge. - * Note we could try to be much smarter (like e.g. storing a whole poly's indices, - * and making decision (one which side of cutting edge(s!) to be on the end, - * but this is one more level of complexity, better to first see if - * simple solution works! - */ - int last_valid_pidx_isld_src = -1; - /* Note we go backward here, from dest to src poly. */ - for (i = as_solution.steps - 1; i--;) { - BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; - int eidx = POINTER_AS_INT(as_link->custom_data); - - pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; - BLI_assert(pidx_isld_src != -1); - if (eidx != -1) { - /* we are 'crossing' a cutting edge. */ - last_valid_pidx_isld_src = pidx_isld_src; - } - } - if (last_valid_pidx_isld_src != -1) { - /* Find a new valid loop in that new poly (nearest point on poly for now). - * Note we could be much more subtle here, again that's for later... */ - float best_dist_sq = FLT_MAX; - int j; - - ml_dst = &loops_dst[lidx_dst]; - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); - - /* We do our transform here, since we may do several raycast/nearest queries. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - pidx_src = ( - use_islands ? best_island->indices[last_valid_pidx_isld_src] : - last_valid_pidx_isld_src); - mp_src = &polys_src[pidx_src]; - - /* Create that one on demand. */ - if (poly_to_looptri_map_src == NULL) { - BKE_mesh_origindex_map_create_looptri( - &poly_to_looptri_map_src, &poly_to_looptri_map_src_buff, - polys_src, num_polys_src, - looptri_src, num_looptri_src); - } - - for (j = poly_to_looptri_map_src[pidx_src].count; j--;) { - float h[3]; - const MLoopTri *lt = &looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]]; - float dist_sq; - - closest_on_tri_to_point_v3( - h, tmp_co, - vcos_src[loops_src[lt->tri[0]].v], - vcos_src[loops_src[lt->tri[1]].v], - vcos_src[loops_src[lt->tri[2]].v]); - dist_sq = len_squared_v3v3(tmp_co, h); - if (dist_sq < best_dist_sq) { - copy_v3_v3(hit_co, h); - best_dist_sq = dist_sq; - } - } - } - } - } - - if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) { - mesh_remap_interp_poly_data_get( - mp_src, loops_src, (const float (*)[3])vcos_src, hit_co, - &buff_size_interp, &vcos_interp, true, &indices_interp, - &weights_interp, false, &best_loop_index_src); - - mesh_remap_item_define( - r_map, lidx_dst, isld_res->hit_dist, - best_island_index, 1, &best_loop_index_src, &full_weight); - } - else { - const int sources_num = mesh_remap_interp_poly_data_get( - mp_src, loops_src, (const float (*)[3])vcos_src, hit_co, - &buff_size_interp, &vcos_interp, true, &indices_interp, - &weights_interp, true, NULL); - - mesh_remap_item_define( - r_map, lidx_dst, - isld_res->hit_dist, best_island_index, - sources_num, indices_interp, weights_interp); - } - - pidx_src_prev = pidx_src; - } - else { - /* No source for this loop in this island. */ - /* TODO: would probably be better to get a source at all cost in best island anyway? */ - mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL); - } - } - } - - BLI_astar_solution_clear(&as_solution); - } - } - - for (tindex = 0; tindex < num_trees; tindex++) { - MEM_freeN(islands_res[tindex]); - free_bvhtree_from_mesh(&treedata[tindex]); - if (isld_steps_src) { - BLI_astar_graph_free(&as_graphdata[tindex]); - } - } - MEM_freeN(islands_res); - BKE_mesh_loop_islands_free(&island_store); - MEM_freeN(treedata); - if (isld_steps_src) { - MEM_freeN(as_graphdata); - BLI_astar_solution_free(&as_solution); - } - - if (vcos_src) { - MEM_freeN(vcos_src); - } - if (vert_to_loop_map_src) { - MEM_freeN(vert_to_loop_map_src); - } - if (vert_to_loop_map_src_buff) { - MEM_freeN(vert_to_loop_map_src_buff); - } - if (vert_to_poly_map_src) { - MEM_freeN(vert_to_poly_map_src); - } - if (vert_to_poly_map_src_buff) { - MEM_freeN(vert_to_poly_map_src_buff); - } - if (edge_to_poly_map_src) { - MEM_freeN(edge_to_poly_map_src); - } - if (edge_to_poly_map_src_buff) { - MEM_freeN(edge_to_poly_map_src_buff); - } - if (poly_to_looptri_map_src) { - MEM_freeN(poly_to_looptri_map_src); - } - if (poly_to_looptri_map_src_buff) { - MEM_freeN(poly_to_looptri_map_src_buff); - } - if (loop_to_poly_map_src) { - MEM_freeN(loop_to_poly_map_src); - } - if (poly_cents_src) { - MEM_freeN(poly_cents_src); - } - if (vcos_interp) { - MEM_freeN(vcos_interp); - } - if (indices_interp) { - MEM_freeN(indices_interp); - } - if (weights_interp) { - MEM_freeN(weights_interp); - } - } + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + + int i; + + BLI_assert(mode & MREMAP_MODE_LOOP); + BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f)); + + BKE_mesh_remap_init(r_map, numloops_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + /* In topology mapping, we assume meshes are identical, islands included! */ + BLI_assert(numloops_dst == me_src->totloop); + for (i = 0; i < numloops_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh *treedata = NULL; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + int num_trees = 0; + float hit_dist; + float tmp_co[3], tmp_no[3]; + + const bool use_from_vert = (mode & MREMAP_USE_VERT); + + MeshIslandStore island_store = {0}; + bool use_islands = false; + + BLI_AStarGraph *as_graphdata = NULL; + BLI_AStarSolution as_solution = {0}; + const int isld_steps_src = (islands_precision_src ? + max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f), + 1) : + 0); + + float(*poly_nors_src)[3] = NULL; + float(*loop_nors_src)[3] = NULL; + float(*poly_nors_dst)[3] = NULL; + float(*loop_nors_dst)[3] = NULL; + + float(*poly_cents_src)[3] = NULL; + + MeshElemMap *vert_to_loop_map_src = NULL; + int *vert_to_loop_map_src_buff = NULL; + MeshElemMap *vert_to_poly_map_src = NULL; + int *vert_to_poly_map_src_buff = NULL; + MeshElemMap *edge_to_poly_map_src = NULL; + int *edge_to_poly_map_src_buff = NULL; + MeshElemMap *poly_to_looptri_map_src = NULL; + int *poly_to_looptri_map_src_buff = NULL; + + /* Unlike above, those are one-to-one mappings, simpler! */ + int *loop_to_poly_map_src = NULL; + + MVert *verts_src = me_src->mvert; + const int num_verts_src = me_src->totvert; + float(*vcos_src)[3] = NULL; + MEdge *edges_src = me_src->medge; + const int num_edges_src = me_src->totedge; + MLoop *loops_src = me_src->mloop; + const int num_loops_src = me_src->totloop; + MPoly *polys_src = me_src->mpoly; + const int num_polys_src = me_src->totpoly; + const MLoopTri *looptri_src = NULL; + int num_looptri_src = 0; + + size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE; + float(*vcos_interp)[3] = NULL; + int *indices_interp = NULL; + float *weights_interp = NULL; + + MLoop *ml_src, *ml_dst; + MPoly *mp_src, *mp_dst; + int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; + + IslandResult **islands_res; + size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE; + + if (!use_from_vert) { + vcos_src = BKE_mesh_vertexCos_get(me_src, NULL); + + vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__); + indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__); + weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__); + } + + { + const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL); + const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ); + const bool need_pnors_src = need_lnors_src || + ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL)); + const bool need_pnors_dst = need_lnors_dst || need_pnors_src; + + if (need_pnors_dst) { + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + const bool do_poly_nors_dst = (poly_nors_dst == NULL); + if (!poly_nors_dst) { + poly_nors_dst = CustomData_add_layer( + pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst || do_poly_nors_dst) { + BKE_mesh_calc_normals_poly(verts_dst, + NULL, + numverts_dst, + loops_dst, + polys_dst, + numloops_dst, + numpolys_dst, + poly_nors_dst, + true); + } + } + if (need_lnors_dst) { + short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); + + /* Cache poly nors into a temp CDLayer. */ + loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); + const bool do_loop_nors_dst = (loop_nors_dst == NULL); + if (!loop_nors_dst) { + loop_nors_dst = CustomData_add_layer( + ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst || do_loop_nors_dst) { + BKE_mesh_normals_loop_split(verts_dst, + numverts_dst, + edges_dst, + numedges_dst, + loops_dst, + loop_nors_dst, + numloops_dst, + polys_dst, + (const float(*)[3])poly_nors_dst, + numpolys_dst, + use_split_nors_dst, + split_angle_dst, + NULL, + custom_nors_dst, + NULL); + } + } + if (need_pnors_src || need_lnors_src) { + if (need_pnors_src) { + poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL); + BLI_assert(poly_nors_src != NULL); + } + if (need_lnors_src) { + loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL); + BLI_assert(loop_nors_src != NULL); + } + } + } + + if (use_from_vert) { + BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src, + &vert_to_loop_map_src_buff, + polys_src, + loops_src, + num_verts_src, + num_polys_src, + num_loops_src); + if (mode & MREMAP_USE_POLY) { + BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src, + &vert_to_poly_map_src_buff, + polys_src, + loops_src, + num_verts_src, + num_polys_src, + num_loops_src); + } + } + + /* Needed for islands (or plain mesh) to AStar graph conversion. */ + BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src, + &edge_to_poly_map_src_buff, + edges_src, + num_edges_src, + polys_src, + num_polys_src, + loops_src, + num_loops_src); + if (use_from_vert) { + loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, + __func__); + poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__); + for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) { + ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; + plidx_src++, lidx_src++) { + loop_to_poly_map_src[lidx_src] = pidx_src; + } + BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]); + } + } + + /* Island makes things slightly more complex here. + * Basically, we: + * * Make one treedata for each island's elements. + * * Check all loops of a same dest poly against all treedata. + * * Choose the island's elements giving the best results. + */ + + /* First, generate the islands, if possible. */ + if (gen_islands_src) { + use_islands = gen_islands_src(verts_src, + num_verts_src, + edges_src, + num_edges_src, + polys_src, + num_polys_src, + loops_src, + num_loops_src, + &island_store); + + num_trees = use_islands ? island_store.islands_num : 1; + treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__); + if (isld_steps_src) { + as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__); + } + + if (use_islands) { + /* We expect our islands to contain poly indices, with edge indices of 'inner cuts', + * and a mapping loops -> islands indices. + * This implies all loops of a same poly are in the same island. */ + BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) && + (island_store.island_type == MISLAND_TYPE_POLY) && + (island_store.innercut_type == MISLAND_TYPE_EDGE)); + } + } + else { + num_trees = 1; + treedata = MEM_callocN(sizeof(*treedata), __func__); + if (isld_steps_src) { + as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__); + } + } + + /* Build our AStar graphs. */ + if (isld_steps_src) { + for (tindex = 0; tindex < num_trees; tindex++) { + mesh_island_to_astar_graph(use_islands ? &island_store : NULL, + tindex, + verts_src, + edge_to_poly_map_src, + num_edges_src, + loops_src, + polys_src, + num_polys_src, + &as_graphdata[tindex]); + } + } + + /* Build our BVHtrees, either from verts or tessfaces. */ + if (use_from_vert) { + if (use_islands) { + BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__); + + for (tindex = 0; tindex < num_trees; tindex++) { + MeshElemMap *isld = island_store.islands[tindex]; + int num_verts_active = 0; + BLI_bitmap_set_all(verts_active, false, (size_t)num_verts_src); + for (i = 0; i < isld->count; i++) { + mp_src = &polys_src[isld->indices[i]]; + for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; + lidx_src++) { + const unsigned int vidx_src = loops_src[lidx_src].v; + if (!BLI_BITMAP_TEST(verts_active, vidx_src)) { + BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); + num_verts_active++; + } + } + } + bvhtree_from_mesh_verts_ex(&treedata[tindex], + verts_src, + num_verts_src, + false, + verts_active, + num_verts_active, + 0.0, + 2, + 6); + } + + MEM_freeN(verts_active); + } + else { + BLI_assert(num_trees == 1); + BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2); + } + } + else { /* We use polygons. */ + if (use_islands) { + /* bvhtree here uses looptri faces... */ + BLI_bitmap *looptri_active; + + looptri_src = BKE_mesh_runtime_looptri_ensure(me_src); + num_looptri_src = me_src->runtime.looptris.len; + looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); + + for (tindex = 0; tindex < num_trees; tindex++) { + int num_looptri_active = 0; + BLI_bitmap_set_all(looptri_active, false, (size_t)num_looptri_src); + for (i = 0; i < num_looptri_src; i++) { + mp_src = &polys_src[looptri_src[i].poly]; + if (island_store.items_to_islands[mp_src->loopstart] == tindex) { + BLI_BITMAP_ENABLE(looptri_active, i); + num_looptri_active++; + } + } + bvhtree_from_mesh_looptri_ex(&treedata[tindex], + verts_src, + false, + loops_src, + false, + looptri_src, + num_looptri_src, + false, + looptri_active, + num_looptri_active, + 0.0, + 2, + 6); + } + + MEM_freeN(looptri_active); + } + else { + BLI_assert(num_trees == 1); + BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2); + } + } + + /* And check each dest poly! */ + islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__); + for (tindex = 0; tindex < num_trees; tindex++) { + islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); + } + + for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { + float pnor_dst[3]; + + /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which + * corner to use from normals only. */ + float pcent_dst[3]; + bool pcent_dst_valid = false; + + if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { + copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]); + if (space_transform) { + BLI_space_transform_apply_normal(space_transform, pnor_dst); + } + } + + if ((size_t)mp_dst->totloop > islands_res_buff_size) { + islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE; + for (tindex = 0; tindex < num_trees; tindex++) { + islands_res[tindex] = MEM_reallocN(islands_res[tindex], + sizeof(**islands_res) * islands_res_buff_size); + } + } + + for (tindex = 0; tindex < num_trees; tindex++) { + BVHTreeFromMesh *tdata = &treedata[tindex]; + + ml_dst = &loops_dst[mp_dst->loopstart]; + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { + if (use_from_vert) { + MeshElemMap *vert_to_refelem_map_src = NULL; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + float(*nor_dst)[3]; + float(*nors_src)[3]; + float best_nor_dot = -2.0f; + float best_sqdist_fallback = FLT_MAX; + int best_index_src = -1; + + if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { + copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + if (space_transform) { + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + nor_dst = &tmp_no; + nors_src = loop_nors_src; + vert_to_refelem_map_src = vert_to_loop_map_src; + } + else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ + nor_dst = &pnor_dst; + nors_src = poly_nors_src; + vert_to_refelem_map_src = vert_to_poly_map_src; + } + + for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { + const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; + BLI_assert(index_src != -1); + const float dot = dot_v3v3(nors_src[index_src], *nor_dst); + + pidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + loop_to_poly_map_src[index_src] : + index_src); + /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it + * to check we stay on current island (all loops from a given poly are + * on same island!). */ + lidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + index_src : + polys_src[pidx_src].loopstart); + + /* A same vert may be at the boundary of several islands! Hence, we have to ensure + * poly/loop we are currently considering *belongs* to current island! */ + if (use_islands && island_store.items_to_islands[lidx_src] != tindex) { + continue; + } + + if (dot > best_nor_dot - 1e-6f) { + /* We need something as fallback decision in case dest normal matches several + * source normals (see T44522), using distance between polys' centers here. */ + float *pcent_src; + float sqdist; + + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + + if (!pcent_dst_valid) { + BKE_mesh_calc_poly_center( + mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst); + pcent_dst_valid = true; + } + pcent_src = poly_cents_src[pidx_src]; + sqdist = len_squared_v3v3(pcent_dst, pcent_src); + + if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) { + best_nor_dot = dot; + best_sqdist_fallback = sqdist; + best_index_src = index_src; + } + } + } + if (best_index_src == -1) { + /* We found no item to map back from closest vertex... */ + best_nor_dot = -1.0f; + hit_dist = FLT_MAX; + } + else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { + /* Our best_index_src is a poly one for now! + * Have to find its loop matching our closest vertex. */ + mp_src = &polys_src[best_index_src]; + ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { + if ((int)ml_src->v == nearest.index) { + best_index_src = plidx_src + mp_src->loopstart; + break; + } + } + } + best_nor_dot = (best_nor_dot + 1.0f) * 0.5f; + islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = best_index_src; + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + else if (mode & MREMAP_USE_NORPROJ) { + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + while (n--) { + if (mesh_remap_bvhtree_query_raycast( + tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) { + islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[rayhit.index].poly; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co); + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + if (n == -1) { + /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to + * have only part of one dest face's loops to map to source. + * Note that since we give this a null weight, if whole weight for a given face + * is null, it means none of its loop mapped to this source island, hence we can skip it + * later. + */ + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + /* In any case, this fallback nearest hit should have no weight at all + * in 'best island' decision! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + } + else { /* Nearest poly either to use all its loops/verts or just closest one. */ + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + } + } + + /* And now, find best island to use! */ + /* We have to first select the 'best source island' for given dst poly and its loops. + * Then, we have to check that poly does not 'spread' across some island's limits + * (like inner seams for UVs, etc.). + * Note we only still partially support that kind of situation here, i.e. polys spreading over actual cracks + * (like a narrow space without faces on src, splitting a 'tube-like' geometry). That kind of situation + * should be relatively rare, though. + */ + /* XXX This block in itself is big and complex enough to be a separate function but... it uses a bunch + * of locale vars. Not worth sending all that through parameters (for now at least). */ + { + BLI_AStarGraph *as_graph = NULL; + int *poly_island_index_map = NULL; + int pidx_src_prev = -1; + + MeshElemMap *best_island = NULL; + float best_island_fac = 0.0f; + int best_island_index = -1; + + for (tindex = 0; tindex < num_trees; tindex++) { + float island_fac = 0.0f; + + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { + island_fac += islands_res[tindex][plidx_dst].factor; + } + island_fac /= (float)mp_dst->totloop; + + if (island_fac > best_island_fac) { + best_island_fac = island_fac; + best_island_index = tindex; + } + } + + if (best_island_index != -1 && isld_steps_src) { + best_island = use_islands ? island_store.islands[best_island_index] : NULL; + as_graph = &as_graphdata[best_island_index]; + poly_island_index_map = (int *)as_graph->custom_data; + BLI_astar_solution_init(as_graph, &as_solution, NULL); + } + + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { + IslandResult *isld_res; + lidx_dst = plidx_dst + mp_dst->loopstart; + + if (best_island_index == -1) { + /* No source for any loops of our dest poly in any source islands. */ + BKE_mesh_remap_item_define_invalid(r_map, lidx_dst); + continue; + } + + as_solution.custom_data = POINTER_FROM_INT(false); + + isld_res = &islands_res[best_island_index][plidx_dst]; + if (use_from_vert) { + /* Indices stored in islands_res are those of loops, one per dest loop. */ + lidx_src = isld_res->index_src; + if (lidx_src >= 0) { + pidx_src = loop_to_poly_map_src[lidx_src]; + /* If prev and curr poly are the same, no need to do anything more!!! */ + if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { + int pidx_isld_src, pidx_isld_src_prev; + if (poly_island_index_map) { + pidx_isld_src = poly_island_index_map[pidx_src]; + pidx_isld_src_prev = poly_island_index_map[pidx_src_prev]; + } + else { + pidx_isld_src = pidx_src; + pidx_isld_src_prev = pidx_src_prev; + } + + BLI_astar_graph_solve(as_graph, + pidx_isld_src_prev, + pidx_isld_src, + mesh_remap_calc_loops_astar_f_cost, + &as_solution, + isld_steps_src); + if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) { + /* Find first 'cutting edge' on path, and bring back lidx_src on poly just + * before that edge. + * Note we could try to be much smarter (like e.g. storing a whole poly's indices, + * and making decision (on which side of cutting edge(s!) to be) on the end, + * but this is one more level of complexity, better to first see if + * simple solution works! + */ + int last_valid_pidx_isld_src = -1; + /* Note we go backward here, from dest to src poly. */ + for (i = as_solution.steps - 1; i--;) { + BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; + const int eidx = POINTER_AS_INT(as_link->custom_data); + pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; + BLI_assert(pidx_isld_src != -1); + if (eidx != -1) { + /* we are 'crossing' a cutting edge. */ + last_valid_pidx_isld_src = pidx_isld_src; + } + } + if (last_valid_pidx_isld_src != -1) { + /* Find a new valid loop in that new poly (nearest one for now). + * Note we could be much more subtle here, again that's for later... */ + int j; + float best_dist_sq = FLT_MAX; + + ml_dst = &loops_dst[lidx_dst]; + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] : + last_valid_pidx_isld_src); + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + for (j = 0; j < mp_src->totloop; j++, ml_src++) { + const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co); + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + lidx_src = mp_src->loopstart + j; + } + } + } + } + } + mesh_remap_item_define(r_map, + lidx_dst, + isld_res->hit_dist, + best_island_index, + 1, + &lidx_src, + &full_weight); + pidx_src_prev = pidx_src; + } + else { + /* No source for this loop in this island. */ + /* TODO: would probably be better to get a source at all cost in best island anyway? */ + mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL); + } + } + else { + /* Else, we use source poly, indices stored in islands_res are those of polygons. */ + pidx_src = isld_res->index_src; + if (pidx_src >= 0) { + float *hit_co = isld_res->hit_point; + int best_loop_index_src; + + mp_src = &polys_src[pidx_src]; + /* If prev and curr poly are the same, no need to do anything more!!! */ + if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { + int pidx_isld_src, pidx_isld_src_prev; + if (poly_island_index_map) { + pidx_isld_src = poly_island_index_map[pidx_src]; + pidx_isld_src_prev = poly_island_index_map[pidx_src_prev]; + } + else { + pidx_isld_src = pidx_src; + pidx_isld_src_prev = pidx_src_prev; + } + + BLI_astar_graph_solve(as_graph, + pidx_isld_src_prev, + pidx_isld_src, + mesh_remap_calc_loops_astar_f_cost, + &as_solution, + isld_steps_src); + if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) { + /* Find first 'cutting edge' on path, and bring back lidx_src on poly just + * before that edge. + * Note we could try to be much smarter (like e.g. storing a whole poly's indices, + * and making decision (one which side of cutting edge(s!) to be on the end, + * but this is one more level of complexity, better to first see if + * simple solution works! + */ + int last_valid_pidx_isld_src = -1; + /* Note we go backward here, from dest to src poly. */ + for (i = as_solution.steps - 1; i--;) { + BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; + int eidx = POINTER_AS_INT(as_link->custom_data); + + pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; + BLI_assert(pidx_isld_src != -1); + if (eidx != -1) { + /* we are 'crossing' a cutting edge. */ + last_valid_pidx_isld_src = pidx_isld_src; + } + } + if (last_valid_pidx_isld_src != -1) { + /* Find a new valid loop in that new poly (nearest point on poly for now). + * Note we could be much more subtle here, again that's for later... */ + float best_dist_sq = FLT_MAX; + int j; + + ml_dst = &loops_dst[lidx_dst]; + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] : + last_valid_pidx_isld_src); + mp_src = &polys_src[pidx_src]; + + /* Create that one on demand. */ + if (poly_to_looptri_map_src == NULL) { + BKE_mesh_origindex_map_create_looptri(&poly_to_looptri_map_src, + &poly_to_looptri_map_src_buff, + polys_src, + num_polys_src, + looptri_src, + num_looptri_src); + } + + for (j = poly_to_looptri_map_src[pidx_src].count; j--;) { + float h[3]; + const MLoopTri *lt = + &looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]]; + float dist_sq; + + closest_on_tri_to_point_v3(h, + tmp_co, + vcos_src[loops_src[lt->tri[0]].v], + vcos_src[loops_src[lt->tri[1]].v], + vcos_src[loops_src[lt->tri[2]].v]); + dist_sq = len_squared_v3v3(tmp_co, h); + if (dist_sq < best_dist_sq) { + copy_v3_v3(hit_co, h); + best_dist_sq = dist_sq; + } + } + } + } + } + + if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) { + mesh_remap_interp_poly_data_get(mp_src, + loops_src, + (const float(*)[3])vcos_src, + hit_co, + &buff_size_interp, + &vcos_interp, + true, + &indices_interp, + &weights_interp, + false, + &best_loop_index_src); + + mesh_remap_item_define(r_map, + lidx_dst, + isld_res->hit_dist, + best_island_index, + 1, + &best_loop_index_src, + &full_weight); + } + else { + const int sources_num = mesh_remap_interp_poly_data_get( + mp_src, + loops_src, + (const float(*)[3])vcos_src, + hit_co, + &buff_size_interp, + &vcos_interp, + true, + &indices_interp, + &weights_interp, + true, + NULL); + + mesh_remap_item_define(r_map, + lidx_dst, + isld_res->hit_dist, + best_island_index, + sources_num, + indices_interp, + weights_interp); + } + + pidx_src_prev = pidx_src; + } + else { + /* No source for this loop in this island. */ + /* TODO: would probably be better to get a source at all cost in best island anyway? */ + mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL); + } + } + } + + BLI_astar_solution_clear(&as_solution); + } + } + + for (tindex = 0; tindex < num_trees; tindex++) { + MEM_freeN(islands_res[tindex]); + free_bvhtree_from_mesh(&treedata[tindex]); + if (isld_steps_src) { + BLI_astar_graph_free(&as_graphdata[tindex]); + } + } + MEM_freeN(islands_res); + BKE_mesh_loop_islands_free(&island_store); + MEM_freeN(treedata); + if (isld_steps_src) { + MEM_freeN(as_graphdata); + BLI_astar_solution_free(&as_solution); + } + + if (vcos_src) { + MEM_freeN(vcos_src); + } + if (vert_to_loop_map_src) { + MEM_freeN(vert_to_loop_map_src); + } + if (vert_to_loop_map_src_buff) { + MEM_freeN(vert_to_loop_map_src_buff); + } + if (vert_to_poly_map_src) { + MEM_freeN(vert_to_poly_map_src); + } + if (vert_to_poly_map_src_buff) { + MEM_freeN(vert_to_poly_map_src_buff); + } + if (edge_to_poly_map_src) { + MEM_freeN(edge_to_poly_map_src); + } + if (edge_to_poly_map_src_buff) { + MEM_freeN(edge_to_poly_map_src_buff); + } + if (poly_to_looptri_map_src) { + MEM_freeN(poly_to_looptri_map_src); + } + if (poly_to_looptri_map_src_buff) { + MEM_freeN(poly_to_looptri_map_src_buff); + } + if (loop_to_poly_map_src) { + MEM_freeN(loop_to_poly_map_src); + } + if (poly_cents_src) { + MEM_freeN(poly_cents_src); + } + if (vcos_interp) { + MEM_freeN(vcos_interp); + } + if (indices_interp) { + MEM_freeN(indices_interp); + } + if (weights_interp) { + MEM_freeN(weights_interp); + } + } } -void BKE_mesh_remap_calc_polys_from_mesh( - const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, - MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst, - MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst, - Mesh *me_src, MeshPairRemap *r_map) +void BKE_mesh_remap_calc_polys_from_mesh(const int mode, + const SpaceTransform *space_transform, + const float max_dist, + const float ray_radius, + MVert *verts_dst, + const int numverts_dst, + MLoop *loops_dst, + const int numloops_dst, + MPoly *polys_dst, + const int numpolys_dst, + CustomData *pdata_dst, + const bool dirty_nors_dst, + Mesh *me_src, + MeshPairRemap *r_map) { - const float full_weight = 1.0f; - const float max_dist_sq = max_dist * max_dist; - float (*poly_nors_dst)[3] = NULL; - float tmp_co[3], tmp_no[3]; - int i; - - BLI_assert(mode & MREMAP_MODE_POLY); - - if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) { - /* Cache poly nors into a temp CDLayer. */ - poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); - if (!poly_nors_dst) { - poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); - CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } - if (dirty_nors_dst) { - BKE_mesh_calc_normals_poly( - verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, - poly_nors_dst, true); - } - } - - BKE_mesh_remap_init(r_map, numpolys_dst); - - if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numpolys_dst == me_src->totpoly); - for (i = 0; i < numpolys_dst; i++) { - mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); - } - } - else { - BVHTreeFromMesh treedata = {NULL}; - BVHTreeNearest nearest = {0}; - BVHTreeRayHit rayhit = {0}; - float hit_dist; - - BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); - - if (mode == MREMAP_MODE_POLY_NEAREST) { - nearest.index = -1; - - for (i = 0; i < numpolys_dst; i++) { - MPoly *mp = &polys_dst[i]; - - BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - - if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { - const MLoopTri *lt = &treedata.looptri[nearest.index]; - const int poly_index = (int)lt->poly; - mesh_remap_item_define( - r_map, i, hit_dist, 0, - 1, &poly_index, &full_weight); - } - else { - /* No source for this dest poly! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - else if (mode == MREMAP_MODE_POLY_NOR) { - BLI_assert(poly_nors_dst); - - for (i = 0; i < numpolys_dst; i++) { - MPoly *mp = &polys_dst[i]; - - BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); - copy_v3_v3(tmp_no, poly_nors_dst[i]); - - /* Convert the vertex to tree coordinates, if needed. */ - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - BLI_space_transform_apply_normal(space_transform, tmp_no); - } - - if (mesh_remap_bvhtree_query_raycast( - &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) - { - const MLoopTri *lt = &treedata.looptri[rayhit.index]; - const int poly_index = (int)lt->poly; - - mesh_remap_item_define( - r_map, i, hit_dist, 0, - 1, &poly_index, &full_weight); - } - else { - /* No source for this dest poly! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - } - else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) { - /* We cast our rays randomly, with a pseudo-even distribution (since we spread across tessellated tris, - * with additional weighting based on each tri's relative area). - */ - RNG *rng = BLI_rng_new(0); - - const size_t numpolys_src = (size_t)me_src->totpoly; - - /* Here it's simpler to just allocate for all polys :/ */ - int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__); - float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__); - - size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE; - float (*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__); - /* Tessellated 2D poly, always (num_loops - 2) triangles. */ - int (*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__); - - for (i = 0; i < numpolys_dst; i++) { - /* For each dst poly, we sample some rays from it (2D grid in pnor space) - * and use their hits to interpolate from source polys. */ - /* Note: dst poly is early-converted into src space! */ - MPoly *mp = &polys_dst[i]; - - int tot_rays, done_rays = 0; - float poly_area_2d_inv, done_area = 0.0f; - - float pcent_dst[3]; - float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3]; - float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z; - float poly_dst_2d_size[2]; - - float totweights = 0.0f; - float hit_dist_accum = 0.0f; - int sources_num = 0; - const int tris_num = mp->totloop - 2; - int j; - - BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst); - copy_v3_v3(tmp_no, poly_nors_dst[i]); - - /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */ - if (space_transform) { - BLI_space_transform_apply(space_transform, pcent_dst); - BLI_space_transform_apply_normal(space_transform, tmp_no); - } - - copy_vn_fl(weights, (int)numpolys_src, 0.0f); - - if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { - tmp_poly_size = (size_t)mp->totloop; - poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size); - tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2)); - } - - axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no); - invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat); - - mul_m3_v3(to_pnor_2d_mat, pcent_dst); - poly_dst_2d_z = pcent_dst[2]; - - /* Get (2D) bounding square of our poly. */ - INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max); - - for (j = 0; j < mp->totloop; j++) { - MLoop *ml = &loops_dst[j + mp->loopstart]; - copy_v3_v3(tmp_co, verts_dst[ml->v].co); - if (space_transform) { - BLI_space_transform_apply(space_transform, tmp_co); - } - mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co); - minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]); - } - - /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), - * with lower/upper bounds. */ - sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min); - - if (ray_radius) { - tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f); - CLAMP(tot_rays, MREMAP_RAYCAST_TRI_SAMPLES_MIN, MREMAP_RAYCAST_TRI_SAMPLES_MAX); - } - else { - /* If no radius (pure rays), give max number of rays! */ - tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN; - } - tot_rays *= tot_rays; - - poly_area_2d_inv = area_poly_v2((const float(*)[2])poly_vcos_2d, (unsigned int)mp->totloop); - /* In case we have a null-area degenerated poly... */ - poly_area_2d_inv = 1.0f / max_ff(poly_area_2d_inv, 1e-9f); - - /* Tessellate our poly. */ - if (mp->totloop == 3) { - tri_vidx_2d[0][0] = 0; - tri_vidx_2d[0][1] = 1; - tri_vidx_2d[0][2] = 2; - } - if (mp->totloop == 4) { - tri_vidx_2d[0][0] = 0; - tri_vidx_2d[0][1] = 1; - tri_vidx_2d[0][2] = 2; - tri_vidx_2d[1][0] = 0; - tri_vidx_2d[1][1] = 2; - tri_vidx_2d[1][2] = 3; - } - else { - BLI_polyfill_calc( - poly_vcos_2d, (unsigned int)mp->totloop, -1, - (unsigned int (*)[3])tri_vidx_2d); - } - - for (j = 0; j < tris_num; j++) { - float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]]; - float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]]; - float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]]; - int rays_num; - - /* All this allows us to get 'absolute' number of rays for each tri, avoiding accumulating - * errors over iterations, and helping better even distribution. */ - done_area += area_tri_v2(v1, v2, v3); - rays_num = max_ii((int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays, 0); - done_rays += rays_num; - - while (rays_num--) { - int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; - float w = 1.0f; - - BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co); - - tmp_co[2] = poly_dst_2d_z; - mul_m3_v3(from_pnor_2d_mat, tmp_co); - - /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */ - while (n--) { - if (mesh_remap_bvhtree_query_raycast( - &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) - { - const MLoopTri *lt = &treedata.looptri[rayhit.index]; - - weights[lt->poly] += w; - totweights += w; - hit_dist_accum += hit_dist; - break; - } - /* Next iteration will get bigger radius but smaller weight! */ - w /= MREMAP_RAYCAST_APPROXIMATE_FAC; - } - } - } - - if (totweights > 0.0f) { - for (j = 0; j < (int)numpolys_src; j++) { - if (!weights[j]) { - continue; - } - /* Note: sources_num is always <= j! */ - weights[sources_num] = weights[j] / totweights; - indices[sources_num] = j; - sources_num++; - } - mesh_remap_item_define(r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights); - } - else { - /* No source for this dest poly! */ - BKE_mesh_remap_item_define_invalid(r_map, i); - } - } - - MEM_freeN(tri_vidx_2d); - MEM_freeN(poly_vcos_2d); - MEM_freeN(indices); - MEM_freeN(weights); - BLI_rng_free(rng); - } - else { - CLOG_WARN(&LOG, "Unsupported mesh-to-mesh poly mapping mode (%d)!", mode); - memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst); - } - - free_bvhtree_from_mesh(&treedata); - } + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + float(*poly_nors_dst)[3] = NULL; + float tmp_co[3], tmp_no[3]; + int i; + + BLI_assert(mode & MREMAP_MODE_POLY); + + if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) { + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + if (!poly_nors_dst) { + poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst) { + BKE_mesh_calc_normals_poly(verts_dst, + NULL, + numverts_dst, + loops_dst, + polys_dst, + numloops_dst, + numpolys_dst, + poly_nors_dst, + true); + } + } + + BKE_mesh_remap_init(r_map, numpolys_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numpolys_dst == me_src->totpoly); + for (i = 0; i < numpolys_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); + + if (mode == MREMAP_MODE_POLY_NEAREST) { + nearest.index = -1; + + for (i = 0; i < numpolys_dst; i++) { + MPoly *mp = &polys_dst[i]; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[nearest.index]; + const int poly_index = (int)lt->poly; + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_POLY_NOR) { + BLI_assert(poly_nors_dst); + + for (i = 0; i < numpolys_dst; i++) { + MPoly *mp = &polys_dst[i]; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); + copy_v3_v3(tmp_no, poly_nors_dst[i]); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[rayhit.index]; + const int poly_index = (int)lt->poly; + + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) { + /* We cast our rays randomly, with a pseudo-even distribution (since we spread across tessellated tris, + * with additional weighting based on each tri's relative area). + */ + RNG *rng = BLI_rng_new(0); + + const size_t numpolys_src = (size_t)me_src->totpoly; + + /* Here it's simpler to just allocate for all polys :/ */ + int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__); + float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__); + + size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE; + float(*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__); + /* Tessellated 2D poly, always (num_loops - 2) triangles. */ + int(*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__); + + for (i = 0; i < numpolys_dst; i++) { + /* For each dst poly, we sample some rays from it (2D grid in pnor space) + * and use their hits to interpolate from source polys. */ + /* Note: dst poly is early-converted into src space! */ + MPoly *mp = &polys_dst[i]; + + int tot_rays, done_rays = 0; + float poly_area_2d_inv, done_area = 0.0f; + + float pcent_dst[3]; + float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3]; + float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z; + float poly_dst_2d_size[2]; + + float totweights = 0.0f; + float hit_dist_accum = 0.0f; + int sources_num = 0; + const int tris_num = mp->totloop - 2; + int j; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst); + copy_v3_v3(tmp_no, poly_nors_dst[i]); + + /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */ + if (space_transform) { + BLI_space_transform_apply(space_transform, pcent_dst); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + copy_vn_fl(weights, (int)numpolys_src, 0.0f); + + if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { + tmp_poly_size = (size_t)mp->totloop; + poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size); + tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2)); + } + + axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no); + invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat); + + mul_m3_v3(to_pnor_2d_mat, pcent_dst); + poly_dst_2d_z = pcent_dst[2]; + + /* Get (2D) bounding square of our poly. */ + INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max); + + for (j = 0; j < mp->totloop; j++) { + MLoop *ml = &loops_dst[j + mp->loopstart]; + copy_v3_v3(tmp_co, verts_dst[ml->v].co); + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co); + minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]); + } + + /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), + * with lower/upper bounds. */ + sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min); + + if (ray_radius) { + tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f); + CLAMP(tot_rays, MREMAP_RAYCAST_TRI_SAMPLES_MIN, MREMAP_RAYCAST_TRI_SAMPLES_MAX); + } + else { + /* If no radius (pure rays), give max number of rays! */ + tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN; + } + tot_rays *= tot_rays; + + poly_area_2d_inv = area_poly_v2((const float(*)[2])poly_vcos_2d, + (unsigned int)mp->totloop); + /* In case we have a null-area degenerated poly... */ + poly_area_2d_inv = 1.0f / max_ff(poly_area_2d_inv, 1e-9f); + + /* Tessellate our poly. */ + if (mp->totloop == 3) { + tri_vidx_2d[0][0] = 0; + tri_vidx_2d[0][1] = 1; + tri_vidx_2d[0][2] = 2; + } + if (mp->totloop == 4) { + tri_vidx_2d[0][0] = 0; + tri_vidx_2d[0][1] = 1; + tri_vidx_2d[0][2] = 2; + tri_vidx_2d[1][0] = 0; + tri_vidx_2d[1][1] = 2; + tri_vidx_2d[1][2] = 3; + } + else { + BLI_polyfill_calc( + poly_vcos_2d, (unsigned int)mp->totloop, -1, (unsigned int(*)[3])tri_vidx_2d); + } + + for (j = 0; j < tris_num; j++) { + float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]]; + float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]]; + float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]]; + int rays_num; + + /* All this allows us to get 'absolute' number of rays for each tri, avoiding accumulating + * errors over iterations, and helping better even distribution. */ + done_area += area_tri_v2(v1, v2, v3); + rays_num = max_ii( + (int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays, 0); + done_rays += rays_num; + + while (rays_num--) { + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co); + + tmp_co[2] = poly_dst_2d_z; + mul_m3_v3(from_pnor_2d_mat, tmp_co); + + /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */ + while (n--) { + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) { + const MLoopTri *lt = &treedata.looptri[rayhit.index]; + + weights[lt->poly] += w; + totweights += w; + hit_dist_accum += hit_dist; + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + } + } + + if (totweights > 0.0f) { + for (j = 0; j < (int)numpolys_src; j++) { + if (!weights[j]) { + continue; + } + /* Note: sources_num is always <= j! */ + weights[sources_num] = weights[j] / totweights; + indices[sources_num] = j; + sources_num++; + } + mesh_remap_item_define( + r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(tri_vidx_2d); + MEM_freeN(poly_vcos_2d); + MEM_freeN(indices); + MEM_freeN(weights); + BLI_rng_free(rng); + } + else { + CLOG_WARN(&LOG, "Unsupported mesh-to-mesh poly mapping mode (%d)!", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst); + } + + free_bvhtree_from_mesh(&treedata); + } } #undef MREMAP_RAYCAST_APPROXIMATE_NR -- cgit v1.2.3