Blender  V3.3
bmo_smooth_laplacian.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_math.h"
12 
13 #include "eigen_capi.h"
14 
15 #include "bmesh.h"
16 
17 #include "intern/bmesh_operators_private.h" /* own include */
18 
19 // #define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f /* UNUSED */
20 // #define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f /* UNUSED */
21 #define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE 1.8f
22 #define SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE 0.15f
23 
25  float *eweights; /* Length weights per Edge. */
26  float (*fweights)[3]; /* Cotangent weights per loop. */
27  float *ring_areas; /* Total area per ring. */
28  float *vlengths; /* Total sum of lengths(edges) per vertex. */
29  float *vweights; /* Total sum of weights per vertex. */
30  int numEdges; /* Number of edges. */
31  int numLoops; /* Number of loops. */
32  int numVerts; /* Number of verts. */
33  bool *zerola; /* Is zero area or length. */
34 
35  /* Pointers to data. */
39 
40  /* Data. */
41  float min_area;
42 };
43 typedef struct BLaplacianSystem LaplacianSystem;
44 
45 static bool vert_is_boundary(BMVert *v);
46 static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts);
47 static void init_laplacian_matrix(LaplacianSystem *sys);
49 static void delete_void_pointer(void *data);
50 static void fill_laplacian_matrix(LaplacianSystem *sys);
51 static void memset_laplacian_system(LaplacianSystem *sys, int val);
52 static void validate_solution(
53  LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume);
54 static void volume_preservation(
55  BMOperator *op, float vini, float vend, int usex, int usey, int usez);
56 
57 static void delete_void_pointer(void *data)
58 {
59  if (data) {
60  MEM_freeN(data);
61  }
62 }
63 
65 {
66  delete_void_pointer(sys->eweights);
68  delete_void_pointer(sys->ring_areas);
69  delete_void_pointer(sys->vlengths);
70  delete_void_pointer(sys->vweights);
71  delete_void_pointer(sys->zerola);
72  if (sys->context) {
74  }
75  sys->bm = NULL;
76  sys->op = NULL;
77  MEM_freeN(sys);
78 }
79 
80 static void memset_laplacian_system(LaplacianSystem *sys, int val)
81 {
82  memset(sys->eweights, val, sizeof(float) * sys->numEdges);
83  memset(sys->fweights, val, sizeof(float[3]) * sys->numLoops);
84  memset(sys->ring_areas, val, sizeof(float) * sys->numVerts);
85  memset(sys->vlengths, val, sizeof(float) * sys->numVerts);
86  memset(sys->vweights, val, sizeof(float) * sys->numVerts);
87  memset(sys->zerola, val, sizeof(bool) * sys->numVerts);
88 }
89 
90 static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts)
91 {
92  LaplacianSystem *sys;
93  sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem");
94  sys->numEdges = a_numEdges;
95  sys->numLoops = a_numLoops;
96  sys->numVerts = a_numVerts;
97 
98  sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight");
99  if (!sys->eweights) {
101  return NULL;
102  }
103 
104  sys->fweights = MEM_callocN(sizeof(float[3]) * sys->numLoops, "ModLaplSmoothFWeight");
105  if (!sys->fweights) {
107  return NULL;
108  }
109 
110  sys->ring_areas = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothRingAreas");
111  if (!sys->ring_areas) {
113  return NULL;
114  }
115 
116  sys->vlengths = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVlengths");
117  if (!sys->vlengths) {
119  return NULL;
120  }
121 
122  sys->vweights = MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVweights");
123  if (!sys->vweights) {
125  return NULL;
126  }
127 
128  sys->zerola = MEM_callocN(sizeof(bool) * sys->numVerts, "ModLaplSmoothZeloa");
129  if (!sys->zerola) {
131  return NULL;
132  }
133 
134  return sys;
135 }
136 
154 {
155  BMEdge *e;
156  BMFace *f;
157  BMIter eiter;
158  BMIter fiter;
159  uint i;
160 
161  BM_ITER_MESH_INDEX (e, &eiter, sys->bm, BM_EDGES_OF_MESH, i) {
163  continue;
164  }
165 
166  const float *v1 = e->v1->co;
167  const float *v2 = e->v2->co;
168  const int idv1 = BM_elem_index_get(e->v1);
169  const int idv2 = BM_elem_index_get(e->v2);
170 
171  float w1 = len_v3v3(v1, v2);
172  if (w1 > sys->min_area) {
173  w1 = 1.0f / w1;
174  sys->eweights[i] = w1;
175  sys->vlengths[idv1] += w1;
176  sys->vlengths[idv2] += w1;
177  }
178  else {
179  sys->zerola[idv1] = true;
180  sys->zerola[idv2] = true;
181  }
182  }
183 
184  uint l_curr_index = 0;
185 
186  BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) {
188  l_curr_index += f->len;
189  continue;
190  }
191 
192  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
193  BMLoop *l_iter;
194 
195  l_iter = l_first;
196  do {
197  const int vi_prev = BM_elem_index_get(l_iter->prev->v);
198  const int vi_curr = BM_elem_index_get(l_iter->v);
199  const int vi_next = BM_elem_index_get(l_iter->next->v);
200 
201  const float *co_prev = l_iter->prev->v->co;
202  const float *co_curr = l_iter->v->co;
203  const float *co_next = l_iter->next->v->co;
204 
205  const float areaf = area_tri_v3(co_prev, co_curr, co_next);
206 
207  if (areaf < sys->min_area) {
208  sys->zerola[vi_curr] = true;
209  }
210 
211  sys->ring_areas[vi_prev] += areaf;
212  sys->ring_areas[vi_curr] += areaf;
213  sys->ring_areas[vi_next] += areaf;
214 
215  const float w1 = cotangent_tri_weight_v3(co_curr, co_next, co_prev) / 2.0f;
216  const float w2 = cotangent_tri_weight_v3(co_next, co_prev, co_curr) / 2.0f;
217  const float w3 = cotangent_tri_weight_v3(co_prev, co_curr, co_next) / 2.0f;
218 
219  sys->fweights[l_curr_index][0] += w1;
220  sys->fweights[l_curr_index][1] += w2;
221  sys->fweights[l_curr_index][2] += w3;
222 
223  sys->vweights[vi_prev] += w1 + w2;
224  sys->vweights[vi_curr] += w2 + w3;
225  sys->vweights[vi_next] += w1 + w3;
226  } while (((void)(l_curr_index += 1), (l_iter = l_iter->next) != l_first));
227  }
228 }
229 
231 {
232  BMEdge *e;
233  BMFace *f;
234  BMIter eiter;
235  BMIter fiter;
236  int i;
237 
238  uint l_curr_index = 0;
239 
240  BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) {
242  l_curr_index += f->len;
243  continue;
244  }
245 
246  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
247  BMLoop *l_iter = l_first;
248 
249  int vi_prev = BM_elem_index_get(l_iter->prev->v);
250  int vi_curr = BM_elem_index_get(l_iter->v);
251 
252  bool ok_prev = (sys->zerola[vi_prev] == false) && !vert_is_boundary(l_iter->prev->v);
253  bool ok_curr = (sys->zerola[vi_curr] == false) && !vert_is_boundary(l_iter->v);
254 
255  do {
256  const int vi_next = BM_elem_index_get(l_iter->next->v);
257  const bool ok_next = (sys->zerola[vi_next] == false) && !vert_is_boundary(l_iter->next->v);
258 
259  if (ok_prev) {
261  vi_prev,
262  vi_curr,
263  sys->fweights[l_curr_index][1] * sys->vweights[vi_prev]);
265  vi_prev,
266  vi_next,
267  sys->fweights[l_curr_index][0] * sys->vweights[vi_prev]);
268  }
269  if (ok_curr) {
271  vi_curr,
272  vi_next,
273  sys->fweights[l_curr_index][2] * sys->vweights[vi_curr]);
275  vi_curr,
276  vi_prev,
277  sys->fweights[l_curr_index][1] * sys->vweights[vi_curr]);
278  }
279  if (ok_next) {
281  vi_next,
282  vi_curr,
283  sys->fweights[l_curr_index][2] * sys->vweights[vi_next]);
285  vi_next,
286  vi_prev,
287  sys->fweights[l_curr_index][0] * sys->vweights[vi_next]);
288  }
289 
290  vi_prev = vi_curr;
291  vi_curr = vi_next;
292 
293  ok_prev = ok_curr;
294  ok_curr = ok_next;
295 
296  } while (((void)(l_curr_index += 1), (l_iter = l_iter->next) != l_first));
297  }
298  BM_ITER_MESH_INDEX (e, &eiter, sys->bm, BM_EDGES_OF_MESH, i) {
300  continue;
301  }
302  const uint idv1 = BM_elem_index_get(e->v1);
303  const uint idv2 = BM_elem_index_get(e->v2);
304  if (sys->zerola[idv1] == false && sys->zerola[idv2] == false) {
306  sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
308  sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
309  }
310  }
311 }
312 
313 static bool vert_is_boundary(BMVert *v)
314 {
315  BMEdge *ed;
316  BMFace *f;
317  BMIter ei;
318  BMIter fi;
319  BM_ITER_ELEM (ed, &ei, v, BM_EDGES_OF_VERT) {
320  if (BM_edge_is_boundary(ed)) {
321  return 1;
322  }
323  }
324  BM_ITER_ELEM (f, &fi, v, BM_FACES_OF_VERT) {
326  return 1;
327  }
328  }
329  return 0;
330 }
331 
333  BMOperator *op, float vini, float vend, int usex, int usey, int usez)
334 {
335  float beta;
336  BMOIter siter;
337  BMVert *v;
338 
339  if (vend != 0.0f) {
340  beta = pow(vini / vend, 1.0f / 3.0f);
341  BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
342  if (usex) {
343  v->co[0] *= beta;
344  }
345  if (usey) {
346  v->co[1] *= beta;
347  }
348  if (usez) {
349  v->co[2] *= beta;
350  }
351  }
352  }
353 }
354 
355 static void validate_solution(
356  LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume)
357 {
358  int m_vertex_id;
359  float leni, lene;
360  float vini, vend;
361  float *vi1, *vi2, ve1[3], ve2[3];
362  uint idv1, idv2;
363  BMOIter siter;
364  BMVert *v;
365  BMEdge *e;
366  BMIter eiter;
367 
368  BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) {
369  idv1 = BM_elem_index_get(e->v1);
370  idv2 = BM_elem_index_get(e->v2);
371  vi1 = e->v1->co;
372  vi2 = e->v2->co;
373  ve1[0] = EIG_linear_solver_variable_get(sys->context, 0, idv1);
374  ve1[1] = EIG_linear_solver_variable_get(sys->context, 1, idv1);
375  ve1[2] = EIG_linear_solver_variable_get(sys->context, 2, idv1);
376  ve2[0] = EIG_linear_solver_variable_get(sys->context, 0, idv2);
377  ve2[1] = EIG_linear_solver_variable_get(sys->context, 1, idv2);
378  ve2[2] = EIG_linear_solver_variable_get(sys->context, 2, idv2);
379  leni = len_v3v3(vi1, vi2);
380  lene = len_v3v3(ve1, ve2);
381  if (lene > leni * SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE ||
382  lene < leni * SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) {
383  sys->zerola[idv1] = true;
384  sys->zerola[idv2] = true;
385  }
386  }
387 
388  if (preserve_volume) {
389  vini = BM_mesh_calc_volume(sys->bm, false);
390  }
391  BMO_ITER (v, &siter, sys->op->slots_in, "verts", BM_VERT) {
392  m_vertex_id = BM_elem_index_get(v);
393  if (sys->zerola[m_vertex_id] == false) {
394  if (usex) {
395  v->co[0] = EIG_linear_solver_variable_get(sys->context, 0, m_vertex_id);
396  }
397  if (usey) {
398  v->co[1] = EIG_linear_solver_variable_get(sys->context, 1, m_vertex_id);
399  }
400  if (usez) {
401  v->co[2] = EIG_linear_solver_variable_get(sys->context, 2, m_vertex_id);
402  }
403  }
404  }
405  if (preserve_volume) {
406  vend = BM_mesh_calc_volume(sys->bm, false);
407  volume_preservation(sys->op, vini, vend, usex, usey, usez);
408  }
409 }
410 
412 {
413  int i;
414  int m_vertex_id;
415  bool usex, usey, usez, preserve_volume;
416  float lambda_factor, lambda_border;
417  float w;
418  BMOIter siter;
419  BMVert *v;
420  LaplacianSystem *sys;
421 
422  if (bm->totface == 0) {
423  return;
424  }
426  if (!sys) {
427  return;
428  }
429  sys->bm = bm;
430  sys->op = op;
431 
432  memset_laplacian_system(sys, 0);
433 
435  lambda_factor = BMO_slot_float_get(op->slots_in, "lambda_factor");
436  lambda_border = BMO_slot_float_get(op->slots_in, "lambda_border");
437  sys->min_area = 0.00001f;
438  usex = BMO_slot_bool_get(op->slots_in, "use_x");
439  usey = BMO_slot_bool_get(op->slots_in, "use_y");
440  usez = BMO_slot_bool_get(op->slots_in, "use_z");
441  preserve_volume = BMO_slot_bool_get(op->slots_in, "preserve_volume");
442 
444 
445  for (i = 0; i < bm->totvert; i++) {
447  }
448  BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
449  m_vertex_id = BM_elem_index_get(v);
450  EIG_linear_solver_variable_unlock(sys->context, m_vertex_id);
451  EIG_linear_solver_variable_set(sys->context, 0, m_vertex_id, v->co[0]);
452  EIG_linear_solver_variable_set(sys->context, 1, m_vertex_id, v->co[1]);
453  EIG_linear_solver_variable_set(sys->context, 2, m_vertex_id, v->co[2]);
454  }
455 
457  BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
458  m_vertex_id = BM_elem_index_get(v);
459  EIG_linear_solver_right_hand_side_add(sys->context, 0, m_vertex_id, v->co[0]);
460  EIG_linear_solver_right_hand_side_add(sys->context, 1, m_vertex_id, v->co[1]);
461  EIG_linear_solver_right_hand_side_add(sys->context, 2, m_vertex_id, v->co[2]);
462  i = m_vertex_id;
463  if ((sys->zerola[i] == false) &&
464  /* Non zero check is to account for vertices that aren't connected to a selected face.
465  * Without this wire edges become `nan`, see T89214. */
466  (sys->ring_areas[i] != 0.0f)) {
467  w = sys->vweights[i] * sys->ring_areas[i];
468  sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda_factor / (4.0f * w);
469  w = sys->vlengths[i];
470  sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w;
471 
472  if (!vert_is_boundary(v)) {
474  sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i]));
475  }
476  else {
477  EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_border * 2.0f);
478  }
479  }
480  else {
481  EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f);
482  }
483  }
485 
486  if (EIG_linear_solver_solve(sys->context)) {
487  validate_solution(sys, usex, usey, usez, preserve_volume);
488  }
489 
491 }
typedef float(TangentPoint)[2]
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:92
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:190
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:67
_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 BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
Definition: bmesh_query.c:2076
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static void delete_void_pointer(void *data)
void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op)
static void init_laplacian_matrix(LaplacianSystem *sys)
static void delete_laplacian_system(LaplacianSystem *sys)
static LaplacianSystem * init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts)
static bool vert_is_boundary(BMVert *v)
static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez, int preserve_volume)
#define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE
static void memset_laplacian_system(LaplacianSystem *sys, int val)
#define SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE
static void volume_preservation(BMOperator *op, float vini, float vend, int usex, int usey, int usez)
static void fill_laplacian_matrix(LaplacianSystem *sys)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_variable_unlock(LinearSolver *solver, int index)
LinearSolver * EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs)
void EIG_linear_solver_delete(LinearSolver *solver)
double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index)
void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value)
bool EIG_linear_solver_solve(LinearSolver *solver)
void EIG_linear_solver_variable_lock(LinearSolver *solver, int index)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
LinearSolver * context
int len
Definition: bmesh_class.h:267
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMLoop * next
Definition: bmesh_class.h:233
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:87
int totvert
Definition: bmesh_class.h:297
int totedge
Definition: bmesh_class.h:297
int totloop
Definition: bmesh_class.h:297
int totface
Definition: bmesh_class.h:297
float(* fweights)[3]
Definition: meshlaplacian.c:68
LinearSolver * context
Definition: meshlaplacian.c:60
ccl_device_inline float beta(float x, float y)
Definition: util/math.h:775