Blender  V3.3
mesh_remap.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include <limits.h>
10 
11 #include "CLG_log.h"
12 
13 #include "MEM_guardedalloc.h"
14 
15 #include "DNA_mesh_types.h"
16 #include "DNA_meshdata_types.h"
17 
18 #include "BLI_alloca.h"
19 #include "BLI_astar.h"
20 #include "BLI_bitmap.h"
21 #include "BLI_math.h"
22 #include "BLI_memarena.h"
23 #include "BLI_polyfill_2d.h"
24 #include "BLI_rand.h"
25 #include "BLI_utildefines.h"
26 
27 #include "BKE_bvhutils.h"
28 #include "BKE_customdata.h"
29 #include "BKE_mesh.h"
30 #include "BKE_mesh_mapping.h"
31 #include "BKE_mesh_remap.h" /* own include */
32 #include "BKE_mesh_runtime.h"
33 
34 #include "BLI_strict_flags.h"
35 
36 static CLG_LogRef LOG = {"bke.mesh"};
37 
38 /* -------------------------------------------------------------------- */
43  BVHTreeNearest *nearest,
44  const float co[3],
45  const float max_dist_sq,
46  float *r_hit_dist)
47 {
48  /* Use local proximity heuristics (to reduce the nearest search). */
49  if (nearest->index != -1) {
50  nearest->dist_sq = len_squared_v3v3(co, nearest->co);
51  if (nearest->dist_sq > max_dist_sq) {
52  /* The previous valid index is too far away and not valid for this check. */
53  nearest->dist_sq = max_dist_sq;
54  nearest->index = -1;
55  }
56  }
57  else {
58  nearest->dist_sq = max_dist_sq;
59  }
60  /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */
61  BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata);
62 
63  if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) {
64  *r_hit_dist = sqrtf(nearest->dist_sq);
65  return true;
66  }
67 
68  return false;
69 }
70 
72  BVHTreeRayHit *rayhit,
73  const float co[3],
74  const float no[3],
75  const float radius,
76  const float max_dist,
77  float *r_hit_dist)
78 {
79  BVHTreeRayHit rayhit_tmp;
80  float inv_no[3];
81 
82  rayhit->index = -1;
83  rayhit->dist = max_dist;
85  treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata);
86 
87  /* Also cast in the other direction! */
88  rayhit_tmp = *rayhit;
89  negate_v3_v3(inv_no, no);
91  treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata);
92  if (rayhit_tmp.dist < rayhit->dist) {
93  *rayhit = rayhit_tmp;
94  }
95 
96  if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) {
97  *r_hit_dist = rayhit->dist;
98  return true;
99  }
100 
101  return false;
102 }
103 
106 /* -------------------------------------------------------------------- */
113  const MVert *verts_dst,
114  const int numverts_dst,
115  Mesh *me_src)
116 {
117  BVHTreeFromMesh treedata = {NULL};
118  BVHTreeNearest nearest = {0};
119  float hit_dist;
120 
121  float result = 0.0f;
122  int i;
123 
124  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
125  nearest.index = -1;
126 
127  for (i = 0; i < numverts_dst; i++) {
128  float tmp_co[3];
129 
130  copy_v3_v3(tmp_co, verts_dst[i].co);
131 
132  /* Convert the vertex to tree coordinates, if needed. */
133  if (space_transform) {
134  BLI_space_transform_apply(space_transform, tmp_co);
135  }
136 
137  if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) {
138  result += 1.0f / (hit_dist + 1.0f);
139  }
140  else {
141  /* No source for this dest vertex! */
142  result += 1e-18f;
143  }
144  }
145 
146  result = ((float)numverts_dst / result) - 1.0f;
147 
148 #if 0
149  printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result);
150 #endif
151 
152  return result;
153 }
154 
155 /* This helper computes the eigen values & vectors for
156  * covariance matrix of all given vertices coordinates.
157  *
158  * Those vectors define the 'average ellipsoid' of the mesh (i.e. the 'best fitting' ellipsoid
159  * containing 50% of the vertices).
160  *
161  * Note that it will not perform fantastic in case two or more eigen values are equal
162  * (e.g. a cylinder or parallelepiped with a square section give two identical eigenvalues,
163  * a sphere or tetrahedron give three identical ones, etc.), since you cannot really define all
164  * axes in those cases. We default to dummy generated orthogonal vectors in this case,
165  * instead of using eigen vectors.
166  */
167 static void mesh_calc_eigen_matrix(const MVert *verts,
168  const float (*vcos)[3],
169  const int numverts,
170  float r_mat[4][4])
171 {
172  float center[3], covmat[3][3];
173  float eigen_val[3], eigen_vec[3][3];
174  float(*cos)[3] = NULL;
175 
176  bool eigen_success;
177  int i;
178 
179  if (verts) {
180  const MVert *mv;
181  float(*co)[3];
182 
183  cos = MEM_mallocN(sizeof(*cos) * (size_t)numverts, __func__);
184  for (i = 0, co = cos, mv = verts; i < numverts; i++, co++, mv++) {
185  copy_v3_v3(*co, mv->co);
186  }
187  /* TODO(sergey): For until we officially drop all compilers which
188  * doesn't handle casting correct we use workaround to avoid explicit
189  * cast here.
190  */
191  vcos = (void *)cos;
192  }
193  unit_m4(r_mat);
194 
195  /* NOTE: here we apply sample correction to covariance matrix, since we consider the vertices
196  * as a sample of the whole 'surface' population of our mesh. */
197  BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center);
198 
199  if (cos) {
200  MEM_freeN(cos);
201  }
202 
203  eigen_success = BLI_eigen_solve_selfadjoint_m3((const float(*)[3])covmat, eigen_val, eigen_vec);
204  BLI_assert(eigen_success);
205  UNUSED_VARS_NDEBUG(eigen_success);
206 
207  /* Special handling of cases where some eigen values are (nearly) identical. */
208  if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) {
209  if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
210  /* No preferred direction, that set of vertices has a spherical average,
211  * so we simply returned scaled/translated identity matrix (with no rotation). */
212  unit_m3(eigen_vec);
213  }
214  else {
215  /* Ellipsoid defined by eigen values/vectors has a spherical section,
216  * we can only define one axis from eigen_vec[2] (two others computed eigen vecs
217  * are not so nice for us here, they tend to 'randomly' rotate around valid one).
218  * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */
219  ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]);
220  }
221  }
222  else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
223  /* Same as above, but with eigen_vec[1] as valid axis. */
224  ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]);
225  }
226  else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) {
227  /* Same as above, but with eigen_vec[0] as valid axis. */
228  ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]);
229  }
230 
231  for (i = 0; i < 3; i++) {
232  float evi = eigen_val[i];
233 
234  /* Protect against 1D/2D degenerated cases! */
235  /* NOTE: not sure why we need square root of eigen values here
236  * (which are equivalent to singular values, as far as I have understood),
237  * but it seems to heavily reduce (if not completely nullify)
238  * the error due to non-uniform scalings... */
239  evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi);
240  mul_v3_fl(eigen_vec[i], evi);
241  }
242 
243  copy_m4_m3(r_mat, eigen_vec);
244  copy_v3_v3(r_mat[3], center);
245 }
246 
248  const int numverts_dst,
249  Mesh *me_src,
250  SpaceTransform *r_space_transform)
251 {
252  /* Note that those are done so that we successively get actual mirror matrix
253  * (by multiplication of columns). */
254  const float mirrors[][3] = {
255  {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */
256  {1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */
257  {1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */
258  {1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */
259  {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */
260  {1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */
261  {1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */
262  {0.0f, 0.0f, 0.0f},
263  };
264  const float(*mirr)[3];
265 
266  float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
267  float best_match = FLT_MAX, match;
268 
269  const int numverts_src = me_src->totvert;
270  float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
271 
272  mesh_calc_eigen_matrix(NULL, (const float(*)[3])vcos_src, numverts_src, mat_src);
273  mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
274 
275  BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
277  r_space_transform, verts_dst, numverts_dst, me_src);
278  best_match = match;
279  copy_m4_m4(best_mat_dst, mat_dst);
280 
281  /* And now, we have to check the other sixth possible mirrored versions... */
282  for (mirr = mirrors; (*mirr)[0]; mirr++) {
283  mul_v3_fl(mat_dst[0], (*mirr)[0]);
284  mul_v3_fl(mat_dst[1], (*mirr)[1]);
285  mul_v3_fl(mat_dst[2], (*mirr)[2]);
286 
287  BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
289  r_space_transform, verts_dst, numverts_dst, me_src);
290  if (match < best_match) {
291  best_match = match;
292  copy_m4_m4(best_mat_dst, mat_dst);
293  }
294  }
295 
296  BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src);
297 
298  MEM_freeN(vcos_src);
299 }
300 
303 /* -------------------------------------------------------------------- */
308  const int UNUSED(edge_mode),
309  const int loop_mode,
310  const int UNUSED(poly_mode),
311  CustomData_MeshMasks *r_cddata_mask)
312 {
313  /* vert, edge and poly mapping modes never need extra cddata from source object. */
314  const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL);
315  const bool need_pnors_src = need_lnors_src ||
316  ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL));
317 
318  if (need_lnors_src) {
319  r_cddata_mask->lmask |= CD_MASK_NORMAL;
320  }
321  if (need_pnors_src) {
322  r_cddata_mask->pmask |= CD_MASK_NORMAL;
323  }
324 }
325 
326 void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
327 {
329 
331 
332  map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num);
333  map->items_num = items_num;
334 
335  map->mem = mem;
336 }
337 
339 {
340  if (map->mem) {
341  BLI_memarena_free((MemArena *)map->mem);
342  }
343 
344  map->items_num = 0;
345  map->items = NULL;
346  map->mem = NULL;
347 }
348 
350  const int index,
351  const float UNUSED(hit_dist),
352  const int island,
353  const int sources_num,
354  const int *indices_src,
355  const float *weights_src)
356 {
357  MeshPairRemapItem *mapit = &map->items[index];
358  MemArena *mem = map->mem;
359 
360  if (sources_num) {
361  mapit->sources_num = sources_num;
362  mapit->indices_src = BLI_memarena_alloc(mem,
363  sizeof(*mapit->indices_src) * (size_t)sources_num);
364  memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num);
365  mapit->weights_src = BLI_memarena_alloc(mem,
366  sizeof(*mapit->weights_src) * (size_t)sources_num);
367  memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num);
368  }
369  else {
370  mapit->sources_num = 0;
371  mapit->indices_src = NULL;
372  mapit->weights_src = NULL;
373  }
374  /* UNUSED */
375  // mapit->hit_dist = hit_dist;
376  mapit->island = island;
377 }
378 
380 {
381  mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL);
382 }
383 
385  MLoop *mloops,
386  const float (*vcos_src)[3],
387  const float point[3],
388  size_t *buff_size,
389  float (**vcos)[3],
390  const bool use_loops,
391  int **indices,
392  float **weights,
393  const bool do_weights,
394  int *r_closest_index)
395 {
396  MLoop *ml;
397  float(*vco)[3];
398  float ref_dist_sq = FLT_MAX;
399  int *index;
400  const int sources_num = mp->totloop;
401  int i;
402 
403  if ((size_t)sources_num > *buff_size) {
404  *buff_size = (size_t)sources_num;
405  *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size);
406  *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size);
407  if (do_weights) {
408  *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size);
409  }
410  }
411 
412  for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num;
413  i++, ml++, vco++, index++) {
414  *index = use_loops ? (int)mp->loopstart + i : (int)ml->v;
415  copy_v3_v3(*vco, vcos_src[ml->v]);
416  if (r_closest_index) {
417  /* Find closest vert/loop in this case. */
418  const float dist_sq = len_squared_v3v3(point, *vco);
419  if (dist_sq < ref_dist_sq) {
420  ref_dist_sq = dist_sq;
421  *r_closest_index = *index;
422  }
423  }
424  }
425 
426  if (do_weights) {
427  interp_weights_poly_v3(*weights, *vcos, sources_num, point);
428  }
429 
430  return sources_num;
431 }
432 
434 typedef struct IslandResult {
436  float factor;
440  float hit_dist;
442  float hit_point[3];
444 
461 /* At most n raycasts per 'real' ray. */
462 #define MREMAP_RAYCAST_APPROXIMATE_NR 3
463 /* Each approximated raycasts will have n times bigger radius than previous one. */
464 #define MREMAP_RAYCAST_APPROXIMATE_FAC 5.0f
465 
466 /* min 16 rays/face, max 400. */
467 #define MREMAP_RAYCAST_TRI_SAMPLES_MIN 4
468 #define MREMAP_RAYCAST_TRI_SAMPLES_MAX 20
469 
470 /* Will be enough in 99% of cases. */
471 #define MREMAP_DEFAULT_BUFSIZE 32
472 
474  const SpaceTransform *space_transform,
475  const float max_dist,
476  const float ray_radius,
477  const MVert *verts_dst,
478  const int numverts_dst,
479  const bool UNUSED(dirty_nors_dst),
480  Mesh *me_src,
481  Mesh *me_dst,
482  MeshPairRemap *r_map)
483 {
484  const float full_weight = 1.0f;
485  const float max_dist_sq = max_dist * max_dist;
486  int i;
487 
489 
490  BKE_mesh_remap_init(r_map, numverts_dst);
491 
492  if (mode == MREMAP_MODE_TOPOLOGY) {
493  BLI_assert(numverts_dst == me_src->totvert);
494  for (i = 0; i < numverts_dst; i++) {
495  mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
496  }
497  }
498  else {
499  BVHTreeFromMesh treedata = {NULL};
500  BVHTreeNearest nearest = {0};
501  BVHTreeRayHit rayhit = {0};
502  float hit_dist;
503  float tmp_co[3], tmp_no[3];
504 
505  if (mode == MREMAP_MODE_VERT_NEAREST) {
506  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
507  nearest.index = -1;
508 
509  for (i = 0; i < numverts_dst; i++) {
510  copy_v3_v3(tmp_co, verts_dst[i].co);
511 
512  /* Convert the vertex to tree coordinates, if needed. */
513  if (space_transform) {
514  BLI_space_transform_apply(space_transform, tmp_co);
515  }
516 
518  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
519  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
520  }
521  else {
522  /* No source for this dest vertex! */
524  }
525  }
526  }
528  MEdge *edges_src = me_src->medge;
529  float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
530 
531  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
532  nearest.index = -1;
533 
534  for (i = 0; i < numverts_dst; i++) {
535  copy_v3_v3(tmp_co, verts_dst[i].co);
536 
537  /* Convert the vertex to tree coordinates, if needed. */
538  if (space_transform) {
539  BLI_space_transform_apply(space_transform, tmp_co);
540  }
541 
543  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
544  MEdge *me = &edges_src[nearest.index];
545  const float *v1cos = vcos_src[me->v1];
546  const float *v2cos = vcos_src[me->v2];
547 
548  if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) {
549  const float dist_v1 = len_squared_v3v3(tmp_co, v1cos);
550  const float dist_v2 = len_squared_v3v3(tmp_co, v2cos);
551  const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1);
552  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
553  }
554  else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) {
555  int indices[2];
556  float weights[2];
557 
558  indices[0] = (int)me->v1;
559  indices[1] = (int)me->v2;
560 
561  /* Weight is inverse of point factor here... */
562  weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos);
563  CLAMP(weights[0], 0.0f, 1.0f);
564  weights[1] = 1.0f - weights[0];
565 
566  mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights);
567  }
568  }
569  else {
570  /* No source for this dest vertex! */
572  }
573  }
574 
575  MEM_freeN(vcos_src);
576  }
577  else if (ELEM(mode,
581  MPoly *polys_src = me_src->mpoly;
582  MLoop *loops_src = me_src->mloop;
583  float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
584  const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_dst);
585 
586  size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
587  float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
588  int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
589  float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
590 
591  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
592 
594  for (i = 0; i < numverts_dst; i++) {
595  copy_v3_v3(tmp_co, verts_dst[i].co);
596  copy_v3_v3(tmp_no, vert_normals_dst[i]);
597 
598  /* Convert the vertex to tree coordinates, if needed. */
599  if (space_transform) {
600  BLI_space_transform_apply(space_transform, tmp_co);
601  BLI_space_transform_apply_normal(space_transform, tmp_no);
602  }
603 
605  &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) {
606  const MLoopTri *lt = &treedata.looptri[rayhit.index];
607  MPoly *mp_src = &polys_src[lt->poly];
608  const int sources_num = mesh_remap_interp_poly_data_get(mp_src,
609  loops_src,
610  (const float(*)[3])vcos_src,
611  rayhit.co,
612  &tmp_buff_size,
613  &vcos,
614  false,
615  &indices,
616  &weights,
617  true,
618  NULL);
619 
620  mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
621  }
622  else {
623  /* No source for this dest vertex! */
625  }
626  }
627  }
628  else {
629  nearest.index = -1;
630 
631  for (i = 0; i < numverts_dst; i++) {
632  copy_v3_v3(tmp_co, verts_dst[i].co);
633 
634  /* Convert the vertex to tree coordinates, if needed. */
635  if (space_transform) {
636  BLI_space_transform_apply(space_transform, tmp_co);
637  }
638 
640  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
641  const MLoopTri *lt = &treedata.looptri[nearest.index];
642  MPoly *mp = &polys_src[lt->poly];
643 
644  if (mode == MREMAP_MODE_VERT_POLY_NEAREST) {
645  int index;
647  loops_src,
648  (const float(*)[3])vcos_src,
649  nearest.co,
650  &tmp_buff_size,
651  &vcos,
652  false,
653  &indices,
654  &weights,
655  false,
656  &index);
657 
658  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
659  }
660  else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) {
661  const int sources_num = mesh_remap_interp_poly_data_get(mp,
662  loops_src,
663  (const float(*)[3])vcos_src,
664  nearest.co,
665  &tmp_buff_size,
666  &vcos,
667  false,
668  &indices,
669  &weights,
670  true,
671  NULL);
672 
673  mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
674  }
675  }
676  else {
677  /* No source for this dest vertex! */
679  }
680  }
681  }
682 
683  MEM_freeN(vcos_src);
684  MEM_freeN(vcos);
686  MEM_freeN(weights);
687  }
688  else {
689  CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode);
690  memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst);
691  }
692 
693  free_bvhtree_from_mesh(&treedata);
694  }
695 }
696 
698  const SpaceTransform *space_transform,
699  const float max_dist,
700  const float ray_radius,
701  const MVert *verts_dst,
702  const int numverts_dst,
703  const MEdge *edges_dst,
704  const int numedges_dst,
705  const bool UNUSED(dirty_nors_dst),
706  Mesh *me_src,
707  Mesh *me_dst,
708  MeshPairRemap *r_map)
709 {
710  const float full_weight = 1.0f;
711  const float max_dist_sq = max_dist * max_dist;
712  int i;
713 
715 
716  BKE_mesh_remap_init(r_map, numedges_dst);
717 
718  if (mode == MREMAP_MODE_TOPOLOGY) {
719  BLI_assert(numedges_dst == me_src->totedge);
720  for (i = 0; i < numedges_dst; i++) {
721  mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
722  }
723  }
724  else {
725  BVHTreeFromMesh treedata = {NULL};
726  BVHTreeNearest nearest = {0};
727  BVHTreeRayHit rayhit = {0};
728  float hit_dist;
729  float tmp_co[3], tmp_no[3];
730 
731  if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
732  const int num_verts_src = me_src->totvert;
733  const int num_edges_src = me_src->totedge;
734  MEdge *edges_src = me_src->medge;
735  float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
736 
737  MeshElemMap *vert_to_edge_src_map;
738  int *vert_to_edge_src_map_mem;
739 
740  struct {
741  float hit_dist;
742  int index;
743  } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst,
744  __func__);
745 
746  for (i = 0; i < numverts_dst; i++) {
747  v_dst_to_src_map[i].hit_dist = -1.0f;
748  }
749 
750  BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map,
751  &vert_to_edge_src_map_mem,
752  edges_src,
753  num_verts_src,
754  num_edges_src);
755 
756  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
757  nearest.index = -1;
758 
759  for (i = 0; i < numedges_dst; i++) {
760  const MEdge *e_dst = &edges_dst[i];
761  float best_totdist = FLT_MAX;
762  int best_eidx_src = -1;
763  int j = 2;
764 
765  while (j--) {
766  const uint vidx_dst = j ? e_dst->v1 : e_dst->v2;
767 
768  /* Compute closest verts only once! */
769  if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
770  copy_v3_v3(tmp_co, verts_dst[vidx_dst].co);
771 
772  /* Convert the vertex to tree coordinates, if needed. */
773  if (space_transform) {
774  BLI_space_transform_apply(space_transform, tmp_co);
775  }
776 
778  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
779  v_dst_to_src_map[vidx_dst].hit_dist = hit_dist;
780  v_dst_to_src_map[vidx_dst].index = nearest.index;
781  }
782  else {
783  /* No source for this dest vert! */
784  v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX;
785  }
786  }
787  }
788 
789  /* Now, check all source edges of closest sources vertices,
790  * and select the one giving the smallest total verts-to-verts distance. */
791  for (j = 2; j--;) {
792  const uint vidx_dst = j ? e_dst->v1 : e_dst->v2;
793  const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist;
794  const int vidx_src = v_dst_to_src_map[vidx_dst].index;
795  int *eidx_src, k;
796 
797  if (vidx_src < 0) {
798  continue;
799  }
800 
801  eidx_src = vert_to_edge_src_map[vidx_src].indices;
802  k = vert_to_edge_src_map[vidx_src].count;
803 
804  for (; k--; eidx_src++) {
805  MEdge *e_src = &edges_src[*eidx_src];
806  const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)];
807  const float *other_co_dst =
808  verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co;
809  const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst);
810 
811  if (totdist < best_totdist) {
812  best_totdist = totdist;
813  best_eidx_src = *eidx_src;
814  }
815  }
816  }
817 
818  if (best_eidx_src >= 0) {
819  const float *co1_src = vcos_src[edges_src[best_eidx_src].v1];
820  const float *co2_src = vcos_src[edges_src[best_eidx_src].v2];
821  const float *co1_dst = verts_dst[e_dst->v1].co;
822  const float *co2_dst = verts_dst[e_dst->v2].co;
823  float co_src[3], co_dst[3];
824 
825  /* TODO: would need an isect_seg_seg_v3(), actually! */
826  const int isect_type = isect_line_line_v3(
827  co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst);
828  if (isect_type != 0) {
829  const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src);
830  const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst);
831  if (fac_src < 0.0f) {
832  copy_v3_v3(co_src, co1_src);
833  }
834  else if (fac_src > 1.0f) {
835  copy_v3_v3(co_src, co2_src);
836  }
837  if (fac_dst < 0.0f) {
838  copy_v3_v3(co_dst, co1_dst);
839  }
840  else if (fac_dst > 1.0f) {
841  copy_v3_v3(co_dst, co2_dst);
842  }
843  }
844  hit_dist = len_v3v3(co_dst, co_src);
845  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
846  }
847  else {
848  /* No source for this dest edge! */
850  }
851  }
852 
853  MEM_freeN(vcos_src);
854  MEM_freeN(v_dst_to_src_map);
855  MEM_freeN(vert_to_edge_src_map);
856  MEM_freeN(vert_to_edge_src_map_mem);
857  }
858  else if (mode == MREMAP_MODE_EDGE_NEAREST) {
859  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
860  nearest.index = -1;
861 
862  for (i = 0; i < numedges_dst; i++) {
863  interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
864 
865  /* Convert the vertex to tree coordinates, if needed. */
866  if (space_transform) {
867  BLI_space_transform_apply(space_transform, tmp_co);
868  }
869 
871  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
872  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
873  }
874  else {
875  /* No source for this dest edge! */
877  }
878  }
879  }
880  else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
881  MEdge *edges_src = me_src->medge;
882  MPoly *polys_src = me_src->mpoly;
883  MLoop *loops_src = me_src->mloop;
884  float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
885 
886  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
887 
888  for (i = 0; i < numedges_dst; i++) {
889  interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
890 
891  /* Convert the vertex to tree coordinates, if needed. */
892  if (space_transform) {
893  BLI_space_transform_apply(space_transform, tmp_co);
894  }
895 
897  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
898  const MLoopTri *lt = &treedata.looptri[nearest.index];
899  MPoly *mp_src = &polys_src[lt->poly];
900  MLoop *ml_src = &loops_src[mp_src->loopstart];
901  int nloops = mp_src->totloop;
902  float best_dist_sq = FLT_MAX;
903  int best_eidx_src = -1;
904 
905  for (; nloops--; ml_src++) {
906  MEdge *med_src = &edges_src[ml_src->e];
907  float *co1_src = vcos_src[med_src->v1];
908  float *co2_src = vcos_src[med_src->v2];
909  float co_src[3];
910  float dist_sq;
911 
912  interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f);
913  dist_sq = len_squared_v3v3(tmp_co, co_src);
914  if (dist_sq < best_dist_sq) {
915  best_dist_sq = dist_sq;
916  best_eidx_src = (int)ml_src->e;
917  }
918  }
919  if (best_eidx_src >= 0) {
920  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
921  }
922  }
923  else {
924  /* No source for this dest edge! */
926  }
927  }
928 
929  MEM_freeN(vcos_src);
930  }
931  else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
932  const int num_rays_min = 5, num_rays_max = 100;
933  const int numedges_src = me_src->totedge;
934 
935  /* Subtleness - this one we can allocate only max number of cast rays per edges! */
936  int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max),
937  __func__);
938  /* Here it's simpler to just allocate for all edges :/ */
939  float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
940 
941  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
942 
943  const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_dst);
944 
945  for (i = 0; i < numedges_dst; i++) {
946  /* For each dst edge, we sample some rays from it (interpolated from its vertices)
947  * and use their hits to interpolate from source edges. */
948  const MEdge *me = &edges_dst[i];
949  float v1_co[3], v2_co[3];
950  float v1_no[3], v2_no[3];
951 
952  int grid_size;
953  float edge_dst_len;
954  float grid_step;
955 
956  float totweights = 0.0f;
957  float hit_dist_accum = 0.0f;
958  int sources_num = 0;
959  int j;
960 
961  copy_v3_v3(v1_co, verts_dst[me->v1].co);
962  copy_v3_v3(v2_co, verts_dst[me->v2].co);
963 
964  copy_v3_v3(v1_no, vert_normals_dst[me->v1]);
965  copy_v3_v3(v2_no, vert_normals_dst[me->v2]);
966 
967  /* We do our transform here, allows to interpolate from normals already in src space. */
968  if (space_transform) {
969  BLI_space_transform_apply(space_transform, v1_co);
970  BLI_space_transform_apply(space_transform, v2_co);
971  BLI_space_transform_apply_normal(space_transform, v1_no);
972  BLI_space_transform_apply_normal(space_transform, v2_no);
973  }
974 
975  copy_vn_fl(weights, (int)numedges_src, 0.0f);
976 
977  /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
978  * with lower/upper bounds. */
979  edge_dst_len = len_v3v3(v1_co, v2_co);
980 
981  grid_size = (int)((edge_dst_len / ray_radius) + 0.5f);
982  CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */
983 
984  grid_step = 1.0f /
985  (float)grid_size; /* Not actual distance here, rather an interp fac... */
986 
987  /* And now we can cast all our rays, and see what we get! */
988  for (j = 0; j < grid_size; j++) {
989  const float fac = grid_step * (float)j;
990 
991  int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
992  float w = 1.0f;
993 
994  interp_v3_v3v3(tmp_co, v1_co, v2_co, fac);
995  interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac);
996 
997  while (n--) {
999  &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
1000  weights[rayhit.index] += w;
1001  totweights += w;
1002  hit_dist_accum += hit_dist;
1003  break;
1004  }
1005  /* Next iteration will get bigger radius but smaller weight! */
1007  }
1008  }
1009  /* A sampling is valid (as in, its result can be considered as valid sources)
1010  * only if at least half of the rays found a source! */
1011  if (totweights > ((float)grid_size / 2.0f)) {
1012  for (j = 0; j < (int)numedges_src; j++) {
1013  if (!weights[j]) {
1014  continue;
1015  }
1016  /* NOTE: sources_num is always <= j! */
1017  weights[sources_num] = weights[j] / totweights;
1018  indices[sources_num] = j;
1019  sources_num++;
1020  }
1022  r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
1023  }
1024  else {
1025  /* No source for this dest edge! */
1027  }
1028  }
1029 
1030  MEM_freeN(indices);
1031  MEM_freeN(weights);
1032  }
1033  else {
1034  CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode);
1035  memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst);
1036  }
1037 
1038  free_bvhtree_from_mesh(&treedata);
1039  }
1040 }
1041 
1042 #define POLY_UNSET 0
1043 #define POLY_CENTER_INIT 1
1044 #define POLY_COMPLETE 2
1045 
1047  const int island_index,
1048  BLI_AStarGraph *as_graph,
1049  MVert *verts,
1050  MPoly *polys,
1051  MLoop *loops,
1052  const int edge_idx,
1053  BLI_bitmap *done_edges,
1054  MeshElemMap *edge_to_poly_map,
1055  const bool is_edge_innercut,
1056  const int *poly_island_index_map,
1057  float (*poly_centers)[3],
1058  unsigned char *poly_status)
1059 {
1060  int *poly_island_indices = BLI_array_alloca(poly_island_indices,
1061  (size_t)edge_to_poly_map[edge_idx].count);
1062  int i, j;
1063 
1064  for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) {
1065  const int pidx = edge_to_poly_map[edge_idx].indices[i];
1066  MPoly *mp = &polys[pidx];
1067  const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx;
1068  void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1);
1069 
1070  if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) {
1071  /* poly not in current island, happens with border edges... */
1072  poly_island_indices[i] = -1;
1073  continue;
1074  }
1075 
1076  if (poly_status[pidx_isld] == POLY_COMPLETE) {
1077  poly_island_indices[i] = pidx_isld;
1078  continue;
1079  }
1080 
1081  if (poly_status[pidx_isld] == POLY_UNSET) {
1082  BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]);
1083  BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]);
1084  poly_status[pidx_isld] = POLY_CENTER_INIT;
1085  }
1086 
1087  for (j = i; j--;) {
1088  float dist_cost;
1089  const int pidx_isld_other = poly_island_indices[j];
1090 
1091  if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) {
1092  /* If the other poly is complete, that link has already been added! */
1093  continue;
1094  }
1095  dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]);
1096  BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data);
1097  }
1098 
1099  poly_island_indices[i] = pidx_isld;
1100  }
1101 
1102  BLI_BITMAP_ENABLE(done_edges, edge_idx);
1103 }
1104 
1106  const int island_index,
1107  MVert *verts,
1108  MeshElemMap *edge_to_poly_map,
1109  const int numedges,
1110  MLoop *loops,
1111  MPoly *polys,
1112  const int numpolys,
1113  BLI_AStarGraph *r_as_graph)
1114 {
1115  MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL;
1116  MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL;
1117 
1118  int *poly_island_index_map = NULL;
1119  BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__);
1120 
1121  const int node_num = islands ? island_poly_map->count : numpolys;
1122  unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__);
1123  float(*poly_centers)[3];
1124 
1125  int pidx_isld;
1126  int i;
1127 
1128  BLI_astar_graph_init(r_as_graph, node_num, NULL);
1129  /* poly_centers is owned by graph memarena. */
1130  poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num);
1131 
1132  if (islands) {
1133  /* poly_island_index_map is owned by graph memarena. */
1134  poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem,
1135  sizeof(*poly_island_index_map) * (size_t)numpolys);
1136  for (i = island_poly_map->count; i--;) {
1137  poly_island_index_map[island_poly_map->indices[i]] = i;
1138  }
1139 
1140  r_as_graph->custom_data = poly_island_index_map;
1141 
1142  for (i = island_einnercut_map->count; i--;) {
1144  island_index,
1145  r_as_graph,
1146  verts,
1147  polys,
1148  loops,
1149  island_einnercut_map->indices[i],
1150  done_edges,
1151  edge_to_poly_map,
1152  true,
1153  poly_island_index_map,
1154  poly_centers,
1155  poly_status);
1156  }
1157  }
1158 
1159  for (pidx_isld = node_num; pidx_isld--;) {
1160  const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld;
1161  MPoly *mp = &polys[pidx];
1162  int pl_idx, l_idx;
1163 
1164  if (poly_status[pidx_isld] == POLY_COMPLETE) {
1165  continue;
1166  }
1167 
1168  for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) {
1169  MLoop *ml = &loops[l_idx];
1170 
1171  if (BLI_BITMAP_TEST(done_edges, ml->e)) {
1172  continue;
1173  }
1174 
1176  island_index,
1177  r_as_graph,
1178  verts,
1179  polys,
1180  loops,
1181  (int)ml->e,
1182  done_edges,
1183  edge_to_poly_map,
1184  false,
1185  poly_island_index_map,
1186  poly_centers,
1187  poly_status);
1188  }
1189  poly_status[pidx_isld] = POLY_COMPLETE;
1190  }
1191 
1192  MEM_freeN(done_edges);
1193  MEM_freeN(poly_status);
1194 }
1195 
1196 #undef POLY_UNSET
1197 #undef POLY_CENTER_INIT
1198 #undef POLY_COMPLETE
1199 
1200 /* Our 'f_cost' callback func, to find shortest poly-path between two remapped-loops.
1201  * Note we do not want to make innercuts 'walls' here,
1202  * just detect when the shortest path goes by those. */
1204  BLI_AStarSolution *as_solution,
1205  BLI_AStarGNLink *link,
1206  const int node_idx_curr,
1207  const int node_idx_next,
1208  const int node_idx_dst)
1209 {
1210  float *co_next, *co_dest;
1211 
1212  if (link && (POINTER_AS_INT(link->custom_data) != -1)) {
1213  /* An innercut edge... We tag our solution as potentially crossing innercuts.
1214  * Note it might not be the case in the end (AStar will explore around optimal path), but helps
1215  * trimming off some processing later... */
1216  if (!POINTER_AS_INT(as_solution->custom_data)) {
1217  as_solution->custom_data = POINTER_FROM_INT(true);
1218  }
1219  }
1220 
1221  /* Our heuristic part of current f_cost is distance from next node to destination one.
1222  * It is guaranteed to be less than (or equal to)
1223  * actual shortest poly-path between next node and destination one. */
1224  co_next = (float *)as_graph->nodes[node_idx_next].custom_data;
1225  co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data;
1226  return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) +
1227  len_v3v3(co_next, co_dest);
1228 }
1229 
1230 #define ASTAR_STEPS_MAX 64
1231 
1233  const SpaceTransform *space_transform,
1234  const float max_dist,
1235  const float ray_radius,
1236  Mesh *mesh_dst,
1237  MVert *verts_dst,
1238  const int numverts_dst,
1239  MEdge *edges_dst,
1240  const int numedges_dst,
1241  MLoop *loops_dst,
1242  const int numloops_dst,
1243  MPoly *polys_dst,
1244  const int numpolys_dst,
1245  CustomData *ldata_dst,
1246  const bool use_split_nors_dst,
1247  const float split_angle_dst,
1248  const bool dirty_nors_dst,
1249  Mesh *me_src,
1250  MeshRemapIslandsCalc gen_islands_src,
1251  const float islands_precision_src,
1252  MeshPairRemap *r_map)
1253 {
1254  const float full_weight = 1.0f;
1255  const float max_dist_sq = max_dist * max_dist;
1256 
1257  int i;
1258 
1259  BLI_assert(mode & MREMAP_MODE_LOOP);
1260  BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f));
1261 
1262  BKE_mesh_remap_init(r_map, numloops_dst);
1263 
1264  if (mode == MREMAP_MODE_TOPOLOGY) {
1265  /* In topology mapping, we assume meshes are identical, islands included! */
1266  BLI_assert(numloops_dst == me_src->totloop);
1267  for (i = 0; i < numloops_dst; i++) {
1268  mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
1269  }
1270  }
1271  else {
1272  BVHTreeFromMesh *treedata = NULL;
1273  BVHTreeNearest nearest = {0};
1274  BVHTreeRayHit rayhit = {0};
1275  int num_trees = 0;
1276  float hit_dist;
1277  float tmp_co[3], tmp_no[3];
1278 
1279  const bool use_from_vert = (mode & MREMAP_USE_VERT);
1280 
1281  MeshIslandStore island_store = {0};
1282  bool use_islands = false;
1283 
1284  BLI_AStarGraph *as_graphdata = NULL;
1285  BLI_AStarSolution as_solution = {0};
1286  const int isld_steps_src = (islands_precision_src ?
1287  max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f),
1288  1) :
1289  0);
1290 
1291  const float(*poly_nors_src)[3] = NULL;
1292  const float(*loop_nors_src)[3] = NULL;
1293  const float(*poly_nors_dst)[3] = NULL;
1294  float(*loop_nors_dst)[3] = NULL;
1295 
1296  float(*poly_cents_src)[3] = NULL;
1297 
1298  MeshElemMap *vert_to_loop_map_src = NULL;
1299  int *vert_to_loop_map_src_buff = NULL;
1300  MeshElemMap *vert_to_poly_map_src = NULL;
1301  int *vert_to_poly_map_src_buff = NULL;
1302  MeshElemMap *edge_to_poly_map_src = NULL;
1303  int *edge_to_poly_map_src_buff = NULL;
1304  MeshElemMap *poly_to_looptri_map_src = NULL;
1305  int *poly_to_looptri_map_src_buff = NULL;
1306 
1307  /* Unlike above, those are one-to-one mappings, simpler! */
1308  int *loop_to_poly_map_src = NULL;
1309 
1310  MVert *verts_src = me_src->mvert;
1311  const int num_verts_src = me_src->totvert;
1312  float(*vcos_src)[3] = NULL;
1313  MEdge *edges_src = me_src->medge;
1314  const int num_edges_src = me_src->totedge;
1315  MLoop *loops_src = me_src->mloop;
1316  const int num_loops_src = me_src->totloop;
1317  MPoly *polys_src = me_src->mpoly;
1318  const int num_polys_src = me_src->totpoly;
1319  const MLoopTri *looptri_src = NULL;
1320  int num_looptri_src = 0;
1321 
1322  size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
1323  float(*vcos_interp)[3] = NULL;
1324  int *indices_interp = NULL;
1325  float *weights_interp = NULL;
1326 
1327  MLoop *ml_src, *ml_dst;
1328  MPoly *mp_src, *mp_dst;
1329  int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
1330 
1331  IslandResult **islands_res;
1332  size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
1333 
1334  if (!use_from_vert) {
1335  vcos_src = BKE_mesh_vert_coords_alloc(me_src, NULL);
1336 
1337  vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
1338  indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
1339  weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__);
1340  }
1341 
1342  {
1343  const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL);
1344  const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ);
1345  const bool need_pnors_src = need_lnors_src ||
1346  ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL));
1347  const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
1348 
1349  if (need_pnors_dst) {
1350  poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
1351  }
1352  if (need_lnors_dst) {
1353  short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
1354 
1355  /* Cache loop normals into a temporary custom data layer. */
1356  loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
1357  const bool do_loop_nors_dst = (loop_nors_dst == NULL);
1358  if (!loop_nors_dst) {
1359  loop_nors_dst = CustomData_add_layer(
1360  ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
1362  }
1363  if (dirty_nors_dst || do_loop_nors_dst) {
1364  BKE_mesh_normals_loop_split(verts_dst,
1366  numverts_dst,
1367  edges_dst,
1368  numedges_dst,
1369  loops_dst,
1370  loop_nors_dst,
1371  numloops_dst,
1372  polys_dst,
1373  poly_nors_dst,
1374  numpolys_dst,
1375  use_split_nors_dst,
1376  split_angle_dst,
1377  NULL,
1378  custom_nors_dst,
1379  NULL);
1380  }
1381  }
1382  if (need_pnors_src || need_lnors_src) {
1383  if (need_pnors_src) {
1384  poly_nors_src = BKE_mesh_poly_normals_ensure(me_src);
1385  }
1386  if (need_lnors_src) {
1387  loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
1388  BLI_assert(loop_nors_src != NULL);
1389  }
1390  }
1391  }
1392 
1393  if (use_from_vert) {
1394  BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src,
1395  &vert_to_loop_map_src_buff,
1396  polys_src,
1397  loops_src,
1398  num_verts_src,
1399  num_polys_src,
1400  num_loops_src);
1401  if (mode & MREMAP_USE_POLY) {
1402  BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src,
1403  &vert_to_poly_map_src_buff,
1404  polys_src,
1405  loops_src,
1406  num_verts_src,
1407  num_polys_src,
1408  num_loops_src);
1409  }
1410  }
1411 
1412  /* Needed for islands (or plain mesh) to AStar graph conversion. */
1413  BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src,
1414  &edge_to_poly_map_src_buff,
1415  edges_src,
1416  num_edges_src,
1417  polys_src,
1418  num_polys_src,
1419  loops_src,
1420  num_loops_src);
1421  if (use_from_vert) {
1422  loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src,
1423  __func__);
1424  poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
1425  for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
1426  ml_src = &loops_src[mp_src->loopstart];
1427  for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop;
1428  plidx_src++, lidx_src++) {
1429  loop_to_poly_map_src[lidx_src] = pidx_src;
1430  }
1431  BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
1432  }
1433  }
1434 
1435  /* Island makes things slightly more complex here.
1436  * Basically, we:
1437  * * Make one treedata for each island's elements.
1438  * * Check all loops of a same dest poly against all treedata.
1439  * * Choose the island's elements giving the best results.
1440  */
1441 
1442  /* First, generate the islands, if possible. */
1443  if (gen_islands_src) {
1444  use_islands = gen_islands_src(verts_src,
1445  num_verts_src,
1446  edges_src,
1447  num_edges_src,
1448  polys_src,
1449  num_polys_src,
1450  loops_src,
1451  num_loops_src,
1452  &island_store);
1453 
1454  num_trees = use_islands ? island_store.islands_num : 1;
1455  treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__);
1456  if (isld_steps_src) {
1457  as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__);
1458  }
1459 
1460  if (use_islands) {
1461  /* We expect our islands to contain poly indices, with edge indices of 'inner cuts',
1462  * and a mapping loops -> islands indices.
1463  * This implies all loops of a same poly are in the same island. */
1464  BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) &&
1465  (island_store.island_type == MISLAND_TYPE_POLY) &&
1466  (island_store.innercut_type == MISLAND_TYPE_EDGE));
1467  }
1468  }
1469  else {
1470  num_trees = 1;
1471  treedata = MEM_callocN(sizeof(*treedata), __func__);
1472  if (isld_steps_src) {
1473  as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__);
1474  }
1475  }
1476 
1477  /* Build our AStar graphs. */
1478  if (isld_steps_src) {
1479  for (tindex = 0; tindex < num_trees; tindex++) {
1480  mesh_island_to_astar_graph(use_islands ? &island_store : NULL,
1481  tindex,
1482  verts_src,
1483  edge_to_poly_map_src,
1484  num_edges_src,
1485  loops_src,
1486  polys_src,
1487  num_polys_src,
1488  &as_graphdata[tindex]);
1489  }
1490  }
1491 
1492  /* Build our BVHtrees, either from verts or tessfaces. */
1493  if (use_from_vert) {
1494  if (use_islands) {
1495  BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__);
1496 
1497  for (tindex = 0; tindex < num_trees; tindex++) {
1498  MeshElemMap *isld = island_store.islands[tindex];
1499  int num_verts_active = 0;
1500  BLI_bitmap_set_all(verts_active, false, (size_t)num_verts_src);
1501  for (i = 0; i < isld->count; i++) {
1502  mp_src = &polys_src[isld->indices[i]];
1503  for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop;
1504  lidx_src++) {
1505  const uint vidx_src = loops_src[lidx_src].v;
1506  if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
1507  BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
1508  num_verts_active++;
1509  }
1510  }
1511  }
1512  bvhtree_from_mesh_verts_ex(&treedata[tindex],
1513  verts_src,
1514  num_verts_src,
1515  verts_active,
1516  num_verts_active,
1517  0.0,
1518  2,
1519  6);
1520  }
1521 
1522  MEM_freeN(verts_active);
1523  }
1524  else {
1525  BLI_assert(num_trees == 1);
1526  BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
1527  }
1528  }
1529  else { /* We use polygons. */
1530  if (use_islands) {
1531  /* bvhtree here uses looptri faces... */
1532  BLI_bitmap *looptri_active;
1533 
1534  looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
1535  num_looptri_src = me_src->runtime.looptris.len;
1536  looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
1537 
1538  for (tindex = 0; tindex < num_trees; tindex++) {
1539  int num_looptri_active = 0;
1540  BLI_bitmap_set_all(looptri_active, false, (size_t)num_looptri_src);
1541  for (i = 0; i < num_looptri_src; i++) {
1542  mp_src = &polys_src[looptri_src[i].poly];
1543  if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
1544  BLI_BITMAP_ENABLE(looptri_active, i);
1545  num_looptri_active++;
1546  }
1547  }
1548  bvhtree_from_mesh_looptri_ex(&treedata[tindex],
1549  verts_src,
1550  loops_src,
1551  looptri_src,
1552  num_looptri_src,
1553  looptri_active,
1554  num_looptri_active,
1555  0.0,
1556  2,
1557  6);
1558  }
1559 
1560  MEM_freeN(looptri_active);
1561  }
1562  else {
1563  BLI_assert(num_trees == 1);
1564  BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
1565  }
1566  }
1567 
1568  /* And check each dest poly! */
1569  islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__);
1570  for (tindex = 0; tindex < num_trees; tindex++) {
1571  islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
1572  }
1573 
1574  for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
1575  float pnor_dst[3];
1576 
1577  /* Only in use_from_vert case, we may need polys' centers as fallback
1578  * in case we cannot decide which corner to use from normals only. */
1579  float pcent_dst[3];
1580  bool pcent_dst_valid = false;
1581 
1582  if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
1583  copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]);
1584  if (space_transform) {
1585  BLI_space_transform_apply_normal(space_transform, pnor_dst);
1586  }
1587  }
1588 
1589  if ((size_t)mp_dst->totloop > islands_res_buff_size) {
1590  islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE;
1591  for (tindex = 0; tindex < num_trees; tindex++) {
1592  islands_res[tindex] = MEM_reallocN(islands_res[tindex],
1593  sizeof(**islands_res) * islands_res_buff_size);
1594  }
1595  }
1596 
1597  for (tindex = 0; tindex < num_trees; tindex++) {
1598  BVHTreeFromMesh *tdata = &treedata[tindex];
1599 
1600  ml_dst = &loops_dst[mp_dst->loopstart];
1601  for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
1602  if (use_from_vert) {
1603  MeshElemMap *vert_to_refelem_map_src = NULL;
1604 
1605  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1606  nearest.index = -1;
1607 
1608  /* Convert the vertex to tree coordinates, if needed. */
1609  if (space_transform) {
1610  BLI_space_transform_apply(space_transform, tmp_co);
1611  }
1612 
1614  tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
1615  float(*nor_dst)[3];
1616  const float(*nors_src)[3];
1617  float best_nor_dot = -2.0f;
1618  float best_sqdist_fallback = FLT_MAX;
1619  int best_index_src = -1;
1620 
1621  if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
1622  copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
1623  if (space_transform) {
1624  BLI_space_transform_apply_normal(space_transform, tmp_no);
1625  }
1626  nor_dst = &tmp_no;
1627  nors_src = loop_nors_src;
1628  vert_to_refelem_map_src = vert_to_loop_map_src;
1629  }
1630  else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
1631  nor_dst = &pnor_dst;
1632  nors_src = poly_nors_src;
1633  vert_to_refelem_map_src = vert_to_poly_map_src;
1634  }
1635 
1636  for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
1637  const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
1638  BLI_assert(index_src != -1);
1639  const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
1640 
1641  pidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
1642  loop_to_poly_map_src[index_src] :
1643  index_src);
1644  /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
1645  * to check we stay on current island (all loops from a given poly are
1646  * on same island!). */
1647  lidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
1648  index_src :
1649  polys_src[pidx_src].loopstart);
1650 
1651  /* A same vert may be at the boundary of several islands! Hence, we have to ensure
1652  * poly/loop we are currently considering *belongs* to current island! */
1653  if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
1654  continue;
1655  }
1656 
1657  if (dot > best_nor_dot - 1e-6f) {
1658  /* We need something as fallback decision in case dest normal matches several
1659  * source normals (see T44522), using distance between polys' centers here. */
1660  float *pcent_src;
1661  float sqdist;
1662 
1663  mp_src = &polys_src[pidx_src];
1664  ml_src = &loops_src[mp_src->loopstart];
1665 
1666  if (!pcent_dst_valid) {
1668  mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
1669  pcent_dst_valid = true;
1670  }
1671  pcent_src = poly_cents_src[pidx_src];
1672  sqdist = len_squared_v3v3(pcent_dst, pcent_src);
1673 
1674  if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
1675  best_nor_dot = dot;
1676  best_sqdist_fallback = sqdist;
1677  best_index_src = index_src;
1678  }
1679  }
1680  }
1681  if (best_index_src == -1) {
1682  /* We found no item to map back from closest vertex... */
1683  best_nor_dot = -1.0f;
1684  hit_dist = FLT_MAX;
1685  }
1686  else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
1687  /* Our best_index_src is a poly one for now!
1688  * Have to find its loop matching our closest vertex. */
1689  mp_src = &polys_src[best_index_src];
1690  ml_src = &loops_src[mp_src->loopstart];
1691  for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
1692  if ((int)ml_src->v == nearest.index) {
1693  best_index_src = plidx_src + mp_src->loopstart;
1694  break;
1695  }
1696  }
1697  }
1698  best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
1699  islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f;
1700  islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1701  islands_res[tindex][plidx_dst].index_src = best_index_src;
1702  }
1703  else {
1704  /* No source for this dest loop! */
1705  islands_res[tindex][plidx_dst].factor = 0.0f;
1706  islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1707  islands_res[tindex][plidx_dst].index_src = -1;
1708  }
1709  }
1710  else if (mode & MREMAP_USE_NORPROJ) {
1711  int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
1712  float w = 1.0f;
1713 
1714  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1715  copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
1716 
1717  /* We do our transform here, since we may do several raycast/nearest queries. */
1718  if (space_transform) {
1719  BLI_space_transform_apply(space_transform, tmp_co);
1720  BLI_space_transform_apply_normal(space_transform, tmp_no);
1721  }
1722 
1723  while (n--) {
1725  tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
1726  islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w;
1727  islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1728  islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[rayhit.index].poly;
1729  copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co);
1730  break;
1731  }
1732  /* Next iteration will get bigger radius but smaller weight! */
1734  }
1735  if (n == -1) {
1736  /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to
1737  * have only part of one dest face's loops to map to source.
1738  * Note that since we give this a null weight, if whole weight for a given face
1739  * is null, it means none of its loop mapped to this source island,
1740  * hence we can skip it later.
1741  */
1742  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1743  nearest.index = -1;
1744 
1745  /* Convert the vertex to tree coordinates, if needed. */
1746  if (space_transform) {
1747  BLI_space_transform_apply(space_transform, tmp_co);
1748  }
1749 
1750  /* In any case, this fallback nearest hit should have no weight at all
1751  * in 'best island' decision! */
1752  islands_res[tindex][plidx_dst].factor = 0.0f;
1753 
1755  tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
1756  islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1757  islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
1758  copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
1759  }
1760  else {
1761  /* No source for this dest loop! */
1762  islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1763  islands_res[tindex][plidx_dst].index_src = -1;
1764  }
1765  }
1766  }
1767  else { /* Nearest poly either to use all its loops/verts or just closest one. */
1768  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1769  nearest.index = -1;
1770 
1771  /* Convert the vertex to tree coordinates, if needed. */
1772  if (space_transform) {
1773  BLI_space_transform_apply(space_transform, tmp_co);
1774  }
1775 
1777  tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
1778  islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f;
1779  islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1780  islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
1781  copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
1782  }
1783  else {
1784  /* No source for this dest loop! */
1785  islands_res[tindex][plidx_dst].factor = 0.0f;
1786  islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1787  islands_res[tindex][plidx_dst].index_src = -1;
1788  }
1789  }
1790  }
1791  }
1792 
1793  /* And now, find best island to use! */
1794  /* We have to first select the 'best source island' for given dst poly and its loops.
1795  * Then, we have to check that poly does not 'spread' across some island's limits
1796  * (like inner seams for UVs, etc.).
1797  * Note we only still partially support that kind of situation here, i.e.
1798  * Polys spreading over actual cracks
1799  * (like a narrow space without faces on src, splitting a 'tube-like' geometry).
1800  * That kind of situation should be relatively rare, though.
1801  */
1802  /* XXX This block in itself is big and complex enough to be a separate function but...
1803  * it uses a bunch of locale vars.
1804  * Not worth sending all that through parameters (for now at least). */
1805  {
1806  BLI_AStarGraph *as_graph = NULL;
1807  int *poly_island_index_map = NULL;
1808  int pidx_src_prev = -1;
1809 
1810  MeshElemMap *best_island = NULL;
1811  float best_island_fac = 0.0f;
1812  int best_island_index = -1;
1813 
1814  for (tindex = 0; tindex < num_trees; tindex++) {
1815  float island_fac = 0.0f;
1816 
1817  for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
1818  island_fac += islands_res[tindex][plidx_dst].factor;
1819  }
1820  island_fac /= (float)mp_dst->totloop;
1821 
1822  if (island_fac > best_island_fac) {
1823  best_island_fac = island_fac;
1824  best_island_index = tindex;
1825  }
1826  }
1827 
1828  if (best_island_index != -1 && isld_steps_src) {
1829  best_island = use_islands ? island_store.islands[best_island_index] : NULL;
1830  as_graph = &as_graphdata[best_island_index];
1831  poly_island_index_map = (int *)as_graph->custom_data;
1832  BLI_astar_solution_init(as_graph, &as_solution, NULL);
1833  }
1834 
1835  for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
1836  IslandResult *isld_res;
1837  lidx_dst = plidx_dst + mp_dst->loopstart;
1838 
1839  if (best_island_index == -1) {
1840  /* No source for any loops of our dest poly in any source islands. */
1841  BKE_mesh_remap_item_define_invalid(r_map, lidx_dst);
1842  continue;
1843  }
1844 
1845  as_solution.custom_data = POINTER_FROM_INT(false);
1846 
1847  isld_res = &islands_res[best_island_index][plidx_dst];
1848  if (use_from_vert) {
1849  /* Indices stored in islands_res are those of loops, one per dest loop. */
1850  lidx_src = isld_res->index_src;
1851  if (lidx_src >= 0) {
1852  pidx_src = loop_to_poly_map_src[lidx_src];
1853  /* If prev and curr poly are the same, no need to do anything more!!! */
1854  if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
1855  int pidx_isld_src, pidx_isld_src_prev;
1856  if (poly_island_index_map) {
1857  pidx_isld_src = poly_island_index_map[pidx_src];
1858  pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
1859  }
1860  else {
1861  pidx_isld_src = pidx_src;
1862  pidx_isld_src_prev = pidx_src_prev;
1863  }
1864 
1865  BLI_astar_graph_solve(as_graph,
1866  pidx_isld_src_prev,
1867  pidx_isld_src,
1869  &as_solution,
1870  isld_steps_src);
1871  if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
1872  /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
1873  * before that edge.
1874  * Note we could try to be much smarter, g.g. Storing a whole poly's indices,
1875  * and making decision (on which side of cutting edge(s!) to be) on the end,
1876  * but this is one more level of complexity, better to first see if
1877  * simple solution works!
1878  */
1879  int last_valid_pidx_isld_src = -1;
1880  /* Note we go backward here, from dest to src poly. */
1881  for (i = as_solution.steps - 1; i--;) {
1882  BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
1883  const int eidx = POINTER_AS_INT(as_link->custom_data);
1884  pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
1885  BLI_assert(pidx_isld_src != -1);
1886  if (eidx != -1) {
1887  /* we are 'crossing' a cutting edge. */
1888  last_valid_pidx_isld_src = pidx_isld_src;
1889  }
1890  }
1891  if (last_valid_pidx_isld_src != -1) {
1892  /* Find a new valid loop in that new poly (nearest one for now).
1893  * Note we could be much more subtle here, again that's for later... */
1894  int j;
1895  float best_dist_sq = FLT_MAX;
1896 
1897  ml_dst = &loops_dst[lidx_dst];
1898  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1899 
1900  /* We do our transform here,
1901  * since we may do several raycast/nearest queries. */
1902  if (space_transform) {
1903  BLI_space_transform_apply(space_transform, tmp_co);
1904  }
1905 
1906  pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
1907  last_valid_pidx_isld_src);
1908  mp_src = &polys_src[pidx_src];
1909  ml_src = &loops_src[mp_src->loopstart];
1910  for (j = 0; j < mp_src->totloop; j++, ml_src++) {
1911  const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co);
1912  if (dist_sq < best_dist_sq) {
1913  best_dist_sq = dist_sq;
1914  lidx_src = mp_src->loopstart + j;
1915  }
1916  }
1917  }
1918  }
1919  }
1920  mesh_remap_item_define(r_map,
1921  lidx_dst,
1922  isld_res->hit_dist,
1923  best_island_index,
1924  1,
1925  &lidx_src,
1926  &full_weight);
1927  pidx_src_prev = pidx_src;
1928  }
1929  else {
1930  /* No source for this loop in this island. */
1931  /* TODO: would probably be better to get a source
1932  * at all cost in best island anyway? */
1933  mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL);
1934  }
1935  }
1936  else {
1937  /* Else, we use source poly, indices stored in islands_res are those of polygons. */
1938  pidx_src = isld_res->index_src;
1939  if (pidx_src >= 0) {
1940  float *hit_co = isld_res->hit_point;
1941  int best_loop_index_src;
1942 
1943  mp_src = &polys_src[pidx_src];
1944  /* If prev and curr poly are the same, no need to do anything more!!! */
1945  if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
1946  int pidx_isld_src, pidx_isld_src_prev;
1947  if (poly_island_index_map) {
1948  pidx_isld_src = poly_island_index_map[pidx_src];
1949  pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
1950  }
1951  else {
1952  pidx_isld_src = pidx_src;
1953  pidx_isld_src_prev = pidx_src_prev;
1954  }
1955 
1956  BLI_astar_graph_solve(as_graph,
1957  pidx_isld_src_prev,
1958  pidx_isld_src,
1960  &as_solution,
1961  isld_steps_src);
1962  if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
1963  /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
1964  * before that edge.
1965  * Note we could try to be much smarter: e.g. Storing a whole poly's indices,
1966  * and making decision (one which side of cutting edge(s)!) to be on the end,
1967  * but this is one more level of complexity, better to first see if
1968  * simple solution works!
1969  */
1970  int last_valid_pidx_isld_src = -1;
1971  /* Note we go backward here, from dest to src poly. */
1972  for (i = as_solution.steps - 1; i--;) {
1973  BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
1974  int eidx = POINTER_AS_INT(as_link->custom_data);
1975 
1976  pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
1977  BLI_assert(pidx_isld_src != -1);
1978  if (eidx != -1) {
1979  /* we are 'crossing' a cutting edge. */
1980  last_valid_pidx_isld_src = pidx_isld_src;
1981  }
1982  }
1983  if (last_valid_pidx_isld_src != -1) {
1984  /* Find a new valid loop in that new poly (nearest point on poly for now).
1985  * Note we could be much more subtle here, again that's for later... */
1986  float best_dist_sq = FLT_MAX;
1987  int j;
1988 
1989  ml_dst = &loops_dst[lidx_dst];
1990  copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
1991 
1992  /* We do our transform here,
1993  * since we may do several raycast/nearest queries. */
1994  if (space_transform) {
1995  BLI_space_transform_apply(space_transform, tmp_co);
1996  }
1997 
1998  pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
1999  last_valid_pidx_isld_src);
2000  mp_src = &polys_src[pidx_src];
2001 
2002  /* Create that one on demand. */
2003  if (poly_to_looptri_map_src == NULL) {
2004  BKE_mesh_origindex_map_create_looptri(&poly_to_looptri_map_src,
2005  &poly_to_looptri_map_src_buff,
2006  polys_src,
2007  num_polys_src,
2008  looptri_src,
2009  num_looptri_src);
2010  }
2011 
2012  for (j = poly_to_looptri_map_src[pidx_src].count; j--;) {
2013  float h[3];
2014  const MLoopTri *lt =
2015  &looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]];
2016  float dist_sq;
2017 
2019  tmp_co,
2020  vcos_src[loops_src[lt->tri[0]].v],
2021  vcos_src[loops_src[lt->tri[1]].v],
2022  vcos_src[loops_src[lt->tri[2]].v]);
2023  dist_sq = len_squared_v3v3(tmp_co, h);
2024  if (dist_sq < best_dist_sq) {
2025  copy_v3_v3(hit_co, h);
2026  best_dist_sq = dist_sq;
2027  }
2028  }
2029  }
2030  }
2031  }
2032 
2033  if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) {
2035  loops_src,
2036  (const float(*)[3])vcos_src,
2037  hit_co,
2038  &buff_size_interp,
2039  &vcos_interp,
2040  true,
2041  &indices_interp,
2042  &weights_interp,
2043  false,
2044  &best_loop_index_src);
2045 
2046  mesh_remap_item_define(r_map,
2047  lidx_dst,
2048  isld_res->hit_dist,
2049  best_island_index,
2050  1,
2051  &best_loop_index_src,
2052  &full_weight);
2053  }
2054  else {
2055  const int sources_num = mesh_remap_interp_poly_data_get(
2056  mp_src,
2057  loops_src,
2058  (const float(*)[3])vcos_src,
2059  hit_co,
2060  &buff_size_interp,
2061  &vcos_interp,
2062  true,
2063  &indices_interp,
2064  &weights_interp,
2065  true,
2066  NULL);
2067 
2068  mesh_remap_item_define(r_map,
2069  lidx_dst,
2070  isld_res->hit_dist,
2071  best_island_index,
2072  sources_num,
2073  indices_interp,
2074  weights_interp);
2075  }
2076 
2077  pidx_src_prev = pidx_src;
2078  }
2079  else {
2080  /* No source for this loop in this island. */
2081  /* TODO: would probably be better to get a source
2082  * at all cost in best island anyway? */
2083  mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL);
2084  }
2085  }
2086  }
2087 
2088  BLI_astar_solution_clear(&as_solution);
2089  }
2090  }
2091 
2092  for (tindex = 0; tindex < num_trees; tindex++) {
2093  MEM_freeN(islands_res[tindex]);
2094  free_bvhtree_from_mesh(&treedata[tindex]);
2095  if (isld_steps_src) {
2096  BLI_astar_graph_free(&as_graphdata[tindex]);
2097  }
2098  }
2099  MEM_freeN(islands_res);
2100  BKE_mesh_loop_islands_free(&island_store);
2101  MEM_freeN(treedata);
2102  if (isld_steps_src) {
2103  MEM_freeN(as_graphdata);
2104  BLI_astar_solution_free(&as_solution);
2105  }
2106 
2107  if (vcos_src) {
2108  MEM_freeN(vcos_src);
2109  }
2110  if (vert_to_loop_map_src) {
2111  MEM_freeN(vert_to_loop_map_src);
2112  }
2113  if (vert_to_loop_map_src_buff) {
2114  MEM_freeN(vert_to_loop_map_src_buff);
2115  }
2116  if (vert_to_poly_map_src) {
2117  MEM_freeN(vert_to_poly_map_src);
2118  }
2119  if (vert_to_poly_map_src_buff) {
2120  MEM_freeN(vert_to_poly_map_src_buff);
2121  }
2122  if (edge_to_poly_map_src) {
2123  MEM_freeN(edge_to_poly_map_src);
2124  }
2125  if (edge_to_poly_map_src_buff) {
2126  MEM_freeN(edge_to_poly_map_src_buff);
2127  }
2128  if (poly_to_looptri_map_src) {
2129  MEM_freeN(poly_to_looptri_map_src);
2130  }
2131  if (poly_to_looptri_map_src_buff) {
2132  MEM_freeN(poly_to_looptri_map_src_buff);
2133  }
2134  if (loop_to_poly_map_src) {
2135  MEM_freeN(loop_to_poly_map_src);
2136  }
2137  if (poly_cents_src) {
2138  MEM_freeN(poly_cents_src);
2139  }
2140  if (vcos_interp) {
2141  MEM_freeN(vcos_interp);
2142  }
2143  if (indices_interp) {
2144  MEM_freeN(indices_interp);
2145  }
2146  if (weights_interp) {
2147  MEM_freeN(weights_interp);
2148  }
2149  }
2150 }
2151 
2153  const SpaceTransform *space_transform,
2154  const float max_dist,
2155  const float ray_radius,
2156  Mesh *mesh_dst,
2157  MVert *verts_dst,
2158  MLoop *loops_dst,
2159  MPoly *polys_dst,
2160  const int numpolys_dst,
2161  Mesh *me_src,
2162  MeshPairRemap *r_map)
2163 {
2164  const float full_weight = 1.0f;
2165  const float max_dist_sq = max_dist * max_dist;
2166  const float(*poly_nors_dst)[3] = NULL;
2167  float tmp_co[3], tmp_no[3];
2168  int i;
2169 
2170  BLI_assert(mode & MREMAP_MODE_POLY);
2171 
2172  if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
2173  poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
2174  }
2175 
2176  BKE_mesh_remap_init(r_map, numpolys_dst);
2177 
2178  if (mode == MREMAP_MODE_TOPOLOGY) {
2179  BLI_assert(numpolys_dst == me_src->totpoly);
2180  for (i = 0; i < numpolys_dst; i++) {
2181  mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
2182  }
2183  }
2184  else {
2185  BVHTreeFromMesh treedata = {NULL};
2186  BVHTreeNearest nearest = {0};
2187  BVHTreeRayHit rayhit = {0};
2188  float hit_dist;
2189 
2190  BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
2191 
2192  if (mode == MREMAP_MODE_POLY_NEAREST) {
2193  nearest.index = -1;
2194 
2195  for (i = 0; i < numpolys_dst; i++) {
2196  MPoly *mp = &polys_dst[i];
2197 
2198  BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
2199 
2200  /* Convert the vertex to tree coordinates, if needed. */
2201  if (space_transform) {
2202  BLI_space_transform_apply(space_transform, tmp_co);
2203  }
2204 
2206  &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
2207  const MLoopTri *lt = &treedata.looptri[nearest.index];
2208  const int poly_index = (int)lt->poly;
2209  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight);
2210  }
2211  else {
2212  /* No source for this dest poly! */
2214  }
2215  }
2216  }
2217  else if (mode == MREMAP_MODE_POLY_NOR) {
2218  BLI_assert(poly_nors_dst);
2219 
2220  for (i = 0; i < numpolys_dst; i++) {
2221  MPoly *mp = &polys_dst[i];
2222 
2223  BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
2224  copy_v3_v3(tmp_no, poly_nors_dst[i]);
2225 
2226  /* Convert the vertex to tree coordinates, if needed. */
2227  if (space_transform) {
2228  BLI_space_transform_apply(space_transform, tmp_co);
2229  BLI_space_transform_apply_normal(space_transform, tmp_no);
2230  }
2231 
2233  &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) {
2234  const MLoopTri *lt = &treedata.looptri[rayhit.index];
2235  const int poly_index = (int)lt->poly;
2236 
2237  mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight);
2238  }
2239  else {
2240  /* No source for this dest poly! */
2242  }
2243  }
2244  }
2245  else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) {
2246  /* We cast our rays randomly, with a pseudo-even distribution
2247  * (since we spread across tessellated tris,
2248  * with additional weighting based on each tri's relative area).
2249  */
2250  RNG *rng = BLI_rng_new(0);
2251 
2252  const size_t numpolys_src = (size_t)me_src->totpoly;
2253 
2254  /* Here it's simpler to just allocate for all polys :/ */
2255  int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
2256  float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__);
2257 
2258  size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE;
2259  float(*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__);
2260  /* Tessellated 2D poly, always (num_loops - 2) triangles. */
2261  int(*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__);
2262 
2263  for (i = 0; i < numpolys_dst; i++) {
2264  /* For each dst poly, we sample some rays from it (2D grid in pnor space)
2265  * and use their hits to interpolate from source polys. */
2266  /* NOTE: dst poly is early-converted into src space! */
2267  MPoly *mp = &polys_dst[i];
2268 
2269  int tot_rays, done_rays = 0;
2270  float poly_area_2d_inv, done_area = 0.0f;
2271 
2272  float pcent_dst[3];
2273  float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3];
2274  float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z;
2275  float poly_dst_2d_size[2];
2276 
2277  float totweights = 0.0f;
2278  float hit_dist_accum = 0.0f;
2279  int sources_num = 0;
2280  const int tris_num = mp->totloop - 2;
2281  int j;
2282 
2283  BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst);
2284  copy_v3_v3(tmp_no, poly_nors_dst[i]);
2285 
2286  /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */
2287  if (space_transform) {
2288  BLI_space_transform_apply(space_transform, pcent_dst);
2289  BLI_space_transform_apply_normal(space_transform, tmp_no);
2290  }
2291 
2292  copy_vn_fl(weights, (int)numpolys_src, 0.0f);
2293 
2294  if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
2295  tmp_poly_size = (size_t)mp->totloop;
2296  poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size);
2297  tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2));
2298  }
2299 
2300  axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no);
2301  invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat);
2302 
2303  mul_m3_v3(to_pnor_2d_mat, pcent_dst);
2304  poly_dst_2d_z = pcent_dst[2];
2305 
2306  /* Get (2D) bounding square of our poly. */
2307  INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max);
2308 
2309  for (j = 0; j < mp->totloop; j++) {
2310  MLoop *ml = &loops_dst[j + mp->loopstart];
2311  copy_v3_v3(tmp_co, verts_dst[ml->v].co);
2312  if (space_transform) {
2313  BLI_space_transform_apply(space_transform, tmp_co);
2314  }
2315  mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co);
2316  minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]);
2317  }
2318 
2319  /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
2320  * with lower/upper bounds. */
2321  sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min);
2322 
2323  if (ray_radius) {
2324  tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f);
2326  }
2327  else {
2328  /* If no radius (pure rays), give max number of rays! */
2329  tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN;
2330  }
2331  tot_rays *= tot_rays;
2332 
2333  poly_area_2d_inv = area_poly_v2(poly_vcos_2d, (uint)mp->totloop);
2334  /* In case we have a null-area degenerated poly... */
2335  poly_area_2d_inv = 1.0f / max_ff(poly_area_2d_inv, 1e-9f);
2336 
2337  /* Tessellate our poly. */
2338  if (mp->totloop == 3) {
2339  tri_vidx_2d[0][0] = 0;
2340  tri_vidx_2d[0][1] = 1;
2341  tri_vidx_2d[0][2] = 2;
2342  }
2343  if (mp->totloop == 4) {
2344  tri_vidx_2d[0][0] = 0;
2345  tri_vidx_2d[0][1] = 1;
2346  tri_vidx_2d[0][2] = 2;
2347  tri_vidx_2d[1][0] = 0;
2348  tri_vidx_2d[1][1] = 2;
2349  tri_vidx_2d[1][2] = 3;
2350  }
2351  else {
2352  BLI_polyfill_calc(poly_vcos_2d, (uint)mp->totloop, -1, (uint(*)[3])tri_vidx_2d);
2353  }
2354 
2355  for (j = 0; j < tris_num; j++) {
2356  float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]];
2357  float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]];
2358  float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]];
2359  int rays_num;
2360 
2361  /* All this allows us to get 'absolute' number of rays for each tri,
2362  * avoiding accumulating errors over iterations, and helping better even distribution. */
2363  done_area += area_tri_v2(v1, v2, v3);
2364  rays_num = max_ii(
2365  (int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays, 0);
2366  done_rays += rays_num;
2367 
2368  while (rays_num--) {
2369  int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
2370  float w = 1.0f;
2371 
2372  BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co);
2373 
2374  tmp_co[2] = poly_dst_2d_z;
2375  mul_m3_v3(from_pnor_2d_mat, tmp_co);
2376 
2377  /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */
2378  while (n--) {
2380  &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
2381  const MLoopTri *lt = &treedata.looptri[rayhit.index];
2382 
2383  weights[lt->poly] += w;
2384  totweights += w;
2385  hit_dist_accum += hit_dist;
2386  break;
2387  }
2388  /* Next iteration will get bigger radius but smaller weight! */
2390  }
2391  }
2392  }
2393 
2394  if (totweights > 0.0f) {
2395  for (j = 0; j < (int)numpolys_src; j++) {
2396  if (!weights[j]) {
2397  continue;
2398  }
2399  /* NOTE: sources_num is always <= j! */
2400  weights[sources_num] = weights[j] / totweights;
2401  indices[sources_num] = j;
2402  sources_num++;
2403  }
2405  r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
2406  }
2407  else {
2408  /* No source for this dest poly! */
2410  }
2411  }
2412 
2413  MEM_freeN(tri_vidx_2d);
2414  MEM_freeN(poly_vcos_2d);
2415  MEM_freeN(indices);
2416  MEM_freeN(weights);
2417  BLI_rng_free(rng);
2418  }
2419  else {
2420  CLOG_WARN(&LOG, "Unsupported mesh-to-mesh poly mapping mode (%d)!", mode);
2421  memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst);
2422  }
2423 
2424  free_bvhtree_from_mesh(&treedata);
2425  }
2426 }
2427 
2428 #undef MREMAP_RAYCAST_APPROXIMATE_NR
2429 #undef MREMAP_RAYCAST_APPROXIMATE_FAC
2430 #undef MREMAP_RAYCAST_TRI_SAMPLES_MIN
2431 #undef MREMAP_RAYCAST_TRI_SAMPLES_MAX
2432 #undef MREMAP_DEFAULT_BUFSIZE
2433 
typedef float(TangentPoint)[2]
BVHTree * bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num, const BLI_bitmap *mask, int looptri_num_active, float epsilon, int tree_type, int axis)
Definition: bvhutils.cc:1100
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_EDGES
Definition: BKE_bvhutils.h:71
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
@ BVHTREE_FROM_VERTS
Definition: BKE_bvhutils.h:70
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
BVHTree * bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data, const struct MVert *vert, int verts_num, const BLI_bitmap *verts_mask, int verts_num_active, float epsilon, int tree_type, int axis)
CustomData interface, see also DNA_customdata_types.h.
@ CD_CALLOC
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
Definition: customdata.cc:2626
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v)
const float(* BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_calc_poly_center(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float r_cent[3])
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_normals_loop_split(const struct MVert *mverts, const float(*vert_normals)[3], int numVerts, struct MEdge *medges, int numEdges, struct MLoop *mloops, float(*r_loopnors)[3], int numLoops, struct MPoly *mpolys, const float(*polynors)[3], int numPolys, bool use_split_normals, float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], int *r_loop_to_poly)
float(* BKE_mesh_vert_coords_alloc(const struct Mesh *mesh, int *r_vert_len))[3]
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, const struct MLoop *mloop, int totvert, int totpoly, int totloop)
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, const struct MLoop *mloop, int totvert, int totpoly, int totloop)
@ MISLAND_TYPE_POLY
@ MISLAND_TYPE_LOOP
@ MISLAND_TYPE_EDGE
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge)
bool(* MeshRemapIslandsCalc)(struct MVert *verts, int totvert, struct MEdge *edges, int totedge, struct MPoly *polys, int totpoly, struct MLoop *loops, int totloop, struct MeshIslandStore *r_island_store)
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, int mpoly_num, const struct MLoopTri *looptri, int looptri_num)
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store)
Definition: mesh_mapping.c:869
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totedge, const struct MPoly *mpoly, int totpoly, const struct MLoop *mloop, int totloop)
@ MREMAP_MODE_VERT_EDGE_NEAREST
@ MREMAP_MODE_VERT_POLYINTERP_VNORPROJ
@ MREMAP_MODE_LOOP
@ MREMAP_MODE_EDGE_POLY_NEAREST
@ MREMAP_MODE_POLY
@ MREMAP_MODE_VERT_EDGEINTERP_NEAREST
@ MREMAP_MODE_VERT_NEAREST
@ MREMAP_MODE_LOOP_NEAREST_POLYNOR
@ MREMAP_MODE_EDGE_VERT_NEAREST
@ MREMAP_USE_NORMAL
@ MREMAP_USE_LOOP
@ MREMAP_MODE_TOPOLOGY
@ MREMAP_MODE_VERT
@ MREMAP_USE_POLY
@ MREMAP_MODE_EDGE
@ MREMAP_MODE_EDGE_NEAREST
@ MREMAP_MODE_POLY_NOR
@ MREMAP_MODE_LOOP_NEAREST_LOOPNOR
@ MREMAP_MODE_LOOP_POLY_NEAREST
@ MREMAP_USE_NORPROJ
@ MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ
@ MREMAP_USE_VERT
@ MREMAP_MODE_POLY_POLYINTERP_PNORPROJ
@ MREMAP_MODE_VERT_POLY_NEAREST
@ MREMAP_MODE_POLY_NEAREST
@ MREMAP_MODE_VERT_POLYINTERP_NEAREST
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
An implementation of the A* (AStar) algorithm to solve shortest path problem.
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph, int node_index_src, int node_index_dst, astar_f_cost f_cost_cb, BLI_AStarSolution *r_solution, int max_steps)
Definition: astar.c:144
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
Definition: astar.c:95
void BLI_astar_node_init(BLI_AStarGraph *as_graph, int node_index, void *custom_data)
Definition: astar.c:40
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph, int node1_index, int node2_index, float cost, void *custom_data)
Definition: astar.c:45
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data)
Definition: astar.c:71
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, int node_num, void *custom_data)
Definition: astar.c:120
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
Definition: astar.c:112
void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
Definition: astar.c:136
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
Definition: bitmap.c:17
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1942
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1616
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE float sqrtf_signed(float f)
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3])
Definition: math_geom.c:2935
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:980
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3527
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3254
float area_poly_v2(const float verts[][2], unsigned int nr)
Definition: math_geom.c:174
void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3])
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3])
void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3])
void unit_m3(float m[3][3])
Definition: math_matrix.c:40
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:917
void unit_m4(float m[4][4])
Definition: rct.c:1090
void copy_m4_m3(float m1[4][4], const float m2[3][3])
Definition: math_matrix.c:102
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4])
Definition: math_matrix.c:3222
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3], float r_eigen_vectors[3][3])
Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
Definition: math_solvers.c:19
void BLI_covariance_m3_v3n(const float(*cos_v3)[3], int cos_v3_num, bool use_sample_correction, float r_covmat[3][3], float r_center[3])
Compute the covariance matrix of given set of 3D coordinates.
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
Definition: math_vector.c:1259
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:92
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
Definition: math_vector.c:707
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:20
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:116
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:153
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
Definition: polyfill_2d.c:875
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:58
struct RNG * BLI_rng_new(unsigned int seed)
Definition: rand.cc:39
void void void BLI_rng_get_tri_sample_float_v2(struct RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2]) ATTR_NONNULL()
Definition: rand.cc:108
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:67
#define INIT_MINMAX2(min, max)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CD_MASK_NORMAL
@ CD_FLAG_TEMPORARY
@ CD_CUSTOMLOOPNORMAL
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
static float verts[][3]
int count
ccl_gpu_kernel_postfix int ccl_global int * indices
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define POLY_UNSET
Definition: mesh_remap.c:1042
#define MREMAP_RAYCAST_TRI_SAMPLES_MIN
Definition: mesh_remap.c:467
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)
Definition: mesh_remap.c:384
void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform)
Definition: mesh_remap.c:247
#define MREMAP_RAYCAST_TRI_SAMPLES_MAX
Definition: mesh_remap.c:468
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 *r_cddata_mask)
Definition: mesh_remap.c:307
void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, Mesh *mesh_dst, 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, 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)
Definition: mesh_remap.c:1232
void BKE_mesh_remap_free(MeshPairRemap *map)
Definition: mesh_remap.c:338
#define MREMAP_RAYCAST_APPROXIMATE_NR
Definition: mesh_remap.c:462
void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index)
Definition: mesh_remap.c:379
struct IslandResult IslandResult
static void mesh_calc_eigen_matrix(const MVert *verts, const float(*vcos)[3], const int numverts, float r_mat[4][4])
Definition: mesh_remap.c:167
void BKE_mesh_remap_calc_polys_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, Mesh *mesh_dst, MVert *verts_dst, MLoop *loops_dst, MPoly *polys_dst, const int numpolys_dst, Mesh *me_src, MeshPairRemap *r_map)
Definition: mesh_remap.c:2152
#define MREMAP_RAYCAST_APPROXIMATE_FAC
Definition: mesh_remap.c:464
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, const int *poly_island_index_map, float(*poly_centers)[3], unsigned char *poly_status)
Definition: mesh_remap.c:1046
#define POLY_COMPLETE
Definition: mesh_remap.c:1044
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)
Definition: mesh_remap.c:1203
float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src)
Definition: mesh_remap.c:112
static CLG_LogRef LOG
Definition: mesh_remap.c:36
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)
Definition: mesh_remap.c:349
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, Mesh *me_dst, MeshPairRemap *r_map)
Definition: mesh_remap.c:697
#define MREMAP_DEFAULT_BUFSIZE
Definition: mesh_remap.c:471
static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata, BVHTreeNearest *nearest, const float co[3], const float max_dist_sq, float *r_hit_dist)
Definition: mesh_remap.c:42
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)
Definition: mesh_remap.c:71
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)
Definition: mesh_remap.c:1105
#define ASTAR_STEPS_MAX
Definition: mesh_remap.c:1230
#define POLY_CENTER_INIT
Definition: mesh_remap.c:1043
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
Definition: mesh_remap.c:326
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, Mesh *me_dst, MeshPairRemap *r_map)
Definition: mesh_remap.c:473
#define sqrtf(x)
Definition: metal/compat.h:243
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
SocketIndexByIdentifierMap * map
void * custom_data
Definition: BLI_astar.h:31
BLI_AStarGNode * nodes
Definition: BLI_astar.h:56
void * custom_data
Definition: BLI_astar.h:58
struct MemArena * mem
Definition: BLI_astar.h:60
BLI_AStarGNLink ** prev_links
Definition: BLI_astar.h:42
float * g_costs
Definition: BLI_astar.h:48
void * custom_data
Definition: BLI_astar.h:44
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:54
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:53
const struct MLoopTri * looptri
Definition: BKE_bvhutils.h:62
float co[3]
Definition: BLI_kdopbvh.h:43
float co[3]
Definition: BLI_kdopbvh.h:68
float hit_dist
Definition: mesh_remap.c:440
float hit_point[3]
Definition: mesh_remap.c:442
float factor
Definition: mesh_remap.c:436
unsigned int v1
unsigned int v2
unsigned int poly
unsigned int tri[3]
unsigned int e
unsigned int v
float co[3]
struct MeshElemMap ** innercuts
struct MeshElemMap ** islands
MeshPairRemapItem * items
struct MLoopTri_Store looptris
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
Definition: rand.cc:33