Blender  V2.93
mesh_boolean_convert.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include "DNA_mesh_types.h"
25 #include "DNA_meshdata_types.h"
26 #include "DNA_object_types.h"
27 
28 #include "BKE_customdata.h"
29 #include "BKE_material.h"
30 #include "BKE_mesh.h"
32 
33 #include "BLI_alloca.h"
34 #include "BLI_array.hh"
35 #include "BLI_float2.hh"
36 #include "BLI_float4x4.hh"
37 #include "BLI_math.h"
38 #include "BLI_mesh_boolean.hh"
39 #include "BLI_mesh_intersect.hh"
40 #include "BLI_span.hh"
41 
42 namespace blender::meshintersect {
43 
44 #ifdef WITH_GMP
45 
46 constexpr int estimated_max_facelen = 100; /* Used for initial size of some Vectors. */
47 
48 /* Snap entries that are near 0 or 1 or -1 to those values.
49  * Sometimes Blender's rotation matrices for multiples of 90 degrees have
50  * tiny numbers where there should be zeros. That messes makes some things
51  * every so slightly non-coplanar when users expect coplanarity,
52  * so this is a hack to clean up such matrices.
53  * Would be better to change the transformation code itself.
54  */
55 static float4x4 clean_obmat(const float4x4 &mat)
56 {
57  float4x4 cleaned;
58  const float fuzz = 1e-6f;
59  for (int i = 0; i < 4; i++) {
60  for (int j = 0; j < 4; j++) {
61  float f = mat.values[i][j];
62  if (fabsf(f) <= fuzz) {
63  f = 0.0f;
64  }
65  else if (fabsf(f - 1.0f) <= fuzz) {
66  f = 1.0f;
67  }
68  else if (fabsf(f + 1.0f) <= fuzz) {
69  f = -1.0f;
70  }
71  cleaned.values[i][j] = f;
72  }
73  }
74  return cleaned;
75 }
76 
77 /* `MeshesToIMeshInfo` keeps track of information used when combining a number
78  * of `Mesh`es into a single `IMesh` for doing boolean on.
79  * Mostly this means keeping track of the index offsets for various mesh elements. */
80 class MeshesToIMeshInfo {
81  public:
82  /* The input meshes, */
83  Span<const Mesh *> meshes;
84  /* Numbering the vertices of the meshes in order of meshes,
85  * at what offset does the vertex range for mesh[i] start? */
86  Array<int> mesh_vert_offset;
87  /* Similarly for edges of meshes. */
88  Array<int> mesh_edge_offset;
89  /* Similarly for polys of meshes. */
90  Array<int> mesh_poly_offset;
91  /* For each Mesh vertex in all the meshes (with concatenated indexing),
92  * what is the IMesh Vert* allocated for it in the input IMesh? */
93  Array<const Vert *> mesh_to_imesh_vert;
94  /* Similarly for each Mesh poly. */
95  Array<Face *> mesh_to_imesh_face;
96  /* Transformation matrix to transform a coordinate in the corresponding
97  * Mesh to the local space of the first Mesh. */
98  Array<float4x4> to_target_transform;
99  /* For each input mesh, how to remap the material slot numbers to
100  * the material slots in the first mesh. */
101  Span<Array<short>> material_remaps;
102  /* Total number of input mesh vertices. */
103  int tot_meshes_verts;
104  /* Total number of input mesh edges. */
105  int tot_meshes_edges;
106  /* Total number of input mesh polys. */
107  int tot_meshes_polys;
108 
109  int input_mesh_for_imesh_vert(int imesh_v) const;
110  int input_mesh_for_imesh_edge(int imesh_e) const;
111  int input_mesh_for_imesh_face(int imesh_f) const;
112  const MPoly *input_mpoly_for_orig_index(int orig_index,
113  const Mesh **r_orig_mesh,
114  int *r_orig_mesh_index,
115  int *r_index_in_orig_mesh) const;
116  const MVert *input_mvert_for_orig_index(int orig_index,
117  const Mesh **r_orig_mesh,
118  int *r_index_in_orig_mesh) const;
119  const MEdge *input_medge_for_orig_index(int orig_index,
120  const Mesh **r_orig_mesh,
121  int *r_index_in_orig_mesh) const;
122 };
123 
124 /* Given an index `imesh_v` in the `IMesh`, return the index of the
125  * input `Mesh` that contained the `MVert` that it came from. */
126 int MeshesToIMeshInfo::input_mesh_for_imesh_vert(int imesh_v) const
127 {
128  int n = static_cast<int>(mesh_vert_offset.size());
129  for (int i = 0; i < n - 1; ++i) {
130  if (imesh_v < mesh_vert_offset[i + 1]) {
131  return i;
132  }
133  }
134  return n - 1;
135 }
136 
137 /* Given an index `imesh_e` used as an original index in the `IMesh`,
138  * return the index of the input `Mesh` that contained the `MVert` that it came from. */
139 int MeshesToIMeshInfo::input_mesh_for_imesh_edge(int imesh_e) const
140 {
141  int n = static_cast<int>(mesh_edge_offset.size());
142  for (int i = 0; i < n - 1; ++i) {
143  if (imesh_e < mesh_edge_offset[i + 1]) {
144  return i;
145  }
146  }
147  return n - 1;
148 }
149 
150 /* Given an index `imesh_f` in the `IMesh`, return the index of the
151  * input `Mesh` that contained the `MPoly` that it came from. */
152 int MeshesToIMeshInfo::input_mesh_for_imesh_face(int imesh_f) const
153 {
154  int n = static_cast<int>(mesh_poly_offset.size());
155  for (int i = 0; i < n - 1; ++i) {
156  if (imesh_f < mesh_poly_offset[i + 1]) {
157  return i;
158  }
159  }
160  return n - 1;
161 }
162 
163 /* Given an index of an original face in the `IMesh`, find out the input
164  * `Mesh` that it came from and return it in `*r_orig_mesh`,
165  * and also return the index of that `Mesh` in `*r_orig_mesh_index`.
166  * Finally, return the index of the corresponding `MPoly` in that `Mesh`
167  * in `*r_index_in_orig_mesh`. */
168 const MPoly *MeshesToIMeshInfo::input_mpoly_for_orig_index(int orig_index,
169  const Mesh **r_orig_mesh,
170  int *r_orig_mesh_index,
171  int *r_index_in_orig_mesh) const
172 {
173  int orig_mesh_index = input_mesh_for_imesh_face(orig_index);
174  BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
175  const Mesh *me = meshes[orig_mesh_index];
176  int index_in_mesh = orig_index - mesh_poly_offset[orig_mesh_index];
177  BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totpoly);
178  const MPoly *mp = &me->mpoly[index_in_mesh];
179  if (r_orig_mesh) {
180  *r_orig_mesh = me;
181  }
182  if (r_orig_mesh_index) {
183  *r_orig_mesh_index = orig_mesh_index;
184  }
185  if (r_index_in_orig_mesh) {
186  *r_index_in_orig_mesh = index_in_mesh;
187  }
188  return mp;
189 }
190 
191 /* Given an index of an original vertex in the `IMesh`, find out the input
192  * `Mesh` that it came from and return it in `*r_orig_mesh`.
193  * Also find the index of the `MVert` in that `Mesh` and return it in
194  * `*r_index_in_orig_mesh`. */
195 const MVert *MeshesToIMeshInfo::input_mvert_for_orig_index(int orig_index,
196  const Mesh **r_orig_mesh,
197  int *r_index_in_orig_mesh) const
198 {
199  int orig_mesh_index = input_mesh_for_imesh_vert(orig_index);
200  BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
201  const Mesh *me = meshes[orig_mesh_index];
202  int index_in_mesh = orig_index - mesh_vert_offset[orig_mesh_index];
203  BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totvert);
204  const MVert *mv = &me->mvert[index_in_mesh];
205  if (r_orig_mesh) {
206  *r_orig_mesh = me;
207  }
208  if (r_index_in_orig_mesh) {
209  *r_index_in_orig_mesh = index_in_mesh;
210  }
211  return mv;
212 }
213 
214 /* Similarly for edges. */
215 const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
216  const Mesh **r_orig_mesh,
217  int *r_index_in_orig_mesh) const
218 {
219  int orig_mesh_index = input_mesh_for_imesh_edge(orig_index);
220  BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
221  const Mesh *me = meshes[orig_mesh_index];
222  int index_in_mesh = orig_index - mesh_edge_offset[orig_mesh_index];
223  BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totedge);
224  const MEdge *medge = &me->medge[index_in_mesh];
225  if (r_orig_mesh) {
226  *r_orig_mesh = me;
227  }
228  if (r_index_in_orig_mesh) {
229  *r_index_in_orig_mesh = index_in_mesh;
230  }
231  return medge;
232 }
233 
246 static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
247  Span<const float4x4 *> obmats,
248  Span<Array<short>> material_remaps,
249  const float4x4 &target_transform,
250  IMeshArena &arena,
251  MeshesToIMeshInfo *r_info)
252 {
253  int nmeshes = meshes.size();
254  BLI_assert(nmeshes > 0);
255  r_info->meshes = meshes;
256  r_info->tot_meshes_verts = 0;
257  r_info->tot_meshes_polys = 0;
258  int &totvert = r_info->tot_meshes_verts;
259  int &totedge = r_info->tot_meshes_edges;
260  int &totpoly = r_info->tot_meshes_polys;
261  for (const Mesh *me : meshes) {
262  totvert += me->totvert;
263  totedge += me->totedge;
264  totpoly += me->totpoly;
265  }
266 
267  /* Estimate the number of vertices and faces in the boolean output,
268  * so that the memory arena can reserve some space. It is OK if these
269  * estimates are wrong. */
270  const int estimate_num_outv = 3 * totvert;
271  const int estimate_num_outf = 4 * totpoly;
272  arena.reserve(estimate_num_outv, estimate_num_outf);
273  r_info->mesh_to_imesh_vert = Array<const Vert *>(totvert);
274  r_info->mesh_to_imesh_face = Array<Face *>(totpoly);
275  r_info->mesh_vert_offset = Array<int>(nmeshes);
276  r_info->mesh_edge_offset = Array<int>(nmeshes);
277  r_info->mesh_poly_offset = Array<int>(nmeshes);
278  r_info->to_target_transform = Array<float4x4>(nmeshes);
279  r_info->material_remaps = material_remaps;
280  int v = 0;
281  int e = 0;
282  int f = 0;
283 
284  /* Put these Vectors here, with a size unlikely to need resizing,
285  * so that the loop to make new Faces will likely not need to allocate
286  * over and over. */
287  Vector<const Vert *, estimated_max_facelen> face_vert;
288  Vector<int, estimated_max_facelen> face_edge_orig;
289 
290  /* To convert the coordinates of objects 1, 2, etc. into the local space
291  * of the target. We multiply each object's `obmat` by the inverse of the
292  * target matrix. Exact Boolean works better if these matrices are 'cleaned'
293  * -- see the comment for the `clean_obmat` function, above. */
294  const float4x4 inv_target_mat = clean_obmat(target_transform).inverted();
295 
296  /* For each input `Mesh`, make `Vert`s and `Face`s for the corresponding
297  * `MVert`s and `MPoly`s, and keep track of the original indices (using the
298  * concatenating offset scheme) inside the `Vert`s and `Face`s.
299  * When making `Face`s, we also put in the original indices for `MEdge`s that
300  * make up the `MPoly`s using the same scheme. */
301  for (int mi : meshes.index_range()) {
302  const Mesh *me = meshes[mi];
303  r_info->mesh_vert_offset[mi] = v;
304  r_info->mesh_edge_offset[mi] = e;
305  r_info->mesh_poly_offset[mi] = f;
306  /* Get matrix that transforms a coordinate in objects[mi]'s local space
307  * to the target space space.*/
308  const float4x4 objn_mat = (obmats[mi] == nullptr) ? float4x4::identity() :
309  clean_obmat(*obmats[mi]);
310  r_info->to_target_transform[mi] = inv_target_mat * objn_mat;
311 
312  /* Skip the matrix multiplication for each point when there is no transform for a mesh,
313  * for example when the first mesh is already in the target space. (Note the logic directly
314  * above, which uses an identity matrix with a null input transform). */
315  if (obmats[mi] == nullptr) {
316  for (const MVert &vert : Span(me->mvert, me->totvert)) {
317  const float3 co = float3(vert.co);
318  r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co.x, co.y, co.z), v);
319  ++v;
320  }
321  }
322  else {
323  for (const MVert &vert : Span(me->mvert, me->totvert)) {
324  const float3 co = r_info->to_target_transform[mi] * float3(vert.co);
325  r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co.x, co.y, co.z), v);
326  ++v;
327  }
328  }
329 
330  for (const MPoly &poly : Span(me->mpoly, me->totpoly)) {
331  int flen = poly.totloop;
332  face_vert.clear();
333  face_edge_orig.clear();
334  const MLoop *l = &me->mloop[poly.loopstart];
335  for (int i = 0; i < flen; ++i) {
336  int mverti = r_info->mesh_vert_offset[mi] + l->v;
337  const Vert *fv = r_info->mesh_to_imesh_vert[mverti];
338  face_vert.append(fv);
339  face_edge_orig.append(e + l->e);
340  ++l;
341  }
342  r_info->mesh_to_imesh_face[f] = arena.add_face(face_vert, f, face_edge_orig);
343  ++f;
344  }
345  e += me->totedge;
346  }
347  return IMesh(r_info->mesh_to_imesh_face);
348 }
349 
350 /* Copy vertex attributes, including customdata, from `orig_mv` to `mv`.
351  * `mv` is in `dest_mesh` with index `mv_index`.
352  * The `orig_mv` vertex came from Mesh `orig_me` and had index `index_in_orig_me` there. */
353 static void copy_vert_attributes(Mesh *dest_mesh,
354  MVert *mv,
355  const MVert *orig_mv,
356  const Mesh *orig_me,
357  int mv_index,
358  int index_in_orig_me)
359 {
360  mv->bweight = orig_mv->bweight;
361  mv->flag = orig_mv->flag;
362 
363  /* For all layers in the orig mesh, copy the layer information. */
364  CustomData *target_cd = &dest_mesh->vdata;
365  const CustomData *source_cd = &orig_me->vdata;
366  for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
367  int ty = source_cd->layers[source_layer_i].type;
368  /* The (first) CD_MVERT layer is the same as dest_mesh->vdata, so we've
369  * already set the coordinate to the right value. */
370  if (ty == CD_MVERT) {
371  continue;
372  }
373  const char *name = source_cd->layers[source_layer_i].name;
374  int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
375  /* Not all layers were merged in target: some are marked CD_FLAG_NOCOPY
376  * and some are not in the CD_MASK_MESH.vdata. */
377  if (target_layer_i != -1) {
379  source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, mv_index, 1);
380  }
381  }
382 }
383 
384 /* Similar to copy_vert_attributes but for poly attributes. */
385 static void copy_poly_attributes(Mesh *dest_mesh,
386  MPoly *mp,
387  const MPoly *orig_mp,
388  const Mesh *orig_me,
389  int mp_index,
390  int index_in_orig_me,
391  Span<short> material_remap)
392 {
393  mp->mat_nr = orig_mp->mat_nr;
394  if (mp->mat_nr >= dest_mesh->totcol) {
395  mp->mat_nr = 0;
396  }
397  else {
398  if (material_remap.size() > 0) {
399  short mat_nr = material_remap[orig_mp->mat_nr];
400  if (mat_nr >= 0 && mat_nr < dest_mesh->totcol) {
401  mp->mat_nr = mat_nr;
402  }
403  }
404  }
405  mp->flag = orig_mp->flag;
406  CustomData *target_cd = &dest_mesh->pdata;
407  const CustomData *source_cd = &orig_me->pdata;
408  for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
409  int ty = source_cd->layers[source_layer_i].type;
410  if (ty == CD_MPOLY) {
411  continue;
412  }
413  const char *name = source_cd->layers[source_layer_i].name;
414  int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
415  if (target_layer_i != -1) {
417  source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, mp_index, 1);
418  }
419  }
420 }
421 
422 /* Similar to copy_vert_attributes but for edge attributes. */
423 static void copy_edge_attributes(Mesh *dest_mesh,
424  MEdge *medge,
425  const MEdge *orig_medge,
426  const Mesh *orig_me,
427  int medge_index,
428  int index_in_orig_me)
429 {
430  medge->bweight = orig_medge->bweight;
431  medge->crease = orig_medge->crease;
432  medge->flag = orig_medge->flag;
433  CustomData *target_cd = &dest_mesh->edata;
434  const CustomData *source_cd = &orig_me->edata;
435  for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
436  int ty = source_cd->layers[source_layer_i].type;
437  if (ty == CD_MEDGE) {
438  continue;
439  }
440  const char *name = source_cd->layers[source_layer_i].name;
441  int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
442  if (target_layer_i != -1) {
444  source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, medge_index, 1);
445  }
446  }
447 }
448 
459 static int fill_orig_loops(const Face *f,
460  const MPoly *orig_mp,
461  const Mesh *orig_me,
462  int orig_me_index,
463  MeshesToIMeshInfo &mim,
464  Array<int> &orig_loops)
465 {
466  orig_loops.fill(-1);
467  int orig_mplen = orig_mp->totloop;
468  if (f->size() != orig_mplen) {
469  return 0;
470  }
471  BLI_assert(orig_loops.size() == orig_mplen);
472  /* We'll look for the case where the first vertex in f has an original vertex
473  * that is the same as one in orig_me (after correcting for offset in mim meshes).
474  * Then see that loop and any subsequent ones have the same start and end vertex.
475  * This may miss some cases of partial alignment, but that's OK since discovering
476  * aligned loops is only an optimization to avoid some re-interpolation.
477  */
478  int first_orig_v = f->vert[0]->orig;
479  if (first_orig_v == NO_INDEX) {
480  return 0;
481  }
482  /* It is possible that the original vert was merged with another in another mesh. */
483  if (orig_me_index != mim.input_mesh_for_imesh_vert(first_orig_v)) {
484  return 0;
485  }
486  int orig_me_vert_offset = mim.mesh_vert_offset[orig_me_index];
487  int first_orig_v_in_orig_me = first_orig_v - orig_me_vert_offset;
488  BLI_assert(0 <= first_orig_v_in_orig_me && first_orig_v_in_orig_me < orig_me->totvert);
489  /* Assume all vertices in an mpoly are unique. */
490  int offset = -1;
491  for (int i = 0; i < orig_mplen; ++i) {
492  int loop_i = i + orig_mp->loopstart;
493  if (orig_me->mloop[loop_i].v == first_orig_v_in_orig_me) {
494  offset = i;
495  break;
496  }
497  }
498  if (offset == -1) {
499  return 0;
500  }
501  int num_orig_loops_found = 0;
502  for (int mp_loop_index = 0; mp_loop_index < orig_mplen; ++mp_loop_index) {
503  int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen;
504  MLoop *l = &orig_me->mloop[orig_mp->loopstart + orig_mp_loop_index];
505  int fv_orig = f->vert[mp_loop_index]->orig;
506  if (fv_orig != NO_INDEX) {
507  fv_orig -= orig_me_vert_offset;
508  if (fv_orig < 0 || fv_orig >= orig_me->totvert) {
509  fv_orig = NO_INDEX;
510  }
511  }
512  if (l->v == fv_orig) {
513  MLoop *lnext = &orig_me->mloop[orig_mp->loopstart + ((orig_mp_loop_index + 1) % orig_mplen)];
514  int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig;
515  if (fvnext_orig != NO_INDEX) {
516  fvnext_orig -= orig_me_vert_offset;
517  if (fvnext_orig < 0 || fvnext_orig >= orig_me->totvert) {
518  fvnext_orig = NO_INDEX;
519  }
520  }
521  if (lnext->v == fvnext_orig) {
522  orig_loops[mp_loop_index] = orig_mp->loopstart + orig_mp_loop_index;
523  ++num_orig_loops_found;
524  }
525  }
526  }
527  return num_orig_loops_found;
528 }
529 
530 /* Fill `cos_2d` with the 2d coordinates found by projection MPoly `mp` along
531  * its normal. Also fill in r_axis_mat with the matrix that does that projection.
532  * But before projecting, also transform the 3d coordinate by multiplying by trans_mat.
533  * `cos_2d` should have room for `mp->totloop` entries. */
534 static void get_poly2d_cos(const Mesh *me,
535  const MPoly *mp,
536  float (*cos_2d)[2],
537  const float4x4 &trans_mat,
538  float r_axis_mat[3][3])
539 {
540  int n = mp->totloop;
541 
542  /* Project coordinates to 2d in cos_2d, using normal as projection axis. */
543  float axis_dominant[3];
544  BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, axis_dominant);
545  axis_dominant_v3_to_m3(r_axis_mat, axis_dominant);
546  MLoop *ml = &me->mloop[mp->loopstart];
547  const MVert *mverts = me->mvert;
548  for (int i = 0; i < n; ++i) {
549  float3 co = mverts[ml->v].co;
550  co = trans_mat * co;
551  mul_v2_m3v3(cos_2d[i], r_axis_mat, co);
552  ++ml;
553  }
554 }
555 
556 /* For the loops of `mp`, see if the face is unchanged from `orig_mp`, and if so,
557  * copy the Loop attributes from corresponding loops to corresponding loops.
558  * Otherwise, interpolate the Loop attributes in the face `orig_mp`. */
559 static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
560  const Face *f,
561  MPoly *mp,
562  const MPoly *orig_mp,
563  const Mesh *orig_me,
564  int orig_me_index,
565  MeshesToIMeshInfo &mim)
566 {
567  Array<int> orig_loops(mp->totloop);
568  int norig = fill_orig_loops(f, orig_mp, orig_me, orig_me_index, mim, orig_loops);
569  /* We may need these arrays if we have to interpolate Loop attributes rather than just copy.
570  * Right now, trying Array<float[2]> complains, so declare cos_2d a different way. */
571  float(*cos_2d)[2];
572  Array<float> weights;
573  Array<const void *> src_blocks_ofs;
574  float axis_mat[3][3];
575  if (norig != mp->totloop) {
576  /* We will need to interpolate. Make `cos_2d` hold 2d-projected coordinates of `orig_mp`,
577  * which are transformed into object 0's local space before projecting.
578  * At this point we cannot yet calculate the interpolation weights, as they depend on
579  * the coordinate where interpolation is to happen, but we can allocate the needed arrays,
580  * so they don't have to be allocated per-layer. */
581  cos_2d = (float(*)[2])BLI_array_alloca(cos_2d, orig_mp->totloop);
582  weights = Array<float>(orig_mp->totloop);
583  src_blocks_ofs = Array<const void *>(orig_mp->totloop);
584  get_poly2d_cos(orig_me, orig_mp, cos_2d, mim.to_target_transform[orig_me_index], axis_mat);
585  }
586  CustomData *target_cd = &dest_mesh->ldata;
587  for (int i = 0; i < mp->totloop; ++i) {
588  int loop_index = mp->loopstart + i;
589  int orig_loop_index = norig > 0 ? orig_loops[i] : -1;
590  const CustomData *source_cd = &orig_me->ldata;
591  if (orig_loop_index == -1) {
592  /* Will need interpolation weights for this loop's vertex's coordinates.
593  * The coordinate needs to be projected into 2d, just like the interpolating polygon's
594  * coordinates were. The `dest_mesh` coordinates are already in object 0 local space. */
595  float co[2];
596  mul_v2_m3v3(co, axis_mat, dest_mesh->mvert[dest_mesh->mloop[loop_index].v].co);
597  interp_weights_poly_v2(weights.data(), cos_2d, orig_mp->totloop, co);
598  }
599  for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
600  int ty = source_cd->layers[source_layer_i].type;
601  if (ty == CD_MLOOP) {
602  continue;
603  }
604  const char *name = source_cd->layers[source_layer_i].name;
605  int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
606  if (target_layer_i == -1) {
607  continue;
608  }
609  if (orig_loop_index != -1) {
611  source_cd, target_cd, source_layer_i, target_layer_i, orig_loop_index, loop_index, 1);
612  }
613  else {
614  /* Note: although CustomData_bmesh_interp_n function has bmesh in its name, nothing about
615  * it is BMesh-specific. We can't use CustomData_interp because it assumes that
616  * all source layers exist in the dest.
617  * A non bmesh version could have the benefit of not copying data into src_blocks_ofs -
618  * using the contiguous data instead. TODO: add to the custom data API. */
619  int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name);
620  if (!CustomData_layer_has_interp(source_cd, source_layer_i)) {
621  continue;
622  }
623  int source_layer_type_index = source_layer_i - source_cd->typemap[ty];
624  BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0);
625  for (int j = 0; j < orig_mp->totloop; ++j) {
626  src_blocks_ofs[j] = CustomData_get_n(
627  source_cd, ty, orig_mp->loopstart + j, source_layer_type_index);
628  }
629  void *dst_block_ofs = CustomData_get_n(target_cd, ty, loop_index, target_layer_type_index);
630  CustomData_bmesh_interp_n(target_cd,
631  src_blocks_ofs.data(),
632  weights.data(),
633  nullptr,
634  orig_mp->totloop,
635  dst_block_ofs,
636  target_layer_i);
637  }
638  }
639  }
640 }
641 
648 static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
649 {
650  for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) {
651  const Mesh *me = mim.meshes[mesh_index];
652  if (me->totvert) {
654  &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_DEFAULT, target->totvert);
655  }
656  if (me->totloop) {
658  &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_DEFAULT, target->totloop);
659  }
660  if (me->totpoly) {
662  &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_DEFAULT, target->totpoly);
663  }
664  }
665 }
666 
667 static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
668 {
669  for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) {
670  const Mesh *me = mim.meshes[mesh_index];
671  if (me->totedge) {
673  &me->edata, &target->edata, CD_MASK_MESH.emask, CD_DEFAULT, target->totedge);
674  }
675  }
676 }
677 
682 static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
683 {
684  constexpr int dbg_level = 0;
685 
686  im->populate_vert();
687  int out_totvert = im->vert_size();
688  int out_totpoly = im->face_size();
689  int out_totloop = 0;
690  for (const Face *f : im->faces()) {
691  out_totloop += f->size();
692  }
693  /* Will calculate edges later. */
695  mim.meshes[0], out_totvert, 0, 0, out_totloop, out_totpoly);
696 
697  merge_vertex_loop_poly_customdata_layers(result, mim);
698  /* Set the vertex coordinate values and other data. */
699  for (int vi : im->vert_index_range()) {
700  const Vert *v = im->vert(vi);
701  MVert *mv = &result->mvert[vi];
702  copy_v3fl_v3db(mv->co, v->co);
703  if (v->orig != NO_INDEX) {
704  const Mesh *orig_me;
705  int index_in_orig_me;
706  const MVert *orig_mv = mim.input_mvert_for_orig_index(v->orig, &orig_me, &index_in_orig_me);
707  copy_vert_attributes(result, mv, orig_mv, orig_me, vi, index_in_orig_me);
708  }
709  }
710 
711  /* Set the loopstart and totloop for each output poly,
712  * and set the vertices in the appropriate loops. */
713  int cur_loop_index = 0;
714  MLoop *l = result->mloop;
715  for (int fi : im->face_index_range()) {
716  const Face *f = im->face(fi);
717  const Mesh *orig_me;
718  int index_in_orig_me;
719  int orig_me_index;
720  const MPoly *orig_mp = mim.input_mpoly_for_orig_index(
721  f->orig, &orig_me, &orig_me_index, &index_in_orig_me);
722  MPoly *mp = &result->mpoly[fi];
723  mp->totloop = f->size();
724  mp->loopstart = cur_loop_index;
725  for (int j : f->index_range()) {
726  const Vert *vf = f->vert[j];
727  const int vfi = im->lookup_vert(vf);
728  l->v = vfi;
729  ++l;
730  ++cur_loop_index;
731  }
732 
733  copy_poly_attributes(result,
734  mp,
735  orig_mp,
736  orig_me,
737  fi,
738  index_in_orig_me,
739  (mim.material_remaps.size() > 0) ?
740  mim.material_remaps[orig_me_index].as_span() :
741  Span<short>());
742  copy_or_interp_loop_attributes(result, f, mp, orig_mp, orig_me, orig_me_index, mim);
743  }
744 
745  /* BKE_mesh_calc_edges will calculate and populate all the
746  * MEdges from the MPolys. */
747  BKE_mesh_calc_edges(result, false, false);
748  merge_edge_customdata_layers(result, mim);
749 
750  /* Now that the MEdges are populated, we can copy over the required attributes and custom layers.
751  */
752  for (int fi : im->face_index_range()) {
753  const Face *f = im->face(fi);
754  MPoly *mp = &result->mpoly[fi];
755  for (int j : f->index_range()) {
756  if (f->edge_orig[j] != NO_INDEX) {
757  const Mesh *orig_me;
758  int index_in_orig_me;
759  const MEdge *orig_medge = mim.input_medge_for_orig_index(
760  f->edge_orig[j], &orig_me, &index_in_orig_me);
761  int e_index = result->mloop[mp->loopstart + j].e;
762  MEdge *medge = &result->medge[e_index];
763  copy_edge_attributes(result, medge, orig_medge, orig_me, e_index, index_in_orig_me);
764  }
765  }
766  }
767 
769  if (dbg_level > 0) {
770  BKE_mesh_validate(result, true, true);
771  }
772  return result;
773 }
774 
775 #endif // WITH_GMP
776 
788  Span<const float4x4 *> obmats,
789  const float4x4 &target_transform,
790  Span<Array<short>> material_remaps,
791  const bool use_self,
792  const bool hole_tolerant,
793  const int boolean_mode)
794 {
795 #ifdef WITH_GMP
796  BLI_assert(meshes.size() == obmats.size());
797  BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.size());
798  if (meshes.size() <= 0) {
799  return nullptr;
800  }
801 
802  const int dbg_level = 0;
803  if (dbg_level > 0) {
804  std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes.size() << "\n";
805  }
806  MeshesToIMeshInfo mim;
807  IMeshArena arena;
808  IMesh m_in = meshes_to_imesh(meshes, obmats, material_remaps, target_transform, arena, &mim);
809  std::function<int(int)> shape_fn = [&mim](int f) {
810  for (int mi = 0; mi < mim.mesh_poly_offset.size() - 1; ++mi) {
811  if (f < mim.mesh_poly_offset[mi + 1]) {
812  return mi;
813  }
814  }
815  return static_cast<int>(mim.mesh_poly_offset.size()) - 1;
816  };
817  IMesh m_out = boolean_mesh(m_in,
818  static_cast<BoolOpType>(boolean_mode),
819  meshes.size(),
820  shape_fn,
821  use_self,
822  hole_tolerant,
823  nullptr,
824  &arena);
825  if (dbg_level > 0) {
826  std::cout << m_out;
827  write_obj_mesh(m_out, "m_out");
828  }
829 
830  return imesh_to_mesh(&m_out, mim);
831 #else // WITH_GMP
832  UNUSED_VARS(
833  meshes, obmats, material_remaps, target_transform, use_self, hole_tolerant, boolean_mode);
834  return nullptr;
835 #endif // WITH_GMP
836 }
837 
838 } // namespace blender::meshintersect
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
@ CD_DEFAULT
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
Definition: customdata.c:3832
void CustomData_bmesh_interp_n(struct CustomData *data, const void **src_blocks, const float *weights, const float *sub_weights, int count, void *dst_block_ofs, int n)
Definition: customdata.c:4031
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, int src_layer_index, int dst_layer_index, int src_index, int dst_index, int count)
Definition: customdata.c:2892
void * CustomData_get_n(const struct CustomData *data, int type, int index, int n)
int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name)
Definition: customdata.c:2365
bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, CustomDataMask mask, eCDAllocType alloctype, int totelem)
Definition: customdata.c:2098
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.c:1933
General operations, lookup, etc. for materials.
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
void BKE_mesh_calc_normals(struct Mesh *me)
void BKE_mesh_calc_poly_normal(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float r_no[3])
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask)
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
#define UNUSED_VARS(...)
@ CD_MVERT
Object is a sort of wrapper for general info.
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t size() const
Definition: BLI_span.hh:254
#define fabsf(x)
Mesh * direct_mesh_boolean(blender::Span< const Mesh * > meshes, blender::Span< const float4x4 * > obmats, const float4x4 &target_transform, blender::Span< blender::Array< short >> material_remaps, const bool use_self, const bool hole_tolerant, const int boolean_mode)
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
float co[3]
Definition: bmesh_class.h:99
CustomDataLayer * layers
unsigned int v
short mat_nr
float co[3]
struct MEdge * medge
struct CustomData pdata ldata
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
int totpoly
short totcol
int totloop
struct MPoly * mpoly
static float4x4 identity()
Definition: BLI_float4x4.hh:48
float z
Definition: sky_float3.h:35
float y
Definition: sky_float3.h:35
float x
Definition: sky_float3.h:35