Merge GSoC project from branch: Laplacian Smooth (Operator & Modifier)
authorDaniel Genrich <daniel.genrich@gmx.net>
Wed, 24 Oct 2012 10:39:11 +0000 (10:39 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Wed, 24 Oct 2012 10:39:11 +0000 (10:39 +0000)
by Alexander Pinzon Fernandez (apinzonf)

Supported by Google Summer of Code 2012

Project Documentation:
http://wiki.blender.org/index.php/User:Apinzonf

Manual Page:
http://wiki.blender.org/index.php/User:Apinzonf/Doc:2.6/Manual/Modifiers/Deform/Laplacian_Smooth

19 files changed:
release/scripts/startup/bl_ui/properties_data_modifier.py
release/scripts/startup/bl_ui/space_view3d.py
source/blender/bmesh/CMakeLists.txt
source/blender/bmesh/SConscript
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/intern/bmesh_operators_private.h
source/blender/bmesh/operators/bmo_smooth_laplacian.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/MOD_modifiertypes.h
source/blender/modifiers/SConscript
source/blender/modifiers/intern/MOD_laplaciansmooth.c [new file with mode: 0644]
source/blender/modifiers/intern/MOD_util.c

index c205edc0c3c3a4093c9eb400a3328fdc9cc3662a..28d20bcb2d6d8d2bd25a62ea2811e31daba63ecb 100644 (file)
@@ -331,6 +331,20 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
             row.operator("object.hook_select", text="Select")
             row.operator("object.hook_assign", text="Assign")
 
+    def LAPLACIANSMOOTH(self, layout, ob, md):
+        layout.prop(md, "iterations")
+        layout.prop(md, "lamb")
+        layout.prop(md, "lambdaborder")
+        row = layout.row()
+        row.label(text="Axis: ")
+        row.prop(md, "use_x")
+        row.prop(md, "use_y")
+        row.prop(md, "use_z")
+        row = layout.row()
+        row.prop(md, "volume_preservation")
+        layout.label(text="Vertex Group:")
+        layout.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+               
     def LATTICE(self, layout, ob, md):
         split = layout.split()
 
index 6c7f2d1ed5271001ec39dd34ca8504d796e3dd19..d44213c199ac92a0de917a12f4c0fbb80339692a 100644 (file)
@@ -1711,6 +1711,7 @@ class VIEW3D_MT_edit_mesh_specials(Menu):
         layout.operator("mesh.select_all", text="Select Inverse").action = 'INVERT'
         layout.operator("mesh.flip_normals")
         layout.operator("mesh.vertices_smooth", text="Smooth")
+        layout.operator("mesh.vertices_smooth_laplacian", text="Laplacian Smooth")
         layout.operator("mesh.inset")
         layout.operator("mesh.bevel", text="Bevel")
         layout.operator("mesh.bridge_edge_loops")
index 1e39e7f77d38bfec805df9d11240bab6a21899ee..1753fd3650f5b86081478ca13d383d9c9358fa28 100644 (file)
@@ -29,8 +29,7 @@ set(INC
        ../blenlib
        ../makesdna
        ../../../intern/guardedalloc
-       ../../../extern/bullet2/src
-)
+       ../../../extern/bullet2/src     ../../../intern/opennl/extern)
 
 set(INC_SYS
 
@@ -52,6 +51,7 @@ set(SRC
        operators/bmo_mirror.c
        operators/bmo_primitive.c
        operators/bmo_removedoubles.c
+       operators/bmo_smooth_laplacian.c
        operators/bmo_symmetrize.c
        operators/bmo_subdivide.c
        operators/bmo_subdivide.h
index be6332be47805417aee83dfe5a1b80b4c1e29efa..356ee9b41b01c234775533fbe431e6d41f7472a0 100644 (file)
@@ -13,8 +13,7 @@ incs = [
        '../makesdna',
        '../blenkernel',
        '#/intern/guardedalloc',
-        '#/extern/bullet2/src'
-       ]
+       '#/extern/bullet2/src'  '#/intern/opennl/extern',       ]
 
 defs = []
 
index b527cffbfdcaeebae174ac3595b426b18f4539b2..e12e28f8cffd93cbfb2ba4fd02d2662e002132b4 100644 (file)
@@ -113,6 +113,26 @@ static BMOpDefine bmo_smooth_vert_def = {
        0
 };
 
+/*
+ * Vertext Smooth Laplacian 
+ * Smooths vertices by using Laplacian smoothing propose by.
+ * Desbrun, et al. Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow
+*/
+static BMOpDefine bmo_smooth_laplacian_vert_def = {
+       "smooth_laplacian_vert",
+       {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+        {BMO_OP_SLOT_FLT, "lambda"}, //lambda param
+        {BMO_OP_SLOT_FLT, "lambda_border"}, //lambda param in border
+        {BMO_OP_SLOT_BOOL, "use_x"}, //Smooth object along X axis
+        {BMO_OP_SLOT_BOOL, "use_y"}, //Smooth object along Y axis
+        {BMO_OP_SLOT_BOOL, "use_z"}, //Smooth object along Z axis
+        {BMO_OP_SLOT_BOOL, "volume_preservation"}, //Apply volume preservation after smooth
+       {0} /* null-terminating sentinel */,
+       },
+       bmo_smooth_laplacian_vert_exec,
+       0
+};
+
 /*
  * Right-Hand Faces
  *
@@ -1278,6 +1298,7 @@ BMOpDefine *opdefines[] = {
        &bmo_similar_verts_def,
        &bmo_slide_vert_def,
        &bmo_smooth_vert_def,
+       &bmo_smooth_laplacian_vert_def,
        &bmo_solidify_def,
        &bmo_spin_def,
        &bmo_split_def,
index d6135efe19ac7009dd670e6cf6611bbb9b70dd2c..65c9cf0c421e20c960e935b17be34adbc5e99361 100644 (file)
@@ -91,6 +91,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op);
 void bmo_similar_verts_exec(BMesh *bm, BMOperator *op);
 void bmo_slide_vert_exec(BMesh *bm, BMOperator *op);
 void bmo_smooth_vert_exec(BMesh *bm, BMOperator *op);
+void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op);
 void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op);
 void bmo_spin_exec(BMesh *bm, BMOperator *op);
 void bmo_split_edges_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
new file mode 100644 (file)
index 0000000..ccbc85a
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Alexander Pinzon
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/operators/bmo_smooth_laplacian.c
+ *  \ingroup bmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_array.h"
+#include "BLI_heap.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+
+#include "ONL_opennl.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+#define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f
+#define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f
+#define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE 1.8
+#define SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE 0.15
+
+struct BLaplacianSystem {
+       float *eweights;                /* Length weights per Edge */
+       float (*fweights)[3];   /* Cotangent weights per face */
+       float *ring_areas;              /* Total area per ring*/
+       float *vlengths;                /* Total sum of lengths(edges) per vertice*/
+       float *vweights;                /* Total sum of weights per vertice*/
+       int numEdges;                   /* Number of edges*/
+       int numFaces;                   /* Number of faces*/
+       int numVerts;                   /* Number of verts*/
+       short *zerola;                  /* Is zero area or length*/
+
+       /* Pointers to data*/
+       BMesh *bm;
+       BMOperator *op;
+       NLContext *context;
+
+       /*Data*/
+       float min_area;
+};
+typedef struct BLaplacianSystem LaplacianSystem;
+
+static float compute_volume(BMesh *bm, BMOperator *op);
+static float cotan_weight(float *v1, float *v2, float *v3);
+static int vert_is_boundary(BMVert *v);
+static LaplacianSystem * init_laplacian_system( int a_numEdges, int a_numFaces, int a_numVerts);
+static void init_laplacian_matrix(LaplacianSystem * sys);
+static void delete_laplacian_system(LaplacianSystem * sys);
+static void delete_void_pointer(void * data);
+static void fill_laplacian_matrix(LaplacianSystem * sys);
+static void memset_laplacian_system(LaplacianSystem *sys, int val);
+static void validate_solution(LaplacianSystem * sys, int usex, int usey, int usez, float lambda, float lambda_border, int volumepreservation);
+static void volume_preservation(BMesh *bm, BMOperator *op, float vini, float vend, int usex, int usey, int usez);
+
+static void delete_void_pointer(void * data)
+{
+       if (data) {
+               MEM_freeN(data);
+               data = NULL;
+       }
+}
+
+static void delete_laplacian_system(LaplacianSystem * sys) 
+{
+       delete_void_pointer(sys->eweights);
+       delete_void_pointer(sys->fweights);
+       delete_void_pointer(sys->ring_areas);
+       delete_void_pointer(sys->vlengths);
+       delete_void_pointer(sys->vweights);
+       delete_void_pointer(sys->zerola);
+       if (sys->context) {
+               nlDeleteContext(sys->context);
+       }
+       sys->bm = NULL;
+       sys->op = NULL;
+       MEM_freeN(sys);
+}
+
+static void memset_laplacian_system(LaplacianSystem *sys, int val)
+{
+       memset(sys->eweights    , val, sizeof(float) * sys->numEdges);
+       memset(sys->fweights    , val, sizeof(float) * sys->numFaces * 3);
+       memset(sys->ring_areas  , val, sizeof(float) * sys->numVerts);
+       memset(sys->vlengths    , val, sizeof(float) * sys->numVerts);
+       memset(sys->vweights    , val, sizeof(float) * sys->numVerts);
+       memset(sys->zerola              , val, sizeof(short) * sys->numVerts);
+}
+
+static LaplacianSystem * init_laplacian_system( int a_numEdges, int a_numFaces, int a_numVerts) 
+{
+       LaplacianSystem * sys; 
+       sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem");
+       sys->numEdges = a_numEdges;
+       sys->numFaces = a_numFaces;
+       sys->numVerts = a_numVerts;
+
+       sys->eweights =  MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight");
+       if (!sys->eweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->fweights =  MEM_callocN(sizeof(float) * 3 * sys->numFaces, "ModLaplSmoothFWeight");
+       if (!sys->fweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->ring_areas =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothRingAreas");
+       if (!sys->ring_areas) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->vlengths =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVlengths");
+       if (!sys->vlengths) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       sys->vweights =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVweights");
+       if (!sys->vweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       sys->zerola =  MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothZeloa");
+       if (!sys->zerola) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       return sys;
+}
+
+/* Compute weigth between vertice v_i and all your neighbors
+ * weight between v_i and v_neighbor 
+ * Wij = cot(alpha) + cot(beta) / (4.0 * total area of all faces  * sum all weight)
+ *        v_i *
+ *          / | \
+ *         /  |  \
+ *  v_beta*   |   * v_alpha
+ *         \  |  /
+ *          \ | /
+ *            * v_neighbor
+*/
+
+static void init_laplacian_matrix(LaplacianSystem * sys)
+{
+       float areaf;
+       float *v1, *v2, *v3, *v4;
+       float w1, w2, w3, w4;
+       int i, j;
+       int has_4_vert ;
+       unsigned int idv1, idv2, idv3, idv4, idv[4];
+       BMEdge *e;
+       BMFace *f;
+       BMIter eiter;
+       BMIter fiter;
+       BMIter vi;
+       BMVert *vn;
+       BMVert *vf[4];
+
+       BM_ITER_MESH_INDEX (e, &eiter, sys->bm, BM_EDGES_OF_MESH, j) {
+               if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e)) {
+                       v1 = e->v1->co;
+                       v2 =  e->v2->co;
+                       idv1 = BM_elem_index_get(e->v1);
+                       idv2 = BM_elem_index_get(e->v2);
+                       
+                       w1 = len_v3v3(v1, v2);
+                       if (w1 > sys->min_area) {
+                               w1 = 1.0f / w1;
+                               i = BM_elem_index_get(e);
+                               sys->eweights[i] = w1;
+                               sys->vlengths[idv1] += w1;
+                               sys->vlengths[idv2] += w1;
+                       }else{
+                               sys->zerola[idv1] = 1;
+                               sys->zerola[idv2] = 1;
+                       }
+               }
+       }
+
+       BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) {
+               if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+
+                       BM_ITER_ELEM_INDEX (vn, &vi, f, BM_VERTS_OF_FACE, i) {
+                               vf[i] = vn;
+                       }
+                       has_4_vert = (i == 4) ? 1 : 0;
+                       idv1 = BM_elem_index_get(vf[0]);
+                       idv2 = BM_elem_index_get(vf[1]);
+                       idv3 = BM_elem_index_get(vf[2]);
+                       idv4 = has_4_vert ? BM_elem_index_get(vf[3]) : 0;
+
+                       v1 = vf[0]->co;
+                       v2 = vf[1]->co;
+                       v3 = vf[2]->co;
+                       v4 = has_4_vert ? vf[3]->co : 0;
+
+                       if (has_4_vert) {
+                               areaf = area_quad_v3(v1, v2, v3, v4);
+                       } else {
+                               areaf = area_tri_v3(v1, v2, v3);
+                       }
+
+                       if (fabs(areaf) < sys->min_area) { 
+                               sys->zerola[idv1] = 1;
+                               sys->zerola[idv2] = 1;
+                               sys->zerola[idv3] = 1;
+                               if (has_4_vert) sys->zerola[idv4] = 1;
+                       }
+
+                       sys->ring_areas[idv1] += areaf;
+                       sys->ring_areas[idv2] += areaf;
+                       sys->ring_areas[idv3] += areaf;
+                       if (has_4_vert) sys->ring_areas[idv4] += areaf;
+
+                       if (has_4_vert) {
+                       
+                               idv[0] = idv1;
+                               idv[1] = idv2;
+                               idv[2] = idv3;
+                               idv[3] = idv4;
+
+                               for (j = 0; j < 4; j++) {
+                                       idv1 = idv[j];
+                                       idv2 = idv[(j + 1) % 4];
+                                       idv3 = idv[(j + 2) % 4];
+                                       idv4 = idv[(j + 3) % 4];
+
+                                       v1 = vf[j]->co;
+                                       v2 = vf[(j + 1) % 4]->co;
+                                       v3 = vf[(j + 2) % 4]->co;
+                                       v4 = vf[(j + 3) % 4]->co;
+
+                                       w2 = cotan_weight(v4, v1, v2) + cotan_weight(v3, v1, v2);
+                                       w3 = cotan_weight(v2, v3, v1) + cotan_weight(v4, v1, v3);
+                                       w4 = cotan_weight(v2, v4, v1) + cotan_weight(v3, v4, v1);
+       
+                                       sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f;
+                               }
+                       } else {                        
+                               i = BM_elem_index_get(f);
+
+                               w1 = cotan_weight(v1, v2, v3);
+                               w2 = cotan_weight(v2, v3, v1);
+                               w3 = cotan_weight(v3, v1, v2);
+
+                               sys->fweights[i][0] += w1;
+                               sys->fweights[i][1] += w2;
+                               sys->fweights[i][2] += w3;
+                       
+                               sys->vweights[idv1] += w2 + w3;
+                               sys->vweights[idv2] += w1 + w3;
+                               sys->vweights[idv3] += w1 + w2;
+                       }
+               }
+       }
+}
+
+static void fill_laplacian_matrix(LaplacianSystem * sys)
+{
+       float *v1, *v2, *v3, *v4;
+       float w2, w3, w4;
+       int i, j;
+       int has_4_vert ;
+       unsigned int idv1, idv2, idv3, idv4, idv[4];
+
+       BMEdge *e;
+       BMFace *f;
+       BMIter eiter;
+       BMIter fiter;
+       BMIter vi;
+       BMVert *vn;
+       BMVert *vf[4];
+
+       BM_ITER_MESH (f, &fiter, sys->bm, BM_FACES_OF_MESH) {
+               if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+                       BM_ITER_ELEM_INDEX (vn, &vi, f, BM_VERTS_OF_FACE, i) {
+                               vf[i] = vn;
+                       }
+                       has_4_vert = (i == 4) ? 1 : 0;
+                       if (has_4_vert) {
+                               idv[0] = BM_elem_index_get(vf[0]);
+                               idv[1] = BM_elem_index_get(vf[1]);
+                               idv[2] = BM_elem_index_get(vf[2]);
+                               idv[3] = BM_elem_index_get(vf[3]);
+                               for (j = 0; j < 4; j++) {
+                                       idv1 = idv[j];
+                                       idv2 = idv[(j + 1) % 4];
+                                       idv3 = idv[(j + 2) % 4];
+                                       idv4 = idv[(j + 3) % 4];
+
+                                       v1 = vf[j]->co;
+                                       v2 = vf[(j + 1) % 4]->co;
+                                       v3 = vf[(j + 2) % 4]->co;
+                                       v4 = vf[(j + 3) % 4]->co;
+
+                                       w2 = cotan_weight(v4, v1, v2) + cotan_weight(v3, v1, v2);
+                                       w3 = cotan_weight(v2, v3, v1) + cotan_weight(v4, v1, v3);
+                                       w4 = cotan_weight(v2, v4, v1) + cotan_weight(v3, v4, v1);
+
+                                       w2 = w2 / 4.0f;
+                                       w3 = w3 / 4.0f;
+                                       w4 = w4 / 4.0f;
+               
+                                       if (!vert_is_boundary(vf[j]) && sys->zerola[idv1] == 0) { 
+                                               nlMatrixAdd(idv1, idv2, w2 * sys->vweights[idv1]);
+                                               nlMatrixAdd(idv1, idv3, w3 * sys->vweights[idv1]);
+                                               nlMatrixAdd(idv1, idv4, w4 * sys->vweights[idv1]);
+                                       }
+                               }
+                       } else {
+                               idv1 = BM_elem_index_get(vf[0]);
+                               idv2 = BM_elem_index_get(vf[1]);
+                               idv3 = BM_elem_index_get(vf[2]);
+                               /* Is ring if number of faces == number of edges around vertice*/
+                               i = BM_elem_index_get(f);
+                               if (!vert_is_boundary(vf[0]) && sys->zerola[idv1] == 0) { 
+                                       nlMatrixAdd(idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]);
+                                       nlMatrixAdd(idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]);
+                               }
+                               if (!vert_is_boundary(vf[1]) && sys->zerola[idv2] == 0) { 
+                                       nlMatrixAdd(idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]);
+                                       nlMatrixAdd(idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]);
+                               }
+                               if (!vert_is_boundary(vf[2]) && sys->zerola[idv3] == 0) { 
+                                       nlMatrixAdd(idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]);
+                                       nlMatrixAdd(idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]);
+                               }
+                       }
+               }
+       }
+       BM_ITER_MESH (e, &eiter, sys->bm, BM_EDGES_OF_MESH) {
+               if (!BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_boundary(e) ) {
+                       v1 = e->v1->co;
+                       v2 =  e->v2->co;
+                       idv1 = BM_elem_index_get(e->v1);
+                       idv2 = BM_elem_index_get(e->v2);
+                       if (sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) {
+                               i = BM_elem_index_get(e);
+                               nlMatrixAdd(idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
+                               nlMatrixAdd(idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
+                       }
+               }
+       }
+}
+
+static float cotan_weight(float *v1, float *v2, float *v3)
+{
+       float a[3], b[3], c[3], clen;
+
+       sub_v3_v3v3(a, v2, v1);
+       sub_v3_v3v3(b, v3, v1);
+       cross_v3_v3v3(c, a, b);
+
+       clen = len_v3(c);
+
+       if (clen == 0.0f)
+               return 0.0f;
+       
+       return dot_v3v3(a, b) / clen;
+}
+
+static int vert_is_boundary(BMVert *v)
+{
+       BMEdge *ed;
+       BMFace *f;
+       BMIter ei;
+       BMIter fi;
+       BM_ITER_ELEM(ed, &ei, v, BM_EDGES_OF_VERT) {
+               if (BM_edge_is_boundary(ed)) {
+                       return 1;
+               }
+       }
+       BM_ITER_ELEM (f, &fi, v, BM_FACES_OF_VERT) {
+               if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static float compute_volume(BMesh *bm, BMOperator *op)
+{
+       float vol = 0.0f;
+       float x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
+       int i;
+       BMFace *f;
+       BMIter fiter;
+       BMIter vi;
+       BMVert *vn;
+       BMVert *vf[4];
+       
+       BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+               BM_ITER_ELEM_INDEX (vn, &vi, f, BM_VERTS_OF_FACE, i) {
+                       vf[i] = vn;
+               }
+               x1 = vf[0]->co[0];
+               y1 = vf[0]->co[1];
+               z1 = vf[0]->co[2];
+
+               x2 = vf[1]->co[0];
+               y2 = vf[1]->co[1];
+               z2 = vf[1]->co[2];
+
+               x3 = vf[2]->co[0];
+               y3 = vf[2]->co[1];
+               z3 = vf[2]->co[2];
+
+               vol += (1.0 / 6.0) * (0.0 - x3*y2*z1 + x2*y3*z1 + x3*y1*z2 - x1*y3*z2 - x2*y1*z3 + x1*y2*z3);
+
+               if (i == 4) {
+                       x4 = vf[3]->co[0];
+                       y4 = vf[3]->co[1];
+                       z4 = vf[3]->co[2];
+                       vol += (1.0 / 6.0) * (x1*y3*z4 - x1*y4*z3 - x3*y1*z4 + x3*z1*y4 + y1*x4*z3 - x4*y3*z1);
+               }
+       }
+       return fabs(vol);
+}
+
+static void volume_preservation(BMesh *bm, BMOperator *op, float vini, float vend, int usex, int usey, int usez)
+{
+       float beta;
+       BMOIter siter;
+       BMVert *v;
+
+       if (vend != 0.0f) {     
+               beta  = pow (vini / vend, 1.0f / 3.0f);
+               BMO_ITER (v, &siter, bm, op, "verts", BM_VERT) {
+                       if (usex) {
+                               v->co[0] *=  beta;
+                       }
+                       if (usey) {
+                               v->co[1] *= beta;
+                       }
+                       if (usez) {
+                               v->co[2] *= beta;
+                       }
+                       
+               }
+       }
+}
+
+static void validate_solution(LaplacianSystem * sys, int usex, int usey, int usez, float lambda, float lambda_border, int volumepreservation)
+{
+       int m_vertex_id;
+       float leni, lene;
+       float vini, vend;
+       float *vi1, *vi2, ve1[3], ve2[3];
+       unsigned int idv1, idv2;
+       BMOIter siter;
+       BMVert *v;
+       BMEdge *e;
+       BMIter eiter;
+
+       BM_ITER_MESH  (e, &eiter, sys->bm, BM_EDGES_OF_MESH) {
+               idv1 = BM_elem_index_get(e->v1);
+               idv2 = BM_elem_index_get(e->v2);
+               vi1 = e->v1->co;
+               vi2 =  e->v2->co;
+               ve1[0] = nlGetVariable(0, idv1);
+               ve1[1] = nlGetVariable(1, idv1);
+               ve1[2] = nlGetVariable(2, idv1);
+               ve2[0] = nlGetVariable(0, idv2);
+               ve2[1] = nlGetVariable(1, idv2);
+               ve2[2] = nlGetVariable(2, idv2);
+               leni = len_v3v3(vi1, vi2);
+               lene = len_v3v3(ve1, ve2);
+               if ( lene > leni* SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE || lene < leni*SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) {
+                       sys->zerola[idv1] = 1;
+                       sys->zerola[idv2] = 1;
+               }
+       }
+
+       if (volumepreservation) {
+               vini = compute_volume(sys->bm, sys->op);
+       }
+       BMO_ITER (v, &siter, sys->bm, sys->op, "verts", BM_VERT) {
+               m_vertex_id = BM_elem_index_get(v);
+               if (sys->zerola[m_vertex_id] == 0) {
+                       if (usex) {
+                               v->co[0] =  nlGetVariable(0, m_vertex_id);
+                       }
+                       if (usey) {
+                               v->co[1] =  nlGetVariable(1, m_vertex_id);
+                       }
+                       if (usez) {
+                               v->co[2] =  nlGetVariable(2, m_vertex_id);
+                       }
+               }
+       }
+       if (volumepreservation) {
+               vend = compute_volume(sys->bm, sys->op);
+               volume_preservation(sys->bm, sys->op, vini, vend, usex, usey, usez);
+       }
+
+}
+
+void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op)
+{
+       int i;
+       int m_vertex_id;
+       int usex, usey, usez, volumepreservation;
+       float lambda, lambda_border;
+       float w;
+       BMOIter siter;
+       BMVert *v;
+       LaplacianSystem * sys;
+
+       sys = init_laplacian_system(bm->totedge, bm->totface, bm->totvert);
+       if (!sys) return;
+       sys->bm = bm;
+       sys->op = op;
+
+       memset_laplacian_system(sys, 0);
+
+       BM_mesh_elem_index_ensure(bm, BM_VERT);
+       lambda = BMO_slot_float_get(op, "lambda");
+       lambda_border = BMO_slot_float_get(op, "lambda_border");
+       sys->min_area = 0.00001f;
+       usex = BMO_slot_bool_get(op, "use_x");
+       usey = BMO_slot_bool_get(op, "use_y");
+       usez = BMO_slot_bool_get(op, "use_z");
+       volumepreservation = BMO_slot_bool_get(op, "volume_preservation");
+
+
+       nlNewContext();
+       sys->context = nlGetCurrent();
+
+       nlSolverParameteri(NL_NB_VARIABLES, bm->totvert);
+       nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
+       nlSolverParameteri(NL_NB_ROWS, bm->totvert);
+       nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
+
+       nlBegin(NL_SYSTEM);     
+       for (i=0; i < bm->totvert; i++) {
+               nlLockVariable(i);
+       }
+       BMO_ITER (v, &siter, bm, op, "verts", BM_VERT) {
+               m_vertex_id = BM_elem_index_get(v);
+               nlUnlockVariable(m_vertex_id);
+               nlSetVariable(0,m_vertex_id, v->co[0]);
+               nlSetVariable(1,m_vertex_id, v->co[1]);
+               nlSetVariable(2,m_vertex_id, v->co[2]);
+       }
+
+       nlBegin(NL_MATRIX);
+       init_laplacian_matrix(sys);
+       BMO_ITER (v, &siter, bm, op, "verts", BM_VERT) {
+               m_vertex_id = BM_elem_index_get(v);
+               nlRightHandSideAdd(0, m_vertex_id, v->co[0]);
+               nlRightHandSideAdd(1, m_vertex_id, v->co[1]);
+               nlRightHandSideAdd(2, m_vertex_id, v->co[2]);
+               i = m_vertex_id;
+               if (sys->zerola[i] == 0) {
+                       w = sys->vweights[i] * sys->ring_areas[i];
+                       sys->vweights[i] = (w == 0.0f) ? 0.0f : - lambda  / (4.0f * w);
+                       w = sys->vlengths[i];
+                       sys->vlengths[i] = (w == 0.0f) ? 0.0f : - lambda_border  * 2.0f / w;
+
+                       if (!vert_is_boundary(v)) { 
+                               nlMatrixAdd(i, i,  1.0f + lambda / (4.0f * sys->ring_areas[i]));
+                       } else { 
+                               nlMatrixAdd(i, i,  1.0f + lambda_border * 2.0f);
+                       }
+               } else {
+                       nlMatrixAdd(i, i, 1.0f);
+               }       
+       }
+       fill_laplacian_matrix(sys);
+               
+       nlEnd(NL_MATRIX);
+       nlEnd(NL_SYSTEM);
+
+       if (nlSolveAdvanced(NULL, NL_TRUE) ) {
+               validate_solution(sys, usex, usey, usez, lambda, lambda_border, volumepreservation);
+       }
+               
+       delete_laplacian_system(sys);
+}
index 44933f6a1c0894ffd938e510ca557f9cccc99282..4e13833d85cc68d99132fa6de053b8954d20ee2d 100644 (file)
@@ -1666,6 +1666,88 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
 }
 
+static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit = CTX_data_edit_object(C);
+       BMEditMesh *em = BMEdit_FromObject(obedit);
+       int usex = TRUE, usey = TRUE, usez = TRUE, volume_preservation = TRUE;
+       int i, repeat;
+       float lambda = 0.1f;
+       float lambda_border = 0.1f;
+       BMIter fiter;
+       BMFace *f;
+
+       /* Check if select faces are triangles  */
+       BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
+               if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+                       if(f->len > 4) {
+                               BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
+                               return OPERATOR_CANCELLED;
+                       }       
+               }
+       }
+
+       /* mirror before smooth */
+       if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+               EDBM_verts_mirror_cache_begin(em, TRUE);
+       }
+
+       repeat = RNA_int_get(op->ptr, "repeat");
+       lambda = RNA_float_get(op->ptr, "lambda");
+       lambda_border = RNA_float_get(op->ptr, "lambda_border");
+       usex = RNA_boolean_get(op->ptr, "use_x");
+       usey = RNA_boolean_get(op->ptr, "use_y");
+       usez = RNA_boolean_get(op->ptr, "use_z");
+       volume_preservation = RNA_boolean_get(op->ptr, "volume_preservation");
+       if (!repeat)
+               repeat = 1;
+       
+       for (i = 0; i < repeat; i++) {
+               if (!EDBM_op_callf(em, op,
+                                  "smooth_laplacian_vert verts=%hv lambda=%f lambda_border=%f use_x=%b use_y=%b use_z=%b volume_preservation=%b",
+                                  BM_ELEM_SELECT, lambda, lambda_border, usex, usey, usez, volume_preservation))
+               {
+                       return OPERATOR_CANCELLED;
+               }
+       }
+
+       /* apply mirror */
+       if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+               EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
+               EDBM_verts_mirror_cache_end(em);
+       }
+
+       EDBM_update_generic(C, em, TRUE);
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Laplacian Smooth Vertex";
+       ot->description = "Laplacian smooth of selected vertices";
+       ot->idname = "MESH_OT_vertices_smooth_laplacian";
+       
+       /* api callbacks */
+       ot->exec = edbm_do_smooth_laplacian_vertex_exec;
+       ot->poll = ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       RNA_def_int(ot->srna, "repeat", 1, 1, 200, 
+                                       "Number of iterations to smooth the mesh", "", 1, 200);
+       RNA_def_float(ot->srna, "lambda", 0.00005f, 0.0000001f, 1000.0f, 
+                                       "Lambda factor", "", 0.0000001f, 1000.0f);
+       RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f, 
+                                       "Lambda factor in border", "", 0.0000001f, 1000.0f);
+       RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along     X axis");
+       RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along     Y axis");
+       RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along     Z axis");
+       RNA_def_boolean(ot->srna, "volume_preservation", 1, "Preserve Volume", "Apply volume preservation after smooth");
+}
+
 /********************** Smooth/Solid Operators *************************/
 
 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
index 5c782dc2266f86adabce675f7cb618130ba77b61..8b56109202a7e4fb2f890f24300e602a8ccd1b8a 100644 (file)
@@ -134,6 +134,7 @@ void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
 void MESH_OT_mark_seam(struct wmOperatorType *ot);
 void MESH_OT_mark_sharp(struct wmOperatorType *ot);
 void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
+void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot);
 void MESH_OT_noise(struct wmOperatorType *ot);
 void MESH_OT_flip_normals(struct wmOperatorType *ot);
 void MESH_OT_solidify(struct wmOperatorType *ot);
index 864db7f096d70b6f5c53cc6fc57b03d216458ec7..716af1d938beca6d6a00e304f656929198e364fb 100644 (file)
@@ -133,6 +133,7 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_mark_seam);
        WM_operatortype_append(MESH_OT_mark_sharp);
        WM_operatortype_append(MESH_OT_vertices_smooth);
+       WM_operatortype_append(MESH_OT_vertices_smooth_laplacian);
        WM_operatortype_append(MESH_OT_noise);
        WM_operatortype_append(MESH_OT_flip_normals);
        WM_operatortype_append(MESH_OT_rip);
index 51935b24de3dfcdf7260bdde94a3a99337498c4f..f6a167aefe6de7ad0b3067d04869157011bd3414 100644 (file)
@@ -1000,6 +1000,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
                                        case eModifierType_Bevel:
                                                UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
                                        case eModifierType_Smooth:
+                                       case eModifierType_LaplacianSmooth:
                                                UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
                                        case eModifierType_SimpleDeform:
                                                UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
index af8716b0fb5c83d956a68c7afe6c04d6bfb02304..c9e929ce41b5982d5376fa1954491be3537584e7 100644 (file)
@@ -75,6 +75,7 @@ typedef enum ModifierType {
        eModifierType_DynamicPaint      = 40,
        eModifierType_Remesh            = 41,
        eModifierType_Skin              = 42,
+       eModifierType_LaplacianSmooth   = 43,
        NUM_MODIFIER_TYPES
 } ModifierType;
 
@@ -1112,4 +1113,17 @@ enum {
        MOD_SKIN_SMOOTH_SHADING = 1
 };
 
+/* Smooth modifier flags */
+#define MOD_LAPLACIANSMOOTH_X (1<<1)
+#define MOD_LAPLACIANSMOOTH_Y (1<<2)
+#define MOD_LAPLACIANSMOOTH_Z (1<<3)
+#define MOD_LAPLACIANSMOOTH_VOLUME_PRESERVATION (1<<4)
+
+typedef struct LaplacianSmoothModifierData {
+       ModifierData modifier;
+       float lambda, lambda_border, pad1;
+       char defgrp_name[64]; /* MAX_VGROUP_NAME */
+       short flag, repeat;
+} LaplacianSmoothModifierData;
+
 #endif
index 042acbd5b11272d48493bac52327fe8fd1133c70..60ab231ffc91ba39ee62f0e119d1b3782fba3555 100644 (file)
@@ -286,6 +286,7 @@ extern StructRNA RNA_KinematicConstraint;
 extern StructRNA RNA_Lamp;
 extern StructRNA RNA_LampSkySettings;
 extern StructRNA RNA_LampTextureSlot;
+extern StructRNA RNA_LaplacianSmoothModifier;
 extern StructRNA RNA_Lattice;
 extern StructRNA RNA_LatticeModifier;
 extern StructRNA RNA_LatticePoint;
index 1ec2c391efc99431697c84e217c7cf569dbf094d..f94fbc8b1d6364ae9cd3d2350a50c7a111895c12 100644 (file)
@@ -84,6 +84,7 @@ EnumPropertyItem modifier_type_items[] = {
        {eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
        {eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
        {eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
+       {eModifierType_LaplacianSmooth, "LAPLACIANSMOOTH", ICON_MOD_SMOOTH, "Laplacian Smooth", ""},
        {eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""},
        {eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""},
        {eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
@@ -210,6 +211,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
                        return &RNA_RemeshModifier;
                case eModifierType_Skin:
                        return &RNA_SkinModifier;
+               case eModifierType_LaplacianSmooth:
+                       return &RNA_LaplacianSmoothModifier;
                default:
                        return &RNA_Modifier;
        }
@@ -359,6 +362,12 @@ static void rna_SmoothModifier_vgroup_set(PointerRNA *ptr, const char *value)
        rna_object_vgroup_name_set(ptr, value, lmd->defgrp_name, sizeof(lmd->defgrp_name));
 }
 
+static void rna_LaplacianSmoothModifier_vgroup_set(PointerRNA *ptr, const char *value)
+{
+       LaplacianSmoothModifierData *lmd = (LaplacianSmoothModifierData *)ptr->data;
+       rna_object_vgroup_name_set(ptr, value, lmd->defgrp_name, sizeof(lmd->defgrp_name));
+}
+
 static void rna_WaveModifier_vgroup_set(PointerRNA *ptr, const char *value)
 {
        WaveModifierData *lmd = (WaveModifierData *)ptr->data;
@@ -1780,6 +1789,64 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 }
 
+static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "LaplacianSmoothModifier", "Modifier");
+       RNA_def_struct_ui_text(srna, "Laplacian Smooth Modifier", "Smoothing effect modifier");
+       RNA_def_struct_sdna(srna, "LaplacianSmoothModifierData");
+       RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+       prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_X);
+       RNA_def_property_ui_text(prop, "X", "Smooth object along X axis");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "use_y", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_Y);
+       RNA_def_property_ui_text(prop, "Y", "Smooth object along Y axis");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "use_z", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_Z);
+       RNA_def_property_ui_text(prop, "Z", "Smooth object along Z axis");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "volume_preservation", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_VOLUME_PRESERVATION);
+       RNA_def_property_ui_text(prop, "Preserve Volume", "Apply volume preservation after smooth");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "lamb", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "lambda");
+       RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+       RNA_def_property_ui_range(prop, 0.0000001, 1000.0, 0.0000001, 8);
+       RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "lambdaborder", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "lambda_border");
+       RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+       RNA_def_property_ui_range(prop, 0.0000001, 1000.0, 0.0000001, 8);
+       RNA_def_property_ui_text(prop, "Lambda border", "Lambda factor in border");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "repeat");
+       RNA_def_property_ui_range(prop, 0, 200, 1, 0);
+       RNA_def_property_ui_text(prop, "Repeat", "");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+       
+       prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+       RNA_def_property_ui_text(prop, "Vertex Group",
+                                "Name of Vertex Group which determines influence of modifier per point");
+       RNA_def_property_string_funcs(prop, NULL, NULL, "rna_LaplacianSmoothModifier_vgroup_set");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
 static void rna_def_modifier_cast(BlenderRNA *brna)
 {
        StructRNA *srna;
@@ -3394,6 +3461,7 @@ void RNA_def_modifier(BlenderRNA *brna)
        rna_def_modifier_ocean(brna);
        rna_def_modifier_remesh(brna);
        rna_def_modifier_skin(brna);
+       rna_def_modifier_laplaciansmooth(brna);
 }
 
 #endif
index 2d07dda789506a163b05f49c062838300fecb50e..3a7066ff41a0847fa1bacb1da2c5d49bb6106991 100644 (file)
@@ -38,6 +38,7 @@ set(INC
        ../render/extern/include
        ../../../intern/elbeem/extern
        ../../../intern/guardedalloc
+       ../../../intern/opennl/extern
 )
 
 set(INC_SYS
@@ -64,6 +65,7 @@ set(SRC
        intern/MOD_fluidsim_util.c
        intern/MOD_hook.c
        intern/MOD_lattice.c
+       intern/MOD_laplaciansmooth.c
        intern/MOD_mask.c
        intern/MOD_meshdeform.c
        intern/MOD_mirror.c
index 51e574e276dd6906dc1b7f21c2bde87f09f01cca..a4817ff775dec504fc45faa278dddc89f6b7f04a 100644 (file)
@@ -75,6 +75,7 @@ extern ModifierTypeInfo modifierType_WeightVGProximity;
 extern ModifierTypeInfo modifierType_DynamicPaint;
 extern ModifierTypeInfo modifierType_Remesh;
 extern ModifierTypeInfo modifierType_Skin;
+extern ModifierTypeInfo modifierType_LaplacianSmooth;
 
 /* MOD_util.c */
 void modifier_type_init(ModifierTypeInfo *types[]);
index 9059ae210e36b753a448a17f6afb23cbb0217de7..62fd9ba2de1811dec467b6741d8b1e7b8c2ab57b 100644 (file)
@@ -4,7 +4,7 @@ Import ('env')
 sources = env.Glob('intern/*.c')
 
 incs = '. ./intern'
-incs += ' #/intern/guardedalloc #/intern/bsp/extern #/intern/elbeem/extern #/extern/glew/include'
+incs += ' #/intern/guardedalloc #/intern/bsp/extern #/intern/elbeem/extern #/extern/glew/include #/intern/opennl/extern'
 incs += ' ../render/extern/include ../blenloader ../bmesh'
 incs += ' ../include ../blenlib ../blenfont ../makesdna ../makesrna ../blenkernel ../blenkernel/intern'
 incs += ' ../gpu'
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
new file mode 100644 (file)
index 0000000..103d959
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Alexander Pinzon
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_laplaciansmooth.c
+ *  \ingroup modifiers
+ */
+
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#include "ONL_opennl.h"
+
+#define MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE 1.8
+#define MOD_LAPLACIANSMOOTH_MIN_EDGE_PERCENTAGE 0.02
+
+struct BLaplacianSystem {
+       float *eweights;                /* Length weights per Edge */
+       float (*fweights)[3];   /* Cotangent weights per face */
+       float *ring_areas;              /* Total area per ring*/
+       float *vlengths;                /* Total sum of lengths(edges) per vertice*/
+       float *vweights;                /* Total sum of weights per vertice*/
+       int numEdges;                   /* Number of edges*/
+       int numFaces;                   /* Number of faces*/
+       int numVerts;                   /* Number of verts*/
+       short *numNeFa;                 /* Number of neighboors faces around vertice*/
+       short *numNeEd;                 /* Number of neighboors Edges around vertice*/
+       short *zerola;                  /* Is zero area or length*/
+
+       /* Pointers to data*/
+       float (*vertexCos)[3];
+       MFace *mfaces;  
+       MEdge *medges;
+       NLContext *context;
+
+       /*Data*/
+       float min_area;
+       float vert_centroid[3];
+};
+typedef struct BLaplacianSystem LaplacianSystem;
+
+static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md);
+static int is_disabled(ModifierData *md, int UNUSED(useRenderParams));
+static float compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces);
+static float cotan_weight(float *v1, float *v2, float *v3);
+static LaplacianSystem * init_laplacian_system( int a_numEdges, int a_numFaces, int a_numVerts);
+static void copy_data(ModifierData *md, ModifierData *target);
+static void delete_laplacian_system(LaplacianSystem * sys);
+static void delete_void_pointer(void * data);
+static void fill_laplacian_matrix(LaplacianSystem * sys);
+static void init_data(ModifierData *md);
+static void init_laplacian_matrix(LaplacianSystem * sys);
+static void memset_laplacian_system(LaplacianSystem *sys, int val);
+static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag);
+static void validate_solution(LaplacianSystem * sys, short flag, float lambda, float lambda_border);
+
+static void delete_void_pointer(void * data)
+{
+       if (data) {
+               MEM_freeN(data);
+               data = NULL;
+       }
+}
+
+static void delete_laplacian_system(LaplacianSystem * sys) 
+{
+       delete_void_pointer(sys->eweights);
+       delete_void_pointer(sys->fweights);
+       delete_void_pointer(sys->numNeEd);
+       delete_void_pointer(sys->numNeFa);
+       delete_void_pointer(sys->ring_areas);
+       delete_void_pointer(sys->vlengths);
+       delete_void_pointer(sys->vweights);
+       delete_void_pointer(sys->zerola);
+       if (sys->context) {
+               nlDeleteContext(sys->context);
+       }
+       sys->vertexCos = NULL;
+       sys->mfaces = NULL;     
+       sys->medges = NULL;
+       MEM_freeN(sys);
+}
+
+static void memset_laplacian_system(LaplacianSystem *sys, int val)
+{
+       memset(sys->eweights    , val, sizeof(float) * sys->numEdges);
+       memset(sys->fweights    , val, sizeof(float) * sys->numFaces * 3);
+       memset(sys->numNeEd             , val, sizeof(short) * sys->numVerts);
+       memset(sys->numNeFa             , val, sizeof(short) * sys->numVerts);
+       memset(sys->ring_areas  , val, sizeof(float) * sys->numVerts);
+       memset(sys->vlengths    , val, sizeof(float) * sys->numVerts);
+       memset(sys->vweights    , val, sizeof(float) * sys->numVerts);
+       memset(sys->zerola              , val, sizeof(short) * sys->numVerts);
+}
+
+static LaplacianSystem * init_laplacian_system( int a_numEdges, int a_numFaces, int a_numVerts) 
+{
+       LaplacianSystem * sys; 
+       sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem");
+       sys->numEdges = a_numEdges;
+       sys->numFaces = a_numFaces;
+       sys->numVerts = a_numVerts;
+
+       sys->eweights =  MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight");
+       if (!sys->eweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->fweights =  MEM_callocN(sizeof(float) * 3 * sys->numFaces, "ModLaplSmoothFWeight");
+       if (!sys->fweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       sys->numNeEd =  MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothNumNeEd");
+       if (!sys->numNeEd) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->numNeFa =  MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothNumNeFa");
+       if (!sys->numNeFa) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->ring_areas =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothRingAreas");
+       if (!sys->ring_areas) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+       
+       sys->vlengths =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVlengths");
+       if (!sys->vlengths) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       sys->vweights =  MEM_callocN(sizeof(float) * sys->numVerts, "ModLaplSmoothVweights");
+       if (!sys->vweights) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       sys->zerola =  MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothZeloa");
+       if (!sys->zerola) {
+               delete_laplacian_system(sys);
+               return NULL;
+       }
+
+       return sys;
+}
+
+static void init_data(ModifierData *md)
+{
+       LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
+       smd->lambda = 0.00001f;
+       smd->lambda_border = 0.00005f;
+       smd->repeat = 1;
+       smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | MOD_LAPLACIANSMOOTH_VOLUME_PRESERVATION;
+       smd->defgrp_name[0] = '\0';
+}
+
+static void copy_data(ModifierData *md, ModifierData *target)
+{
+       LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
+       LaplacianSmoothModifierData *tsmd = (LaplacianSmoothModifierData *) target;
+
+       tsmd->lambda = smd->lambda;
+       tsmd->lambda_border = smd->lambda_border;
+       tsmd->repeat = smd->repeat;
+       tsmd->flag = smd->flag;
+       BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->defgrp_name));
+}
+
+static int is_disabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+       LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
+       short flag;
+
+       flag = smd->flag & (MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z);
+
+       /* disable if modifier is off for X, Y and Z or if factor is 0 */
+       if ( flag == 0) return 1;
+
+       return 0;
+}
+
+static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md)
+{
+       LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *)md;
+       CustomDataMask dataMask = 0;
+
+       /* ask for vertexgroups if we need them */
+       if (smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
+
+       return dataMask;
+}
+
+static float cotan_weight(float *v1, float *v2, float *v3)
+{
+       float a[3], b[3], c[3], clen;
+
+       sub_v3_v3v3(a, v2, v1);
+       sub_v3_v3v3(b, v3, v1);
+       cross_v3_v3v3(c, a, b);
+
+       clen = len_v3(c);
+
+       if (clen == 0.0f)
+               return 0.0f;
+       
+       return dot_v3v3(a, b) / clen;
+}
+
+static float compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces)
+{
+       float vol = 0.0f;
+       float x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
+       int i;
+       float *vf[4];
+       for (i = 0; i<numFaces; i++) {
+               vf[0] = vertexCos[mfaces[i].v1];
+               vf[1] = vertexCos[mfaces[i].v2];
+               vf[2] = vertexCos[mfaces[i].v3];
+
+               x1 = vf[0][0];
+               y1 = vf[0][1];
+               z1 = vf[0][2];
+
+               x2 = vf[1][0];
+               y2 = vf[1][1];
+               z2 = vf[1][2];
+
+               x3 = vf[2][0];
+               y3 = vf[2][1];
+               z3 = vf[2][2];
+               
+
+               vol +=  (1.0 / 6.0) * (x2*y3*z1 + x3*y1*z2 - x1*y3*z2 - x2*y1*z3 + x1*y2*z3 - x3*y2*z1);
+               if ((&mfaces[i])->v4) {
+                       vf[3] = vertexCos[mfaces[i].v4];
+                       x4 = vf[3][0];
+                       y4 = vf[3][1];
+                       z4 = vf[3][2];
+                       vol += (1.0 / 6.0) * (x1*y3*z4 - x1*y4*z3 - x3*y1*z4 + x3*z1*y4 + y1*x4*z3 - x4*y3*z1);
+               }
+       }
+       return fabs(vol);
+}
+
+static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag)
+{
+       float beta;
+       int i;
+
+       if (vend != 0.0f) {     
+               beta  = pow (vini / vend, 1.0f / 3.0f);
+               for (i = 0; i < sys->numVerts; i++) {
+                       if (flag & MOD_LAPLACIANSMOOTH_X) {
+                               sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0])* beta + sys->vert_centroid[0];
+                       }
+                       if (flag & MOD_LAPLACIANSMOOTH_Y) {
+                               sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1])* beta + sys->vert_centroid[1];
+                       }
+                       if (flag & MOD_LAPLACIANSMOOTH_Z) {
+                               sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2])* beta + sys->vert_centroid[2];
+                       }
+                       
+               }
+       }
+}
+
+static void init_laplacian_matrix(LaplacianSystem * sys)
+{
+       float *v1, *v2, *v3, *v4;
+       float w1, w2, w3, w4;
+       float areaf;
+       int i, j;
+       unsigned int idv1, idv2, idv3, idv4, idv[4];
+       int has_4_vert ;
+       for ( i = 0; i < sys->numEdges; i++) {
+               idv1 = sys->medges[i].v1;
+               idv2 = sys->medges[i].v2;
+
+               v1 = sys->vertexCos[idv1];
+               v2 = sys->vertexCos[idv2];
+
+               sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1;
+               sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1;
+               w1 = len_v3v3(v1, v2);
+               if (w1 < sys->min_area) {
+                       sys->zerola[idv1] = 1;
+                       sys->zerola[idv2] = 1;
+               } else {
+                       w1 = 1.0f / w1;
+               }
+               
+               sys->eweights[i] = w1;
+       }
+       for ( i = 0; i < sys->numFaces; i++) {
+               has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0;
+
+               idv1 = sys->mfaces[i].v1;
+               idv2 = sys->mfaces[i].v2;
+               idv3 = sys->mfaces[i].v3;
+               idv4 = has_4_vert ? sys->mfaces[i].v4 : 0;
+               
+               sys->numNeFa[idv1] += 1;
+               sys->numNeFa[idv2] += 1;
+               sys->numNeFa[idv3] += 1;
+               if (has_4_vert) sys->numNeFa[idv4] += 1;
+
+               v1 = sys->vertexCos[idv1];
+               v2 = sys->vertexCos[idv2];
+               v3 = sys->vertexCos[idv3];
+               v4 = has_4_vert ? sys->vertexCos[idv4] : 0;
+               
+               if (has_4_vert) {
+                       areaf = area_quad_v3(v1, v2, v3, sys->vertexCos[sys->mfaces[i].v4]);
+               } else {
+                       areaf = area_tri_v3(v1, v2, v3);
+               }
+               if (fabs(areaf) < sys->min_area) { 
+                       sys->zerola[idv1] = 1;
+                       sys->zerola[idv2] = 1;
+                       sys->zerola[idv3] = 1;
+                       if (has_4_vert) sys->zerola[idv4] = 1;
+               }
+
+               sys->ring_areas[idv1] += areaf;
+               sys->ring_areas[idv2] += areaf;
+               sys->ring_areas[idv3] += areaf;
+               if (has_4_vert) sys->ring_areas[idv4] += areaf;
+
+               if (has_4_vert) {
+                       
+                       idv[0] = idv1;
+                       idv[1] = idv2;
+                       idv[2] = idv3;
+                       idv[3] = idv4;
+
+                       for (j = 0; j < 4; j++) {
+                               idv1 = idv[j];
+                               idv2 = idv[(j + 1) % 4];
+                               idv3 = idv[(j + 2) % 4];
+                               idv4 = idv[(j + 3) % 4];
+
+                               v1 = sys->vertexCos[idv1];
+                               v2 = sys->vertexCos[idv2];
+                               v3 = sys->vertexCos[idv3];
+                               v4 = sys->vertexCos[idv4];
+
+                               w2 = cotan_weight(v4, v1, v2) + cotan_weight(v3, v1, v2);
+                               w3 = cotan_weight(v2, v3, v1) + cotan_weight(v4, v1, v3);
+                               w4 = cotan_weight(v2, v4, v1) + cotan_weight(v3, v4, v1);
+       
+                               sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f;
+                       }
+               } else {                        
+                       w1 = cotan_weight(v1, v2, v3);
+                       w2 = cotan_weight(v2, v3, v1);
+                       w3 = cotan_weight(v3, v1, v2);
+
+                       sys->fweights[i][0] = sys->fweights[i][0] + w1;
+                       sys->fweights[i][1] = sys->fweights[i][1] + w2;
+                       sys->fweights[i][2] = sys->fweights[i][2] + w3;
+                       
+                       sys->vweights[idv1] = sys->vweights[idv1] + w2 + w3;
+                       sys->vweights[idv2] = sys->vweights[idv2] + w1 + w3;
+                       sys->vweights[idv3] = sys->vweights[idv3] + w1 + w2;
+               }
+       }
+       for ( i = 0; i < sys->numEdges; i++) {
+               idv1 = sys->medges[i].v1;
+               idv2 = sys->medges[i].v2;
+               /* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */
+               if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { 
+                       sys->vlengths[idv1] += sys->eweights[i];
+                       sys->vlengths[idv2] += sys->eweights[i];
+               }
+       }
+
+}
+
+static void fill_laplacian_matrix(LaplacianSystem * sys)
+{
+       float *v1, *v2, *v3, *v4;
+       float w2, w3, w4;
+       int i, j;
+       int has_4_vert ;
+       unsigned int idv1, idv2, idv3, idv4, idv[4];
+       
+       for ( i = 0; i < sys->numFaces; i++) {
+               idv1 = sys->mfaces[i].v1;
+               idv2 = sys->mfaces[i].v2;
+               idv3 = sys->mfaces[i].v3;
+               has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0;
+
+               if (has_4_vert) {
+                       idv[0] = sys->mfaces[i].v1;
+                       idv[1] = sys->mfaces[i].v2;
+                       idv[2] = sys->mfaces[i].v3;
+                       idv[3] = sys->mfaces[i].v4;
+                       for (j = 0; j < 4; j++) {
+                               idv1 = idv[j];
+                               idv2 = idv[(j + 1) % 4];
+                               idv3 = idv[(j + 2) % 4];
+                               idv4 = idv[(j + 3) % 4];
+
+                               v1 = sys->vertexCos[idv1];
+                               v2 = sys->vertexCos[idv2];
+                               v3 = sys->vertexCos[idv3];
+                               v4 = sys->vertexCos[idv4];
+
+                               w2 = cotan_weight(v4, v1, v2) + cotan_weight(v3, v1, v2);
+                               w3 = cotan_weight(v2, v3, v1) + cotan_weight(v4, v1, v3);
+                               w4 = cotan_weight(v2, v4, v1) + cotan_weight(v3, v4, v1);
+
+                               w2 = w2 / 4.0f;
+                               w3 = w3 / 4.0f;
+                               w4 = w4 / 4.0f;
+               
+                               if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) { 
+                                       nlMatrixAdd(idv1, idv2, w2 * sys->vweights[idv1]);
+                                       nlMatrixAdd(idv1, idv3, w3 * sys->vweights[idv1]);
+                                       nlMatrixAdd(idv1, idv4, w4 * sys->vweights[idv1]);
+                               }
+                       }
+               } else {
+                       /* Is ring if number of faces == number of edges around vertice*/
+                       if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) { 
+                               nlMatrixAdd(idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]);
+                               nlMatrixAdd(idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]);
+                       }
+                       if (sys->numNeEd[idv2] == sys->numNeFa[idv2] && sys->zerola[idv2] == 0) { 
+                               nlMatrixAdd(idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]);
+                               nlMatrixAdd(idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]);
+                       }
+                       if (sys->numNeEd[idv3] == sys->numNeFa[idv3] && sys->zerola[idv3] == 0) { 
+                               nlMatrixAdd(idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]);
+                               nlMatrixAdd(idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]);
+                       }
+               }
+       }
+
+       for ( i = 0; i < sys->numEdges; i++) {
+               idv1 = sys->medges[i].v1;
+               idv2 = sys->medges[i].v2;
+               /* Is boundary */
+               if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && 
+                       sys->numNeEd[idv2] != sys->numNeFa[idv2] && 
+                       sys->zerola[idv1] == 0 && 
+                       sys->zerola[idv2] == 0) 
+               {
+                       nlMatrixAdd(idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
+                       nlMatrixAdd(idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
+               }       
+       }
+}
+
+static void validate_solution(LaplacianSystem * sys, short flag, float lambda, float lambda_border)
+{
+       int i, idv1, idv2;
+       float leni, lene;
+       float vini, vend;
+       float *vi1, *vi2, ve1[3], ve2[3];
+       if (flag & MOD_LAPLACIANSMOOTH_VOLUME_PRESERVATION) {
+               vini = compute_volume(sys->vertexCos, sys->mfaces, sys->numFaces);
+       }
+       for ( i = 0; i < sys->numEdges; i++) {
+               idv1 = sys->medges[i].v1;
+               idv2 = sys->medges[i].v2;
+               vi1 = sys->vertexCos[idv1];
+               vi2 = sys->vertexCos[idv2];
+               ve1[0] = nlGetVariable(0, idv1);
+               ve1[1] = nlGetVariable(1, idv1);
+               ve1[2] = nlGetVariable(2, idv1);
+               ve2[0] = nlGetVariable(0, idv2);
+               ve2[1] = nlGetVariable(1, idv2);
+               ve2[2] = nlGetVariable(2, idv2);
+               leni = len_v3v3(vi1, vi2);
+               lene = len_v3v3(ve1, ve2);
+               if ( lene > leni*MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE || lene < leni*MOD_LAPLACIANSMOOTH_MIN_EDGE_PERCENTAGE ){
+                       sys->zerola[idv1] = 1;
+                       sys->zerola[idv2] = 1;
+               }
+       }
+       for (i = 0; i < sys->numVerts; i++) {
+               if (sys->zerola[i] == 0) {
+                       if (flag & MOD_LAPLACIANSMOOTH_X) {
+                               sys->vertexCos[i][0] = nlGetVariable(0, i);
+                       }
+                       if (flag & MOD_LAPLACIANSMOOTH_Y) {
+                               sys->vertexCos[i][1] = nlGetVariable(1, i);
+                       }
+                       if (flag & MOD_LAPLACIANSMOOTH_Z) {
+                               sys->vertexCos[i][2] = nlGetVariable(2, i);
+                       }
+               }
+       }
+       if (flag & MOD_LAPLACIANSMOOTH_VOLUME_PRESERVATION) {
+               vend = compute_volume(sys->vertexCos, sys->mfaces, sys->numFaces);
+               volume_preservation(sys, vini, vend, flag);
+       }
+}
+
+static void laplaciansmoothModifier_do(
+        LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
+        float (*vertexCos)[3], int numVerts)
+{
+       LaplacianSystem *sys;
+       MDeformVert *dvert = NULL;
+       MDeformVert *dv = NULL;
+       float w, wpaint;
+       int i, iter;
+       int defgrp_index;
+
+       DM_ensure_tessface(dm);
+
+       sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumTessFaces(dm), numVerts);
+       if(!sys) return;
+
+       sys->mfaces = dm->getTessFaceArray(dm);
+       sys->medges = dm->getEdgeArray(dm);
+       sys->vertexCos = vertexCos;
+       sys->min_area = 0.00001f;
+       modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+
+       sys->vert_centroid[0] = 0.0f;
+       sys->vert_centroid[1] = 0.0f;
+       sys->vert_centroid[2] = 0.0f;
+       for (iter = 0; iter < smd->repeat; iter++) {
+               memset_laplacian_system(sys, 0);
+               nlNewContext();
+               sys->context = nlGetCurrent();
+               nlSolverParameteri(NL_NB_VARIABLES, numVerts);
+               nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
+               nlSolverParameteri(NL_NB_ROWS, numVerts);
+               nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
+
+               init_laplacian_matrix(sys);
+
+               nlBegin(NL_SYSTEM);     
+               for (i = 0; i < numVerts; i++) {
+                       nlSetVariable(0, i, vertexCos[i][0]);
+                       nlSetVariable(1, i, vertexCos[i][1]);
+                       nlSetVariable(2, i, vertexCos[i][2]);
+                       if (iter == 0) {
+                               sys->vert_centroid[0] += vertexCos[i][0];
+                               sys->vert_centroid[1] += vertexCos[i][1];
+                               sys->vert_centroid[2] += vertexCos[i][2];
+                       }
+               }
+               if (iter == 0 && numVerts >0) {
+                       sys->vert_centroid[0] = sys->vert_centroid[0] / numVerts;
+                       sys->vert_centroid[1] = sys->vert_centroid[1] / numVerts;
+                       sys->vert_centroid[2] = sys->vert_centroid[2] / numVerts;
+               }
+
+               nlBegin(NL_MATRIX);
+               dv = dvert;
+               for (i = 0; i < numVerts; i++) {
+                       nlRightHandSideAdd(0, i, vertexCos[i][0]);
+                       nlRightHandSideAdd(1, i, vertexCos[i][1]);
+                       nlRightHandSideAdd(2, i, vertexCos[i][2]);
+                       if (dv) {
+                               wpaint = defvert_find_weight(dv, defgrp_index);
+                               dv++;
+                       } else {
+                               wpaint = 1.0f;
+                       }
+                       if (sys->zerola[i] == 0) {
+                               w = sys->vweights[i] * sys->ring_areas[i];
+                               sys->vweights[i] = (w == 0.0f) ? 0.0f : - smd->lambda * wpaint / (4.0f * w);
+                               w = sys->vlengths[i];
+                               sys->vlengths[i] = (w == 0.0f) ? 0.0f : - smd->lambda_border * wpaint * 2.0f / w;
+
+                               if (sys->numNeEd[i] == sys->numNeFa[i]) { 
+                                       nlMatrixAdd(i, i,  1.0f + smd->lambda * wpaint / (4.0f * sys->ring_areas[i]));
+                               } else { 
+                                       nlMatrixAdd(i, i,  1.0f + smd->lambda_border * wpaint * 2.0f);
+                               }
+                       } else {
+                               nlMatrixAdd(i, i, 1.0f);
+                       }
+               }
+
+               fill_laplacian_matrix(sys);
+
+               nlEnd(NL_MATRIX);
+               nlEnd(NL_SYSTEM);
+
+               if (nlSolveAdvanced(NULL, NL_TRUE)) {
+                       validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
+               }
+               nlDeleteContext(sys->context);
+               sys->context = NULL;
+       }
+       delete_laplacian_system(sys);
+
+}
+
+static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                        float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+{
+       DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, 0);
+
+       laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ob, dm,
+                         vertexCos, numVerts);
+
+       if (dm != derivedData)
+               dm->release(dm);
+}
+
+static void deformVertsEM(
+        ModifierData *md, Object *ob, struct BMEditMesh *editData,
+        DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+       DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, 0);
+
+       laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ob, dm,
+                         vertexCos, numVerts);
+
+       if (dm != derivedData)
+               dm->release(dm);
+}
+
+
+ModifierTypeInfo modifierType_LaplacianSmooth = {
+       /* name */              "Laplacian Smooth",
+       /* structName */        "LaplacianSmoothModifierData",
+       /* structSize */        sizeof(LaplacianSmoothModifierData),
+       /* type */              eModifierTypeType_OnlyDeform,
+       /* flags */             eModifierTypeFlag_AcceptsMesh |
+                               eModifierTypeFlag_SupportsEditmode,
+
+       /* copy_data */         copy_data,
+       /* deformVerts */       deformVerts,
+       /* deformMatrices */    NULL,
+       /* deformVertsEM */     deformVertsEM,
+       /* deformMatricesEM */  NULL,
+       /* applyModifier */     NULL,
+       /* applyModifierEM */   NULL,
+       /* init_data */         init_data,
+       /* required_data_mask */  required_data_mask,
+       /* freeData */          NULL,
+       /* is_disabled */       is_disabled,
+       /* updateDepgraph */    NULL,
+       /* dependsOnTime */     NULL,
+       /* dependsOnNormals */  NULL,
+       /* foreachObjectLink */ NULL,
+       /* foreachIDLink */     NULL,
+       /* foreachTexLink */    NULL,
+};
index 6443a88a222e95d75dcee705542ea11b3df13209..3b769a30994b4f8b36b4cb8ee8391db96dae1dae 100644 (file)
@@ -277,5 +277,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
        INIT_TYPE(DynamicPaint);
        INIT_TYPE(Remesh);
        INIT_TYPE(Skin);
+       INIT_TYPE(LaplacianSmooth);
 #undef INIT_TYPE
 }