Compare commits
74 Commits
temp-node-
...
soc-2012-s
Author | SHA1 | Date | |
---|---|---|---|
210f04878b | |||
df0a0e59cb | |||
bfdc655a4d | |||
7304f19ff1 | |||
83dfe21f1a | |||
598ee4c6e1 | |||
cb691c6e1f | |||
f540a9e96c | |||
4446ff3cd5 | |||
cf3a0e0139 | |||
882425990d | |||
a1b4d76cfc | |||
30d4bdcb01 | |||
![]() |
cfbb0e673c | ||
0fdc4a1d63 | |||
8512f76825 | |||
b07b0c6e79 | |||
![]() |
f739cbb6d7 | ||
07ead95884 | |||
7b375313cc | |||
68b5725768 | |||
3b115827bd | |||
11c1bcc3f2 | |||
d754800391 | |||
2f52684217 | |||
1563952090 | |||
75353c1996 | |||
761a3bd74e | |||
![]() |
41cd82a743 | ||
![]() |
bd95e14091 | ||
ce3b024d07 | |||
0293fd7727 | |||
883b9c55f4 | |||
![]() |
c498e55f34 | ||
![]() |
2bc6757f87 | ||
118b39acb8 | |||
c347054acf | |||
cfd4e814d2 | |||
f52ce3e423 | |||
3014024101 | |||
0ed81a5a89 | |||
6104894772 | |||
d8ace02ab2 | |||
0637acd792 | |||
![]() |
f302951972 | ||
1908a6a73c | |||
7b4ce30e95 | |||
5a1b810fa1 | |||
7ea7a636ac | |||
5574114a32 | |||
7a11881ad0 | |||
28637dcd9e | |||
8a519ed167 | |||
c6c57fd092 | |||
5392ef6158 | |||
6e5beb9f22 | |||
fea4cf0d54 | |||
828b3101e3 | |||
ce317d58f7 | |||
db0ab592bc | |||
6dc4f68f41 | |||
083b849408 | |||
5fd10574c0 | |||
2bdd16a44b | |||
1ab8b85bf9 | |||
29064ca096 | |||
bdba23371e | |||
44d332404d | |||
2008a8ec58 | |||
94e8e2a96e | |||
d64eb8eac0 | |||
bbd61787eb | |||
b35a1f6858 | |||
4618fb4936 |
@@ -39,16 +39,16 @@
|
|||||||
#include "ceres/residual_block.h"
|
#include "ceres/residual_block.h"
|
||||||
#include "ceres/internal/scoped_ptr.h"
|
#include "ceres/internal/scoped_ptr.h"
|
||||||
|
|
||||||
CERES_HASH_NAMESPACE_START
|
//CERES_HASH_NAMESPACE_START
|
||||||
|
namespace std {
|
||||||
// Allow us to hash pointers as if they were int's
|
// Allow us to hash pointers as if they were int's
|
||||||
template<> struct hash< ::ceres::internal::ParameterBlock*> {
|
template<> struct hash< ::ceres::internal::ParameterBlock*> {
|
||||||
size_t operator()(::ceres::internal::ParameterBlock* x) const {
|
size_t operator()(::ceres::internal::ParameterBlock* x) const {
|
||||||
return reinterpret_cast<size_t>(x);
|
return reinterpret_cast<size_t>(x);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
CERES_HASH_NAMESPACE_END
|
//CERES_HASH_NAMESPACE_END
|
||||||
|
|
||||||
namespace ceres {
|
namespace ceres {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@@ -315,6 +315,24 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator("object.hook_select", text="Select")
|
row.operator("object.hook_select", text="Select")
|
||||||
row.operator("object.hook_assign", text="Assign")
|
row.operator("object.hook_assign", text="Assign")
|
||||||
|
def LAPLACIANSMOOTH(self, layout, ob, md):
|
||||||
|
#split = layout.split(percentage=0.25)
|
||||||
|
|
||||||
|
#col = split.column()
|
||||||
|
|
||||||
|
#col = split.column()
|
||||||
|
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):
|
def LATTICE(self, layout, ob, md):
|
||||||
split = layout.split()
|
split = layout.split()
|
||||||
|
@@ -1699,6 +1699,7 @@ class VIEW3D_MT_edit_mesh_specials(Menu):
|
|||||||
layout.operator("mesh.select_all", text="Select Inverse").action = 'INVERT'
|
layout.operator("mesh.select_all", text="Select Inverse").action = 'INVERT'
|
||||||
layout.operator("mesh.flip_normals")
|
layout.operator("mesh.flip_normals")
|
||||||
layout.operator("mesh.vertices_smooth", text="Smooth")
|
layout.operator("mesh.vertices_smooth", text="Smooth")
|
||||||
|
layout.operator("mesh.vertices_smooth_laplacian", text="Laplacian Smooth")
|
||||||
layout.operator("mesh.inset")
|
layout.operator("mesh.inset")
|
||||||
layout.operator("mesh.bevel", text="Bevel")
|
layout.operator("mesh.bevel", text="Bevel")
|
||||||
layout.operator("mesh.bridge_edge_loops")
|
layout.operator("mesh.bridge_edge_loops")
|
||||||
|
@@ -109,6 +109,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
|
|||||||
*/
|
*/
|
||||||
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float m_dist, const float v0[3], const float v1[3], const float v2[3]);
|
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float m_dist, const float v0[3], const float v1[3], const float v2[3]);
|
||||||
float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]);
|
float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]);
|
||||||
|
float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BVHCache
|
* BVHCache
|
||||||
|
178
source/blender/blenkernel/BKE_snap.h
Normal file
178
source/blender/blenkernel/BKE_snap.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* ***** 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): Luke Frisken 2012
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __BKE_SNAP_H__
|
||||||
|
#define __BKE_SNAP_H__
|
||||||
|
|
||||||
|
#include "DNA_scene_types.h"
|
||||||
|
#include "DNA_object_types.h"
|
||||||
|
#include "DNA_view3d_types.h"
|
||||||
|
#include "DNA_screen_types.h"
|
||||||
|
#include "DNA_meshdata_types.h"
|
||||||
|
#include "DNA_mesh_types.h"
|
||||||
|
#include "BKE_context.h"
|
||||||
|
#include "WM_types.h"
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
//perhaps more info later I might guess
|
||||||
|
float location[3];
|
||||||
|
float normal[3];
|
||||||
|
int r_dist;
|
||||||
|
float r_depth;
|
||||||
|
}SnapPoint;
|
||||||
|
|
||||||
|
typedef struct SnapSystem SnapSystem;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAPSYSTEM_MODE_SELECT_ALL = 0,
|
||||||
|
SNAPSYSTEM_MODE_SELECT_NOT_SELECTED = 1,
|
||||||
|
SNAPSYSTEM_MODE_SELECT_NOT_OBEDIT = 2
|
||||||
|
}SnapSystem_mode_select;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAPSYSTEM_STATE_SNAPPING,
|
||||||
|
SNAPSYSTEM_STATE_INIT_SNAP,
|
||||||
|
SNAPSYSTEM_STATE_IDLE
|
||||||
|
}SnapSystem_state;
|
||||||
|
|
||||||
|
/*This function creates a new instance of the snapping system*/
|
||||||
|
/*callback_data: is the data to be used by the code using the snapping system (e.g transform)
|
||||||
|
when the callbacks are called by snapsystem.
|
||||||
|
|
||||||
|
update_callback: gets called when the snapping system has not yet recieved confirmation from the user
|
||||||
|
of the chosen snap point, but there is a temporary snap_point available for providing realtime feedback
|
||||||
|
to the user of their actions when moving the mouse. In the case of transform, this means the geometry
|
||||||
|
moves towards the snap point without permenantly being applied.
|
||||||
|
|
||||||
|
finish_callback: same as update_callback, but the snap_point is to be applied this time.
|
||||||
|
|
||||||
|
cancel_callback: tells the code using the snapsystem that the current snapsystem snap search has been cancelled.
|
||||||
|
|
||||||
|
nofeedback_callback: will probably be removed/changed/refactored soon.
|
||||||
|
*/
|
||||||
|
/*The return value pointer to SnapSystem, when finished requires the code using the system to call SnapSystem_free
|
||||||
|
on it to free allocated data within the system*/
|
||||||
|
SnapSystem* SnapSystem_create( Scene* scene, View3D* v3d, ARegion* ar, Object* obedit, bContext* C,
|
||||||
|
void* callback_data,
|
||||||
|
void (*update_callback)(SnapSystem *ssystem, void* callback_data, SnapPoint sp),
|
||||||
|
void (*nofeedback_callback)(SnapSystem *ssystem, void* callback_data),
|
||||||
|
void (*finish_callback)(SnapSystem *ssystem, void* callback_data, SnapPoint sp),
|
||||||
|
void (*cancel_callback)(SnapSystem *ssystem, void* callback_data));
|
||||||
|
|
||||||
|
void SnapSystem_test_run(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_reset_ob_list(SnapSystem* ssystem); //reset the list of objects the snapsystem uses for snapping
|
||||||
|
void SnapSystem_evaluate_stack(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_find_snap(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_pick_snap(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_add_ob(SnapSystem* ssystem, Object* ob);
|
||||||
|
Object* SnapSystem_get_ob(SnapSystem* ssystem, int index);
|
||||||
|
void SnapSystem_set_mode_select(SnapSystem* ssystem, SnapSystem_mode_select mode_select);
|
||||||
|
int SnapSystem_get_retval(SnapSystem* ssystem);
|
||||||
|
bContext* SnapSystem_get_C(SnapSystem* ssystem);
|
||||||
|
SnapSystem_state SnapSystem_get_state(SnapSystem* ssystem);
|
||||||
|
|
||||||
|
/*This function handles the events of the snapsystem, and returns a 1 if the event has been
|
||||||
|
handled (and consumed) by the snapsystem*/
|
||||||
|
int SnapSystem_Event(SnapSystem* ssystem, wmEvent* event);
|
||||||
|
/*This function draws all the currently active snaps within the snapsystem*/
|
||||||
|
void SnapSystem_draw(SnapSystem* ssystem);
|
||||||
|
|
||||||
|
void SnapSystem_reset_snappoint(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_clear_pick(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_reset(SnapSystem* ssystem);
|
||||||
|
void SnapSystem_free(SnapSystem* ssystem);
|
||||||
|
|
||||||
|
/*default callbacks*/
|
||||||
|
void SnapSystem_default_object_iterator(SnapSystem* ssystem, void* callback_data);
|
||||||
|
void SnapSystem_default_object_handler(SnapSystem* ssystem, void* callback_data, Object* ob);
|
||||||
|
|
||||||
|
typedef struct Snap Snap;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAP_TYPE_MESH,
|
||||||
|
SNAP_TYPE_CURVE,
|
||||||
|
SNAP_TYPE_BONE,
|
||||||
|
SNAP_TYPE_AXIS
|
||||||
|
}Snap_type;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAPMESH_DATA_TYPE_DerivedMesh,
|
||||||
|
SNAPMESH_DATA_TYPE_BMEditMesh
|
||||||
|
}SnapMesh_data_type;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAPMESH_TYPE_VERTEX,
|
||||||
|
SNAPMESH_TYPE_FACE,
|
||||||
|
SNAPMESH_TYPE_PLANAR,
|
||||||
|
SNAPMESH_TYPE_EDGE,
|
||||||
|
SNAPMESH_TYPE_EDGE_MIDPOINT,
|
||||||
|
SNAPMESH_TYPE_EDGE_PARALLEL
|
||||||
|
}SnapMesh_type;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SNAPMESH_DAT_vert,
|
||||||
|
SNAPMESH_DAT_edge,
|
||||||
|
SNAPMESH_DAT_face
|
||||||
|
}SnapMesh_data_array_type;
|
||||||
|
|
||||||
|
/*This struct provides a storage of face + verts in one place for using
|
||||||
|
as return geometry in face picking, and gets used for planar snapping*/
|
||||||
|
typedef struct{
|
||||||
|
MFace *face;
|
||||||
|
MVert *verts;
|
||||||
|
int nverts;
|
||||||
|
float no[3];
|
||||||
|
}MeshData_pickface;
|
||||||
|
|
||||||
|
/*Return data type for SnapMesh class*/
|
||||||
|
typedef enum{
|
||||||
|
SNAPMESH_RET_DAT_vert_index,
|
||||||
|
SNAPMESH_RET_DAT_edge_index,
|
||||||
|
SNAPMESH_RET_DAT_pface //see MeshData_pickface struct
|
||||||
|
}SnapMesh_ret_data_type;
|
||||||
|
|
||||||
|
/*Flags for use in VertCheck or EdgeCheck or FaceCheck MeshData functions.*/
|
||||||
|
typedef enum{
|
||||||
|
MESHDATA_CHECK_NONE = 0,
|
||||||
|
MESHDATA_CHECK_HIDDEN = 1,
|
||||||
|
MESHDATA_CHECK_SELECTED = 2
|
||||||
|
}MeshData_check;
|
||||||
|
|
||||||
|
void Snap_run(Snap* s);
|
||||||
|
void Snap_free(Snap* s);
|
||||||
|
|
||||||
|
int Snap_getretval(Snap* s);
|
||||||
|
SnapPoint* Snap_getSnapPoint(Snap* s);
|
||||||
|
void Snap_setClosestPoint(Snap* s, SnapPoint* sp);
|
||||||
|
void Snap_setpick(Snap* s, Snap* pick);
|
||||||
|
|
||||||
|
Snap* SnapMesh_create( void* mesh_data,
|
||||||
|
SnapMesh_data_type data_type,
|
||||||
|
int free_mesh_data,
|
||||||
|
MeshData_check check,
|
||||||
|
SnapMesh_type sm_type,
|
||||||
|
Scene *scene, Object *ob, View3D *v3d, ARegion *ar, bContext *C, int mval[2]);
|
||||||
|
|
||||||
|
void SnapMesh_draw(Snap *sm);
|
||||||
|
|
||||||
|
#endif // __BKE_SNAP_H__
|
@@ -29,6 +29,7 @@ set(INC
|
|||||||
../blenfont
|
../blenfont
|
||||||
../blenlib
|
../blenlib
|
||||||
../blenloader
|
../blenloader
|
||||||
|
../editors/include
|
||||||
../gpu
|
../gpu
|
||||||
../ikplugin
|
../ikplugin
|
||||||
../imbuf
|
../imbuf
|
||||||
@@ -44,6 +45,8 @@ set(INC
|
|||||||
../../../intern/mikktspace
|
../../../intern/mikktspace
|
||||||
../../../intern/opennl/extern
|
../../../intern/opennl/extern
|
||||||
../../../intern/raskter
|
../../../intern/raskter
|
||||||
|
../editors/transform
|
||||||
|
|
||||||
|
|
||||||
# XXX - BAD LEVEL CALL WM_api.h
|
# XXX - BAD LEVEL CALL WM_api.h
|
||||||
../windowmanager
|
../windowmanager
|
||||||
@@ -133,6 +136,7 @@ set(SRC
|
|||||||
intern/shrinkwrap.c
|
intern/shrinkwrap.c
|
||||||
intern/sketch.c
|
intern/sketch.c
|
||||||
intern/smoke.c
|
intern/smoke.c
|
||||||
|
intern/snap.c
|
||||||
intern/softbody.c
|
intern/softbody.c
|
||||||
intern/sound.c
|
intern/sound.c
|
||||||
intern/speaker.c
|
intern/speaker.c
|
||||||
@@ -217,6 +221,7 @@ set(SRC
|
|||||||
BKE_shrinkwrap.h
|
BKE_shrinkwrap.h
|
||||||
BKE_sketch.h
|
BKE_sketch.h
|
||||||
BKE_smoke.h
|
BKE_smoke.h
|
||||||
|
BKE_snap.h
|
||||||
BKE_softbody.h
|
BKE_softbody.h
|
||||||
BKE_sound.h
|
BKE_sound.h
|
||||||
BKE_speaker.h
|
BKE_speaker.h
|
||||||
@@ -255,7 +260,6 @@ endif()
|
|||||||
if(WITH_MOD_CLOTH_ELTOPO)
|
if(WITH_MOD_CLOTH_ELTOPO)
|
||||||
list(APPEND INC
|
list(APPEND INC
|
||||||
../../../extern/eltopo
|
../../../extern/eltopo
|
||||||
../../../extern/eltopo/eltopo3d
|
|
||||||
)
|
)
|
||||||
add_definitions(-DWITH_ELTOPO)
|
add_definitions(-DWITH_ELTOPO)
|
||||||
endif()
|
endif()
|
||||||
|
@@ -7,7 +7,7 @@ sources = env.Glob('intern/*.c')
|
|||||||
incs = '. #/intern/guardedalloc #/intern/memutil'
|
incs = '. #/intern/guardedalloc #/intern/memutil'
|
||||||
incs += ' ../blenlib ../blenfont ../makesdna ../windowmanager'
|
incs += ' ../blenlib ../blenfont ../makesdna ../windowmanager'
|
||||||
incs += ' ../render/extern/include #/intern/decimation/extern ../makesrna'
|
incs += ' ../render/extern/include #/intern/decimation/extern ../makesrna'
|
||||||
incs += ' ../imbuf ../ikplugin ../avi #/intern/elbeem/extern ../nodes ../modifiers'
|
incs += ' ../imbuf ../ikplugin ../avi #/intern/elbeem/extern ../nodes ../modifiers ../editors/include'
|
||||||
incs += ' #/intern/iksolver/extern ../blenloader'
|
incs += ' #/intern/iksolver/extern ../blenloader'
|
||||||
incs += ' #/extern/bullet2/src'
|
incs += ' #/extern/bullet2/src'
|
||||||
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
|
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
|
||||||
@@ -18,6 +18,7 @@ incs += ' #/intern/mikktspace'
|
|||||||
incs += ' #/intern/audaspace/intern'
|
incs += ' #/intern/audaspace/intern'
|
||||||
incs += ' #/intern/ffmpeg'
|
incs += ' #/intern/ffmpeg'
|
||||||
incs += ' #/intern/raskter'
|
incs += ' #/intern/raskter'
|
||||||
|
incs += ' ../editors/include ../editors/transform'
|
||||||
|
|
||||||
incs += ' ' + env['BF_OPENGL_INC']
|
incs += ' ' + env['BF_OPENGL_INC']
|
||||||
incs += ' ' + env['BF_ZLIB_INC']
|
incs += ' ' + env['BF_ZLIB_INC']
|
||||||
|
@@ -57,7 +57,7 @@ float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_d
|
|||||||
return FLT_MAX;
|
return FLT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3])
|
float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3])
|
||||||
{
|
{
|
||||||
|
|
||||||
float idist;
|
float idist;
|
||||||
|
2327
source/blender/blenkernel/intern/snap.c
Normal file
2327
source/blender/blenkernel/intern/snap.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@ set(INC
|
|||||||
../blenlib
|
../blenlib
|
||||||
../makesdna
|
../makesdna
|
||||||
../../../intern/guardedalloc
|
../../../intern/guardedalloc
|
||||||
|
../../../intern/opennl/extern
|
||||||
)
|
)
|
||||||
|
|
||||||
set(INC_SYS
|
set(INC_SYS
|
||||||
@@ -52,6 +53,7 @@ set(SRC
|
|||||||
operators/bmo_mirror.c
|
operators/bmo_mirror.c
|
||||||
operators/bmo_primitive.c
|
operators/bmo_primitive.c
|
||||||
operators/bmo_removedoubles.c
|
operators/bmo_removedoubles.c
|
||||||
|
operators/bmo_smooth_laplacian.c
|
||||||
operators/bmo_subdivide.c
|
operators/bmo_subdivide.c
|
||||||
operators/bmo_subdivide.h
|
operators/bmo_subdivide.h
|
||||||
operators/bmo_triangulate.c
|
operators/bmo_triangulate.c
|
||||||
|
@@ -13,6 +13,7 @@ incs = [
|
|||||||
'../makesdna',
|
'../makesdna',
|
||||||
'../blenkernel',
|
'../blenkernel',
|
||||||
'#/intern/guardedalloc',
|
'#/intern/guardedalloc',
|
||||||
|
'#/intern/opennl/extern',
|
||||||
]
|
]
|
||||||
|
|
||||||
defs = []
|
defs = []
|
||||||
|
@@ -29,6 +29,9 @@
|
|||||||
#ifndef __BMESH_INLINE_H__
|
#ifndef __BMESH_INLINE_H__
|
||||||
#define __BMESH_INLINE_H__
|
#define __BMESH_INLINE_H__
|
||||||
|
|
||||||
|
#include "bmesh_class.h"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
/* stuff for dealing with header flags */
|
/* stuff for dealing with header flags */
|
||||||
#define BM_elem_flag_test( ele, hflag) _bm_elem_flag_test (&(ele)->head, hflag)
|
#define BM_elem_flag_test( ele, hflag) _bm_elem_flag_test (&(ele)->head, hflag)
|
||||||
#define BM_elem_flag_test_bool(ele, hflag) _bm_elem_flag_test_bool(&(ele)->head, hflag)
|
#define BM_elem_flag_test_bool(ele, hflag) _bm_elem_flag_test_bool(&(ele)->head, hflag)
|
||||||
|
@@ -113,6 +113,26 @@ static BMOpDefine bmo_smooth_vert_def = {
|
|||||||
0
|
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
|
* Right-Hand Faces
|
||||||
*
|
*
|
||||||
@@ -420,8 +440,15 @@ static BMOpDefine bmo_contextual_create_def = {
|
|||||||
*/
|
*/
|
||||||
static BMOpDefine bmo_bridge_loops_def = {
|
static BMOpDefine bmo_bridge_loops_def = {
|
||||||
"bridge_loops",
|
"bridge_loops",
|
||||||
{{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
|
//{{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
|
||||||
|
{{BMO_OP_SLOT_ELEMENT_BUF, "edgefacein"}, /* input faces and edge */
|
||||||
{BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, /* new face */
|
{BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, /* new face */
|
||||||
|
|
||||||
|
{BMO_OP_SLOT_INT, "segmentation"}, /* input segmentation param */
|
||||||
|
{BMO_OP_SLOT_INT, "interpolation"}, /* input interpolation param */
|
||||||
|
{BMO_OP_SLOT_FLT, "strenght"}, /* input strenght param */
|
||||||
|
{BMO_OP_SLOT_BOOL, "n_gon"}, /* flag N-gon optimization */
|
||||||
|
|
||||||
{0, /* null-terminating sentinel */}},
|
{0, /* null-terminating sentinel */}},
|
||||||
bmo_bridge_loops_exec,
|
bmo_bridge_loops_exec,
|
||||||
0,
|
0,
|
||||||
@@ -1043,6 +1070,9 @@ static BMOpDefine bmo_bevel_def = {
|
|||||||
* modifier uses this. We could do this as another float setting */
|
* modifier uses this. We could do this as another float setting */
|
||||||
{BMO_OP_SLOT_INT, "lengthlayer"}, /* which PROP_FLT layer to us */
|
{BMO_OP_SLOT_INT, "lengthlayer"}, /* which PROP_FLT layer to us */
|
||||||
{BMO_OP_SLOT_FLT, "percent"}, /* percentage to expand beveled edge */
|
{BMO_OP_SLOT_FLT, "percent"}, /* percentage to expand beveled edge */
|
||||||
|
|
||||||
|
{BMO_OP_SLOT_FLT, "amount"},
|
||||||
|
{BMO_OP_SLOT_INT, "segmentation"},
|
||||||
{0} /* null-terminating sentinel */},
|
{0} /* null-terminating sentinel */},
|
||||||
bmo_bevel_exec,
|
bmo_bevel_exec,
|
||||||
BMO_OP_FLAG_UNTAN_MULTIRES
|
BMO_OP_FLAG_UNTAN_MULTIRES
|
||||||
@@ -1246,6 +1276,7 @@ BMOpDefine *opdefines[] = {
|
|||||||
&bmo_translate_def,
|
&bmo_translate_def,
|
||||||
&bmo_triangle_fill_def,
|
&bmo_triangle_fill_def,
|
||||||
&bmo_triangulate_def,
|
&bmo_triangulate_def,
|
||||||
|
&bmo_smooth_laplacian_vert_def,
|
||||||
&bmo_weld_verts_def,
|
&bmo_weld_verts_def,
|
||||||
&bmo_wireframe_def,
|
&bmo_wireframe_def,
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "BLI_ghash.h"
|
#include "BLI_ghash.h"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@@ -60,10 +60,13 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op);
|
|||||||
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op);
|
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op);
|
void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_duplicate_exec(BMesh *bm, BMOperator *op);
|
void bmo_duplicate_exec(BMesh *bm, BMOperator *op);
|
||||||
|
void bmo_edgebisect_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op);
|
void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_edgenet_prepare(BMesh *bm, BMOperator *op);
|
void bmo_edgenet_prepare(BMesh *bm, BMOperator *op);
|
||||||
|
void bmo_edgerotate_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op);
|
void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op);
|
void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op);
|
||||||
|
void bmo_extrude_face_indiv_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op);
|
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
|
void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_find_doubles_exec(BMesh *bm, BMOperator *op);
|
void bmo_find_doubles_exec(BMesh *bm, BMOperator *op);
|
||||||
@@ -91,6 +94,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op);
|
|||||||
void bmo_similar_verts_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_slide_vert_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_smooth_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_solidify_face_region_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_spin_exec(BMesh *bm, BMOperator *op);
|
void bmo_spin_exec(BMesh *bm, BMOperator *op);
|
||||||
void bmo_split_edges_exec(BMesh *bm, BMOperator *op);
|
void bmo_split_edges_exec(BMesh *bm, BMOperator *op);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_array.h"
|
#include "BLI_array.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
@@ -34,12 +35,38 @@
|
|||||||
|
|
||||||
#include "intern/bmesh_operators_private.h" /* own include */
|
#include "intern/bmesh_operators_private.h" /* own include */
|
||||||
|
|
||||||
|
|
||||||
#define VERT_INPUT 1
|
#define VERT_INPUT 1
|
||||||
#define EDGE_OUT 1
|
#define EDGE_OUT 1
|
||||||
#define FACE_NEW 2
|
#define FACE_NEW 2
|
||||||
#define EDGE_MARK 4
|
#define EDGE_MARK 4
|
||||||
#define EDGE_DONE 8
|
#define EDGE_DONE 8
|
||||||
|
|
||||||
|
#define FACE_MARK 1
|
||||||
|
#define EDGE_CONNECTED 7
|
||||||
|
#define EDGE_NON_CONNECTED 9
|
||||||
|
|
||||||
|
#define LINEAR_INTER 2
|
||||||
|
#define CUBIC_INTER 4
|
||||||
|
|
||||||
|
#define BRIDGE_EPSILON 1e-6
|
||||||
|
|
||||||
|
typedef struct VertexItem{
|
||||||
|
struct VertexItem *next, *prev;
|
||||||
|
BMVert *v;
|
||||||
|
}VertexItem;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct BridgeParams{
|
||||||
|
ListBase newVertices; // list of new vertex
|
||||||
|
int inter; // interpolation
|
||||||
|
int seg; // segmentation param
|
||||||
|
float strenght;
|
||||||
|
float centrod1[3]; // coordinate of centrod input loops
|
||||||
|
float centrod2[3];
|
||||||
|
} BridgeParams;
|
||||||
|
|
||||||
|
|
||||||
void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
|
void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
|
||||||
{
|
{
|
||||||
BMIter iter, liter;
|
BMIter iter, liter;
|
||||||
@@ -178,7 +205,7 @@ static int clamp_index(const int x, const int len)
|
|||||||
BLI_array_append(arr2, arr_tmp[i]); \
|
BLI_array_append(arr2, arr_tmp[i]); \
|
||||||
} \
|
} \
|
||||||
BLI_array_free(arr_tmp); \
|
BLI_array_free(arr_tmp); \
|
||||||
} (void)0
|
}
|
||||||
|
|
||||||
/* get the 2 loops matching 2 verts.
|
/* get the 2 loops matching 2 verts.
|
||||||
* first attempt to get the face corners that use the edge defined by v1 & v2,
|
* first attempt to get the face corners that use the edge defined by v1 & v2,
|
||||||
@@ -210,7 +237,715 @@ static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BM
|
|||||||
*l2 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v2, 0);
|
*l2 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
|
//TODO: rename function
|
||||||
|
// return count entry element into list
|
||||||
|
int bmo_bridge_array_entry_elem(BMEdge **list, int size, BMEdge *elem)
|
||||||
|
{
|
||||||
|
int i = 0, count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if (list[i] == elem)
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return coordinate of middle edge
|
||||||
|
*/
|
||||||
|
void get_middle_edge(BMEdge* e, float v[3]){
|
||||||
|
BMVert *v1, *v2;
|
||||||
|
v1 = e->v1;
|
||||||
|
v2 = BM_edge_other_vert(e, v1);
|
||||||
|
mid_v3_v3v3(v, v1->co, v2->co);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this function find centroid of group vertex
|
||||||
|
* return coordinate of centroid
|
||||||
|
*/
|
||||||
|
void get_centroid(BMVert **vv, int vert_count, float center[3]){
|
||||||
|
int i;
|
||||||
|
center[0] = 0; center[1] = 0; center[2] = 0;
|
||||||
|
for (i = 0; i < vert_count; i++){
|
||||||
|
add_v3_v3(center, vv[i]->co);
|
||||||
|
}
|
||||||
|
mul_v3_fl(center, 1.0f/vert_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMVert* bridge_check_existing_vertex(BridgeParams *bp, float co[3])
|
||||||
|
{
|
||||||
|
float epsilon = 1e-6;
|
||||||
|
BMVert *vert = NULL;
|
||||||
|
VertexItem *item;
|
||||||
|
for (item = bp->newVertices.first; item; item = item->next)
|
||||||
|
{
|
||||||
|
if (compare_v3v3(item->v->co, co, epsilon))
|
||||||
|
vert = item->v;
|
||||||
|
}
|
||||||
|
return vert;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* this function return vertex of linear interpolation between v1 and v2
|
||||||
|
*/
|
||||||
|
BMVert* get_linear_seg(BMesh *bm, BridgeParams* bp, int n, BMVert *v1, BMVert *v2)
|
||||||
|
{
|
||||||
|
float co[3];
|
||||||
|
BMVert *v;
|
||||||
|
VertexItem *item;
|
||||||
|
|
||||||
|
co[0] = v1->co[0] + (v2->co[0]-v1->co[0])*n / bp->seg;
|
||||||
|
co[1] = v1->co[1] + (v2->co[1]-v1->co[1])*n / bp->seg;
|
||||||
|
co[2] = v1->co[2] + (v2->co[2]-v1->co[2])*n / bp->seg;
|
||||||
|
|
||||||
|
v = bridge_check_existing_vertex(bp, co);
|
||||||
|
if (!v)
|
||||||
|
{
|
||||||
|
item = (VertexItem*)MEM_callocN(sizeof(VertexItem), "VertexItem");
|
||||||
|
item->v = BM_vert_create(bm, co, NULL);
|
||||||
|
BLI_addtail(&bp->newVertices, item);
|
||||||
|
v = item->v;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this function return vertex of cubic interpolation between v1 and v2
|
||||||
|
* Parametric cubic spline in Hermite form
|
||||||
|
* 0 <= t <= 1
|
||||||
|
*/
|
||||||
|
BMVert* get_cubic_seg(BMesh *bm, BridgeParams *bp, int n, BMVert *v1, BMVert *v2){
|
||||||
|
BMVert *v = NULL;
|
||||||
|
VertexItem *item;
|
||||||
|
float t, co[3], r1[3], r2[3]/*, mn[3]*/;
|
||||||
|
t = (float) (n) / bp->seg;
|
||||||
|
|
||||||
|
//sub_v3_v3v3(r1, bp->centrod2 , v1->co);
|
||||||
|
//sub_v3_v3v3(r2, v2->co, bp->centrod1);
|
||||||
|
|
||||||
|
sub_v3_v3v3(r1, bp->centrod1 , v1->co);
|
||||||
|
sub_v3_v3v3(r2, v2->co, bp->centrod2);
|
||||||
|
//sub_v3_v3v3(mn, v1->co, v2->co);
|
||||||
|
|
||||||
|
//mul_v3_fl(r1, bp->strenght);
|
||||||
|
//mul_v3_fl(r2, bp->strenght);
|
||||||
|
//add_v3_v3(r1, mn);
|
||||||
|
//add_v3_v3(r2, mn);
|
||||||
|
|
||||||
|
mul_v3_fl(r1, 2*asin(bp->strenght));
|
||||||
|
mul_v3_fl(r2, 2*asin(bp->strenght));
|
||||||
|
|
||||||
|
co[0] = v1->co[0] * (2 * t * t * t - 3 * t * t + 1) +
|
||||||
|
v2->co[0] * (-2 * t * t * t + 3 * t * t ) +
|
||||||
|
r1[0] * (t * t * t - 2 * t * t + t) +
|
||||||
|
r2[0] * (t * t * t - t * t);
|
||||||
|
co[1] = v1->co[1] * (2 * t * t * t - 3 * t * t + 1) +
|
||||||
|
v2->co[1] * (-2 * t * t * t + 3 * t * t ) +
|
||||||
|
r1[1] * (t * t * t - 2 * t * t + t) +
|
||||||
|
r2[1] * (t * t * t - t * t);
|
||||||
|
co[2] = v1->co[2] * (2 * t * t * t - 3 * t * t + 1) +
|
||||||
|
v2->co[2] * (-2 * t * t * t + 3 * t * t ) +
|
||||||
|
r1[2] * (t * t * t - 2 * t * t + t) +
|
||||||
|
r2[2] * (t * t * t - t * t);
|
||||||
|
|
||||||
|
v = bridge_check_existing_vertex(bp, co);
|
||||||
|
if (!v)
|
||||||
|
{
|
||||||
|
item = (VertexItem*)MEM_callocN(sizeof(VertexItem), "VertexItem");
|
||||||
|
item->v = BM_vert_create(bm, co, NULL);
|
||||||
|
BLI_addtail(&bp->newVertices, item);
|
||||||
|
v = item->v;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float get_cos_v3v3(float a[3], float b[3]){
|
||||||
|
float cos_ab = (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) /
|
||||||
|
(sqrt(a[0]*a[0]+ a[1]*a[1]+ a[2]*a[2]) * sqrt(b[0]*b[0]+ b[1]*b[1]+ b[2]*b[2]));
|
||||||
|
return cos_ab;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
create polygons between two edge
|
||||||
|
*/
|
||||||
|
BMFace* bmo_edge_face_connect(BMesh *bm, BridgeParams* bp, BMEdge *e1, BMEdge *e2, BMFace *f_example)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BMVert *vv[4];
|
||||||
|
BMVert *v1, *v2, *v3, *v4;
|
||||||
|
BMVert *vi1, *vi2, *vi3, *vi4; // input vertex
|
||||||
|
BMFace *f = NULL;
|
||||||
|
float vect1[3], vect2[3], vect3[3], vect4[3], normalA[3], normalB[3], normalVector[3];
|
||||||
|
float vp1[3], vp2[3], vp3[3], vp4[3];
|
||||||
|
|
||||||
|
vi1 = e1->v1;
|
||||||
|
vi2 = e2->v1;
|
||||||
|
vi3 = BM_edge_other_vert(e2,vi2);
|
||||||
|
vi4 = BM_edge_other_vert(e1,vi1);
|
||||||
|
// calculate vector betwen input vertx
|
||||||
|
sub_v3_v3v3(vect1, vi1->co, vi2->co); // v1-v2
|
||||||
|
sub_v3_v3v3(vect2, vi2->co, vi3->co); // v2-v3
|
||||||
|
sub_v3_v3v3(vect3, vi3->co, vi4->co); // v3-v4
|
||||||
|
sub_v3_v3v3(vect4, vi4->co, vi1->co); // v4-v1
|
||||||
|
|
||||||
|
// cros product
|
||||||
|
cross_v3_v3v3(vp1, vect1, vect2);
|
||||||
|
cross_v3_v3v3(vp2, vect2, vect3);
|
||||||
|
cross_v3_v3v3(vp3, vect3, vect4);
|
||||||
|
cross_v3_v3v3(vp4, vect4, vect1);
|
||||||
|
// calculate normal vector
|
||||||
|
mid_v3_v3v3(normalA, bp->centrod1, bp->centrod2);
|
||||||
|
vv[0] = vi1;
|
||||||
|
vv[1] = vi2;
|
||||||
|
vv[2] = vi3;
|
||||||
|
vv[3] = vi4;
|
||||||
|
get_centroid(vv, 4, normalB);
|
||||||
|
sub_v3_v3v3(normalVector, normalB, normalA);
|
||||||
|
|
||||||
|
// check direction cros produc result
|
||||||
|
if (!(get_cos_v3v3(vp1, vp2)>0 &&
|
||||||
|
get_cos_v3v3(vp2, vp3)>0 &&
|
||||||
|
get_cos_v3v3(vp3, vp4)>0 &&
|
||||||
|
get_cos_v3v3(vp4, vp1)>0))
|
||||||
|
{
|
||||||
|
vi1 = e1->v1;
|
||||||
|
vi2 = BM_edge_other_vert(e2, e2->v1);
|
||||||
|
vi3 = BM_edge_other_vert(e2,vi2);
|
||||||
|
vi4 = BM_edge_other_vert(e1,vi1);
|
||||||
|
}
|
||||||
|
// vi1 - v1 - v2 ... vi2
|
||||||
|
// | | | |
|
||||||
|
// vi4 .. v4 - v3 ... vi3
|
||||||
|
v1 = vi1;
|
||||||
|
v2 = vi2;
|
||||||
|
v3 = vi3;
|
||||||
|
v4 = vi4;
|
||||||
|
if (bp->seg > 1){
|
||||||
|
for (i = 1; i < bp->seg; i++){
|
||||||
|
if (bp->inter == LINEAR_INTER)
|
||||||
|
{
|
||||||
|
v2 = get_linear_seg (bm, bp, i, vi1, vi2);
|
||||||
|
v3 = get_linear_seg(bm, bp, i, vi4, vi3);
|
||||||
|
}
|
||||||
|
if (bp->inter == CUBIC_INTER)
|
||||||
|
{
|
||||||
|
v2 = get_cubic_seg (bm, bp, i, vi1, vi2);
|
||||||
|
v3 = get_cubic_seg(bm, bp, i, vi4, vi3);
|
||||||
|
}
|
||||||
|
f = BM_face_create_quad_tri(bm, v1, v2, v3, v4, f_example, TRUE);
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
//check normal BM_face_normal_flip(bm, f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
v1 = v2;
|
||||||
|
v4 = v3;
|
||||||
|
}
|
||||||
|
f = BM_face_create_quad_tri(bm, v1, vi2, vi3, v4, f_example, TRUE);
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = BM_face_create_quad_tri(bm, v1, v2, v3, v4, f_example, TRUE);
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
This function create polygons between edge and vert
|
||||||
|
*/
|
||||||
|
BMFace* bmo_edge_vert_connect(BMesh *bm, BridgeParams *bp, BMEdge *e, BMVert *v, BMFace *f_example)
|
||||||
|
{
|
||||||
|
BMVert *v1, *v2, *v3, *v4, *vv[3];
|
||||||
|
BMFace *f = NULL;
|
||||||
|
float normalA[3], normalB[3], normalVector[3];
|
||||||
|
int i;
|
||||||
|
v1 = e->v1;
|
||||||
|
v2 = v;
|
||||||
|
v3 = NULL;
|
||||||
|
v4 = BM_edge_other_vert(e, e->v1);
|
||||||
|
|
||||||
|
// calculate normal vector
|
||||||
|
mid_v3_v3v3(normalA, bp->centrod1, bp->centrod2);
|
||||||
|
vv[0] = v1;
|
||||||
|
vv[1] = v2;
|
||||||
|
vv[2] = v4;
|
||||||
|
get_centroid(vv, 3, normalB);
|
||||||
|
sub_v3_v3v3(normalVector, normalB, normalA);
|
||||||
|
|
||||||
|
if (bp->seg > 1){
|
||||||
|
for (i = 1; i < bp->seg; i++){
|
||||||
|
if (bp->inter == LINEAR_INTER)
|
||||||
|
{
|
||||||
|
v2 = get_linear_seg(bm, bp, i, v, e->v1);
|
||||||
|
v3 = get_linear_seg(bm, bp, i, v, BM_edge_other_vert(e, e->v1));
|
||||||
|
}
|
||||||
|
if (bp->inter == CUBIC_INTER)
|
||||||
|
{
|
||||||
|
v2 = get_cubic_seg (bm, bp, i, v, e->v1);
|
||||||
|
v3 = get_cubic_seg (bm, bp, i, v, BM_edge_other_vert(e, e->v1));
|
||||||
|
}
|
||||||
|
if (i == 1)
|
||||||
|
f = BM_face_create_quad_tri(bm, v2, v, v3, NULL, f_example, TRUE);
|
||||||
|
else
|
||||||
|
f = BM_face_create_quad_tri(bm, v1, v2, v3, v4, f_example, TRUE);
|
||||||
|
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
v1 = v2;
|
||||||
|
v4 = v3;
|
||||||
|
}
|
||||||
|
f = BM_face_create_quad_tri(bm, e->v1, v2, v3, BM_edge_other_vert(e, e->v1), f_example, TRUE);
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
f = BM_face_create_quad_tri(bm, e->v1, BM_edge_other_vert(e, e->v1), v, NULL, f_example, TRUE);
|
||||||
|
BM_face_normal_update(f);
|
||||||
|
if (get_cos_v3v3(f->no, normalVector)<0)
|
||||||
|
BM_face_normal_flip(bm, f);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int bridge_check_planar_point(float p1[3], float p2[3], float p3[3], float v[3])
|
||||||
|
{
|
||||||
|
float P[3], N[3];
|
||||||
|
float vv1[3], vv2[3];
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
/* calculation of the normal to the surface */
|
||||||
|
sub_v3_v3v3(vv1, p1, p2);
|
||||||
|
sub_v3_v3v3(vv2, p3, p2);
|
||||||
|
cross_v3_v3v3(N, vv1, vv2);
|
||||||
|
|
||||||
|
copy_v3_v3(P, p2);
|
||||||
|
|
||||||
|
if (fabs(N[0] * (v[0]-P[0]) + N[1] * (v[1]-P[1]) + N[2] * (v[2]-P[2])) < BRIDGE_EPSILON){
|
||||||
|
/* point located on plane */
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_planar_faces(BMFace* fa, BMFace *fb)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
float p1[3], p2[3], p3[3];
|
||||||
|
BMLoop *l = fa->l_first;
|
||||||
|
copy_v3_v3(p1, l->v->co);
|
||||||
|
l = l->next;
|
||||||
|
copy_v3_v3(p2, l->v->co);
|
||||||
|
l = l->next;
|
||||||
|
copy_v3_v3(p3, l->v->co);
|
||||||
|
|
||||||
|
l = fb->l_first;
|
||||||
|
do {
|
||||||
|
if (bridge_check_planar_point(p1, p2, p3, l->v->co))
|
||||||
|
result = 1;
|
||||||
|
else{
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l = l->next;
|
||||||
|
} while (l != fb->l_first);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return 1 if face content e
|
||||||
|
*/
|
||||||
|
int bridge_is_edge_of_face (BMFace *f, BMEdge* e)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
BMLoop *l = f->l_first;
|
||||||
|
do {
|
||||||
|
if (l->e == e)
|
||||||
|
result = 1;
|
||||||
|
l = l->next;
|
||||||
|
} while (l != f->l_first);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_content_faces(BMFace *f, BMFace** faces, int count)
|
||||||
|
{
|
||||||
|
int i, result = 0;
|
||||||
|
for(i = 0; i< count; i++){
|
||||||
|
if (f == faces[i])
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect_faces(BMesh *bm, BMFace *fa, BMFace* fb, BMEdge *e)
|
||||||
|
{
|
||||||
|
BMVert **vv = NULL;
|
||||||
|
BMLoop *l;
|
||||||
|
int count;
|
||||||
|
BLI_array_declare(vv);
|
||||||
|
BLI_array_append(vv, e->v1);
|
||||||
|
BLI_array_append(vv, BM_edge_other_vert(e, e->v1));
|
||||||
|
|
||||||
|
l = fa->l_first;
|
||||||
|
do {
|
||||||
|
if ((l->v != e->v1) && (l->v != BM_edge_other_vert(e, e->v1)))
|
||||||
|
BLI_array_append(vv, l->v);
|
||||||
|
l = l->next;
|
||||||
|
} while (l != fa->l_first);
|
||||||
|
|
||||||
|
l = fb->l_first;
|
||||||
|
do {
|
||||||
|
if ((l->v != e->v1) && (l->v != BM_edge_other_vert(e, e->v1)))
|
||||||
|
BLI_array_append(vv, l->v);
|
||||||
|
l = l->next;
|
||||||
|
} while (l != fb->l_first);
|
||||||
|
|
||||||
|
count = BLI_array_count(vv);
|
||||||
|
if (count > 2){
|
||||||
|
BM_face_create_ngon_vcloud(bm, vv, count, 0);
|
||||||
|
}
|
||||||
|
BLI_array_free(vv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1 - unic element
|
||||||
|
0 - dublicated element
|
||||||
|
*/
|
||||||
|
int check_unic_edge(BMEdge **ee, int count, BMEdge*e)
|
||||||
|
{
|
||||||
|
int i, result = 1;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (ee[i] == e)
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bridge_n_gon_optimization(BMesh *bm, BMFace **faces, int count)
|
||||||
|
{
|
||||||
|
int i = 0, j = 0, t_count = 0 ;
|
||||||
|
BMFace *f , **exp_faces = NULL;
|
||||||
|
BMEdge *e = NULL, **ee = NULL;
|
||||||
|
BMLoop *l;
|
||||||
|
BLI_array_declare(exp_faces);
|
||||||
|
BLI_array_declare(ee);
|
||||||
|
for (i = 0; i < count; i++){
|
||||||
|
l = faces[i]->l_first;
|
||||||
|
f = NULL;
|
||||||
|
do {
|
||||||
|
for (j = 0; j < count; j++){
|
||||||
|
if (!check_content_faces(faces[j], exp_faces, BLI_array_count(exp_faces))){
|
||||||
|
if (faces[i] != faces[j]){
|
||||||
|
if (bridge_is_edge_of_face(faces[j], l->e)){
|
||||||
|
if (check_planar_faces(faces[i], faces[j])){
|
||||||
|
connect_faces(bm, faces[i],faces[j], l->e);
|
||||||
|
f = faces[i];
|
||||||
|
e = l->e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l = l->next;
|
||||||
|
} while (l != faces[i]->l_first);
|
||||||
|
|
||||||
|
if ( f != NULL){
|
||||||
|
BLI_array_append(exp_faces, f);
|
||||||
|
if (check_unic_edge(ee, BLI_array_count(ee), e))
|
||||||
|
BLI_array_append(ee, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_count = BLI_array_count(ee);
|
||||||
|
if(t_count > 0 ) {
|
||||||
|
for (i = 0; i < t_count; i++ )
|
||||||
|
BM_edge_kill(bm, ee[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_array_free(exp_faces);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
|
||||||
|
{
|
||||||
|
BMEdge *e;
|
||||||
|
BMOIter siter;
|
||||||
|
BMIter iter;
|
||||||
|
BMEdge **skip_edge = NULL, **all_edge = NULL, **ee1=NULL, **ee2=NULL;
|
||||||
|
BMVert **vv1 = NULL, **vv2 = NULL;
|
||||||
|
BridgeParams bp;
|
||||||
|
|
||||||
|
int i = 0, j = 0, loops_count = 0, cl1 = 0, cl2 = 0;
|
||||||
|
BMFace *f, **face_list = NULL;
|
||||||
|
|
||||||
|
BLI_array_declare(skip_edge);
|
||||||
|
BLI_array_declare(all_edge);
|
||||||
|
BLI_array_declare(ee1);
|
||||||
|
BLI_array_declare(ee2);
|
||||||
|
BLI_array_declare(vv1);
|
||||||
|
BLI_array_declare(vv2);
|
||||||
|
BLI_array_declare(face_list);
|
||||||
|
|
||||||
|
// init bridge param
|
||||||
|
bp.newVertices.first = bp.newVertices.last = NULL;
|
||||||
|
bp.seg = BMO_slot_int_get(op, "segmentation");
|
||||||
|
if (BMO_slot_int_get(op,"interpolation"))
|
||||||
|
bp.inter = CUBIC_INTER;
|
||||||
|
else
|
||||||
|
bp.inter = LINEAR_INTER;
|
||||||
|
bp.strenght = BMO_slot_float_get(op, "strenght");
|
||||||
|
|
||||||
|
// find all edges in faces
|
||||||
|
BMO_ITER (f, &siter, bm, op, "edgefacein", BM_FACE)
|
||||||
|
{
|
||||||
|
BMLoop* loop;
|
||||||
|
loop = f->l_first;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
BLI_array_append(all_edge, loop->e);
|
||||||
|
loop = loop->next;
|
||||||
|
}
|
||||||
|
while (loop != f->l_first);
|
||||||
|
}
|
||||||
|
// count entry edges
|
||||||
|
for (i = 0; i< BLI_array_count(all_edge); i++)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
for (j = 0; j< BLI_array_count(all_edge); j++)
|
||||||
|
{
|
||||||
|
if ((all_edge[i] == all_edge[j]) && (i != j))
|
||||||
|
counter ++;
|
||||||
|
}
|
||||||
|
if ((counter > 0) &&
|
||||||
|
(bmo_bridge_array_entry_elem(skip_edge,
|
||||||
|
BLI_array_count(skip_edge),
|
||||||
|
all_edge[i]) == 0 ))
|
||||||
|
{
|
||||||
|
BLI_array_append(skip_edge, all_edge[i]);
|
||||||
|
BMO_elem_flag_enable(bm, all_edge[i], EDGE_DONE); // skiped adjacent faces edge
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO develop non connected case
|
||||||
|
// create loop according with skiped edges
|
||||||
|
BMO_slot_buffer_flag_enable(bm, op, "edgefacein", BM_EDGE, EDGE_MARK);
|
||||||
|
BMO_ITER (e, &siter, bm, op, "edgefacein", BM_EDGE)
|
||||||
|
{
|
||||||
|
if (!BMO_elem_flag_test(bm, e, EDGE_DONE))
|
||||||
|
{
|
||||||
|
BMVert *v, *ov;
|
||||||
|
BMEdge *e2, *e3;
|
||||||
|
|
||||||
|
if (loops_count > 2)
|
||||||
|
{
|
||||||
|
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Select only two edge loops");
|
||||||
|
goto cleanup_2;
|
||||||
|
}
|
||||||
|
v = e->v1;
|
||||||
|
e2 = e;
|
||||||
|
ov = v;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (loops_count == 0)
|
||||||
|
{
|
||||||
|
BLI_array_append(ee1, e2);
|
||||||
|
BLI_array_append(vv1, v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BLI_array_append(ee2, e2);
|
||||||
|
BLI_array_append(vv2, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
BMO_elem_flag_enable(bm, e2, EDGE_DONE);
|
||||||
|
|
||||||
|
v = BM_edge_other_vert(e2, v);
|
||||||
|
BM_ITER_ELEM (e3, &iter, v, BM_EDGES_OF_VERT)
|
||||||
|
{
|
||||||
|
if ((e3 != e2)
|
||||||
|
&& (BMO_elem_flag_test(bm, e3, EDGE_MARK))
|
||||||
|
&& (!BMO_elem_flag_test(bm, e3, EDGE_DONE)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e3)
|
||||||
|
e2 = e3;
|
||||||
|
}
|
||||||
|
while (e3 && e2 != e);
|
||||||
|
/* test for connected loops, and set cl1 or cl2 if so */
|
||||||
|
if (v == ov) {
|
||||||
|
if (loops_count == 0) {
|
||||||
|
cl1 = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cl2 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loops_count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// -----------------------------------------------
|
||||||
|
// ---------------CREATE BRIDGE-------------------
|
||||||
|
// -----------------------------------------------
|
||||||
|
if (ee1 && ee2)
|
||||||
|
{
|
||||||
|
float min = 1e32;
|
||||||
|
int min_j;
|
||||||
|
float center1[3], center2[3];
|
||||||
|
BMEdge **non_conected = NULL, **conected = NULL;
|
||||||
|
BLI_array_declare(non_conected);
|
||||||
|
BLI_array_declare(conected);
|
||||||
|
|
||||||
|
if(BLI_array_count(ee1) > BLI_array_count(ee2))
|
||||||
|
{
|
||||||
|
ARRAY_SWAP(BMVert *, vv1, vv2);
|
||||||
|
ARRAY_SWAP(BMEdge *, ee1, ee2);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_centroid(vv1, BLI_array_count(vv1), center1);
|
||||||
|
get_centroid(vv2, BLI_array_count(vv2), center2);
|
||||||
|
|
||||||
|
copy_v3_v3(bp.centrod1, center1);
|
||||||
|
copy_v3_v3(bp.centrod2, center2);
|
||||||
|
|
||||||
|
for (i = 0; i < BLI_array_count(ee1); i++)
|
||||||
|
BMO_elem_flag_enable(bm, ee1[i], EDGE_NON_CONNECTED);
|
||||||
|
for (i = 0; i < BLI_array_count(ee2); i++)
|
||||||
|
BMO_elem_flag_enable(bm, ee2[i], EDGE_NON_CONNECTED);
|
||||||
|
|
||||||
|
for (i = 0; i < BLI_array_count(ee1); i++)
|
||||||
|
{
|
||||||
|
float mid_V_i[3], mid_V_j[3]/*, centerV[3]*/;
|
||||||
|
float co1[3], angel;
|
||||||
|
|
||||||
|
get_middle_edge(ee1[i], mid_V_i);
|
||||||
|
sub_v3_v3v3(co1, mid_V_i, bp.centrod1);
|
||||||
|
/* sub_v3_v3v3(centerV, bp.centrod2, bp.centrod1);
|
||||||
|
angel = angle_v3v3(centerV, co1);
|
||||||
|
mul_v3_fl(co1, cos(angel - M_PI_2));*/
|
||||||
|
min = 1e32;
|
||||||
|
min_j = -1;
|
||||||
|
for (j = 0; j < BLI_array_count(ee2); j++)
|
||||||
|
{
|
||||||
|
float co2[3], summ[3]; // new coordinate with center of loops
|
||||||
|
if (BMO_elem_flag_test(bm, ee2[j], EDGE_NON_CONNECTED))
|
||||||
|
{
|
||||||
|
get_middle_edge(ee2[j],mid_V_j);
|
||||||
|
sub_v3_v3v3(co2, mid_V_j, bp.centrod2);
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
/*
|
||||||
|
sub_v3_v3v3(centerV, bp.centrod1, bp.centrod2);
|
||||||
|
angel = angle_v3v3(centerV, co2);
|
||||||
|
mul_v3_fl(co2, cos(angel-M_PI_2));
|
||||||
|
*/
|
||||||
|
//-----------------
|
||||||
|
//sub_v3_v3v3(co1, mid_V_i, bp.centrod1);
|
||||||
|
//sub_v3_v3v3(co2, mid_V_j, bp.centrod2);
|
||||||
|
//---------------------------------
|
||||||
|
//sub_v3_v3v3(co1, co1, bp.centrod1);
|
||||||
|
//sub_v3_v3v3(co2, co2, bp.centrod2);
|
||||||
|
//---------------------------------
|
||||||
|
angel = angle_v3v3(co1, co2);
|
||||||
|
add_v3_v3v3(summ, co1, co2);
|
||||||
|
//angel = angle_v3v3(co1, summ);
|
||||||
|
if (len_v3v3(co1, co2) < min)
|
||||||
|
{
|
||||||
|
min = len_v3v3(co1, co2);
|
||||||
|
min_j = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min_j != -1){
|
||||||
|
f = bmo_edge_face_connect(bm, &bp, ee1[i], ee2[min_j], NULL);
|
||||||
|
if (f != NULL)
|
||||||
|
BLI_array_append(face_list, f);
|
||||||
|
|
||||||
|
BLI_array_append(conected, ee2[min_j]);
|
||||||
|
BMO_elem_flag_enable(bm, ee2[min_j], EDGE_CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// create triangle
|
||||||
|
for (i = 0; i < BLI_array_count(ee2); i++)
|
||||||
|
{
|
||||||
|
int flag = 0;
|
||||||
|
for (j = 0; j < BLI_array_count(conected); j++)
|
||||||
|
{
|
||||||
|
if (ee2[i] == conected[j])
|
||||||
|
flag = 1;
|
||||||
|
}
|
||||||
|
if (flag == 0)
|
||||||
|
BLI_array_append(non_conected, ee2[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// найти ближающую точку в vv1; и приконектить...
|
||||||
|
for (i = 0; i< BLI_array_count(non_conected); i++)
|
||||||
|
{
|
||||||
|
//if (BMO_elem_flag_test(bm, ee2[i], EDGE_CONNECTED))
|
||||||
|
//{
|
||||||
|
float mid[3];
|
||||||
|
float co1[3], co2[3]; // new coordinate with center of loops
|
||||||
|
|
||||||
|
get_middle_edge(non_conected[i], mid);
|
||||||
|
sub_v3_v3v3(co1, mid, center2);
|
||||||
|
min = 1e32;
|
||||||
|
min_j = 0;
|
||||||
|
for (j = 0; j < BLI_array_count(vv1); j++) {
|
||||||
|
sub_v3_v3v3(co2, vv1[j]->co, center1);
|
||||||
|
if (len_v3v3(co1, co2) < min)
|
||||||
|
{
|
||||||
|
min = len_v3v3(co1, co2);
|
||||||
|
min_j = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f = bmo_edge_vert_connect(bm, &bp, non_conected[i], vv1[min_j], NULL);
|
||||||
|
if (f != NULL)
|
||||||
|
BLI_array_append(face_list, f);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
BLI_array_free(non_conected);
|
||||||
|
BLI_array_free(conected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
if (BMO_slot_bool_get(op,"n_gon"))
|
||||||
|
bridge_n_gon_optimization(bm, face_list, BLI_array_count(face_list));
|
||||||
|
// -----kill input data-------------------------
|
||||||
|
BMO_ITER (f, &siter, bm, op, "edgefacein", BM_FACE)
|
||||||
|
{
|
||||||
|
BM_face_kill(bm,f);
|
||||||
|
}
|
||||||
|
for (i=0; i< BLI_array_count(skip_edge); i++){
|
||||||
|
BM_edge_kill(bm, skip_edge[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_2:
|
||||||
|
BLI_array_free(ee1);
|
||||||
|
BLI_array_free(ee2);
|
||||||
|
BLI_array_free(vv1);
|
||||||
|
BLI_array_free(vv2);
|
||||||
|
BLI_array_free(skip_edge);
|
||||||
|
BLI_array_free(all_edge);
|
||||||
|
BLI_freelistN(&bp.newVertices);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bmo_bridge_loops_exec_old(BMesh *bm, BMOperator *op)
|
||||||
{
|
{
|
||||||
BMEdge **ee1 = NULL, **ee2 = NULL;
|
BMEdge **ee1 = NULL, **ee2 = NULL;
|
||||||
BMVert **vv1 = NULL, **vv2 = NULL;
|
BMVert **vv1 = NULL, **vv2 = NULL;
|
||||||
|
613
source/blender/bmesh/operators/bmo_smooth_laplacian.c
Normal file
613
source/blender/bmesh/operators/bmo_smooth_laplacian.c
Normal file
@@ -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);
|
||||||
|
}
|
@@ -99,7 +99,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
|
|||||||
RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
|
RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
|
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
|
||||||
smooth, fractal, along_normal,
|
smooth, fractal, along_normal,
|
||||||
cuts,
|
cuts,
|
||||||
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
|
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
|
||||||
@@ -1607,6 +1607,90 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
|
|||||||
RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
|
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);
|
||||||
|
ModifierData *md;
|
||||||
|
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 *************************/
|
/********************** Smooth/Solid Operators *************************/
|
||||||
|
|
||||||
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
|
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
|
||||||
@@ -4470,7 +4554,11 @@ typedef struct {
|
|||||||
|
|
||||||
static void edbm_bevel_update_header(wmOperator *op, bContext *C)
|
static void edbm_bevel_update_header(wmOperator *op, bContext *C)
|
||||||
{
|
{
|
||||||
|
#ifdef OLDBEV
|
||||||
static char str[] = "Confirm: Enter/LClick, Cancel: (Esc/RMB), factor: %s, Use Dist (D): %s: Use Even (E): %s";
|
static char str[] = "Confirm: Enter/LClick, Cancel: (Esc/RMB), factor: %s, Use Dist (D): %s: Use Even (E): %s";
|
||||||
|
#else
|
||||||
|
static char str[] = "Confirm: Enter/LClick, Cancel: (Esc/RMB), factor: %s, segments: %d";
|
||||||
|
#endif
|
||||||
|
|
||||||
char msg[HEADER_LENGTH];
|
char msg[HEADER_LENGTH];
|
||||||
ScrArea *sa = CTX_wm_area(C);
|
ScrArea *sa = CTX_wm_area(C);
|
||||||
@@ -4482,11 +4570,18 @@ static void edbm_bevel_update_header(wmOperator *op, bContext *C)
|
|||||||
outputNumInput(&opdata->num_input, factor_str);
|
outputNumInput(&opdata->num_input, factor_str);
|
||||||
else
|
else
|
||||||
BLI_snprintf(factor_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "percent"));
|
BLI_snprintf(factor_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "percent"));
|
||||||
|
#ifdef OLDBEV
|
||||||
BLI_snprintf(msg, HEADER_LENGTH, str,
|
BLI_snprintf(msg, HEADER_LENGTH, str,
|
||||||
factor_str,
|
factor_str,
|
||||||
RNA_boolean_get(op->ptr, "use_dist") ? "On" : "Off",
|
RNA_boolean_get(op->ptr, "use_dist") ? "On" : "Off",
|
||||||
RNA_boolean_get(op->ptr, "use_even") ? "On" : "Off"
|
|
||||||
);
|
RNA_boolean_get(op->ptr, "use_even") ? "On" : "Off",
|
||||||
|
RNA_float_get(op->ptr, "Amount"),
|
||||||
|
RNA_int_get(op->ptr, "Segmentation")
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
BLI_snprintf(msg, HEADER_LENGTH, str, factor_str, RNA_int_get(op->ptr, "segmentation"));
|
||||||
|
#endif
|
||||||
|
|
||||||
ED_area_headerprint(sa, msg);
|
ED_area_headerprint(sa, msg);
|
||||||
}
|
}
|
||||||
@@ -4573,6 +4668,8 @@ static int edbm_bevel_calc(bContext *C, wmOperator *op)
|
|||||||
int recursion = 1; /* RNA_int_get(op->ptr, "recursion"); */ /* temp removed, see comment below */
|
int recursion = 1; /* RNA_int_get(op->ptr, "recursion"); */ /* temp removed, see comment below */
|
||||||
const int use_even = RNA_boolean_get(op->ptr, "use_even");
|
const int use_even = RNA_boolean_get(op->ptr, "use_even");
|
||||||
const int use_dist = RNA_boolean_get(op->ptr, "use_dist");
|
const int use_dist = RNA_boolean_get(op->ptr, "use_dist");
|
||||||
|
int seg = RNA_int_get(op->ptr, "segmentation");
|
||||||
|
float amount = RNA_float_get(op->ptr, "amount");
|
||||||
|
|
||||||
/* revert to original mesh */
|
/* revert to original mesh */
|
||||||
if (opdata->is_modal) {
|
if (opdata->is_modal) {
|
||||||
@@ -4584,8 +4681,22 @@ static int edbm_bevel_calc(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
|
|
||||||
if (!EDBM_op_init(em, &bmop, op,
|
if (!EDBM_op_init(em, &bmop, op,
|
||||||
"bevel geom=%hev percent=%f lengthlayer=%i use_lengths=%b use_even=%b use_dist=%b",
|
"bevel geom=%hev"
|
||||||
BM_ELEM_SELECT, fac, opdata->li, TRUE, use_even, use_dist))
|
" percent=%f"
|
||||||
|
" lengthlayer=%i"
|
||||||
|
" use_lengths=%b"
|
||||||
|
" use_even=%b"
|
||||||
|
" use_dist=%b"
|
||||||
|
" amount=%f"
|
||||||
|
" segmentation=%i",
|
||||||
|
BM_ELEM_SELECT,
|
||||||
|
fac,
|
||||||
|
opdata->li,
|
||||||
|
TRUE,
|
||||||
|
use_even,
|
||||||
|
use_dist,
|
||||||
|
amount,
|
||||||
|
seg))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4797,14 +4908,40 @@ void MESH_OT_bevel(wmOperatorType *ot)
|
|||||||
RNA_def_boolean(ot->srna, "use_even", FALSE, "Even", "Calculate evenly spaced bevel");
|
RNA_def_boolean(ot->srna, "use_even", FALSE, "Even", "Calculate evenly spaced bevel");
|
||||||
RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units");
|
RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units");
|
||||||
|
|
||||||
|
RNA_def_float(ot->srna, "amount", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
|
||||||
|
RNA_def_int(ot->srna, "segmentation", 1, 1, 10000, "Segmentation", "", 1, 100);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BRIDGE_LINEAR,
|
||||||
|
BRIDGE_CUBIC
|
||||||
|
};
|
||||||
|
|
||||||
static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
|
static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
BMEditMesh *em = BMEdit_FromObject(obedit);
|
BMEditMesh *em = BMEdit_FromObject(obedit);
|
||||||
|
int seg = RNA_int_get(op->ptr, "Segmentation");
|
||||||
if (!EDBM_op_callf(em, op, "bridge_loops edges=%he", BM_ELEM_SELECT))
|
int interpolation_flag = 0;
|
||||||
|
int ngon = RNA_boolean_get(op->ptr, "n_gon");
|
||||||
|
float strenght = RNA_float_get(op->ptr, "Strenght");
|
||||||
|
if (RNA_enum_get(op->ptr, "Interpolation") == BRIDGE_LINEAR)
|
||||||
|
interpolation_flag = 0;
|
||||||
|
if (RNA_enum_get(op->ptr, "Interpolation") == BRIDGE_CUBIC)
|
||||||
|
interpolation_flag = 1;
|
||||||
|
if (!EDBM_op_callf(em, op,
|
||||||
|
"bridge_loops "
|
||||||
|
"edgefacein=%hfe "
|
||||||
|
"segmentation=%i "
|
||||||
|
"interpolation=%i "
|
||||||
|
"strenght=%f "
|
||||||
|
"n_gon=%b",
|
||||||
|
BM_ELEM_SELECT,
|
||||||
|
seg,
|
||||||
|
interpolation_flag,
|
||||||
|
strenght,
|
||||||
|
ngon))
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
|
|
||||||
EDBM_update_generic(C, em, TRUE);
|
EDBM_update_generic(C, em, TRUE);
|
||||||
@@ -4812,9 +4949,16 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
|
|||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EnumPropertyItem prop_mesh_bridge_interpolation_types[] = {
|
||||||
|
{BRIDGE_LINEAR, "LINEAR", 0, "Linear", ""},
|
||||||
|
{BRIDGE_CUBIC, "CUBIC", 0, "Cubic", ""},
|
||||||
|
{0, NULL, 0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
|
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
|
||||||
|
|
||||||
{
|
{
|
||||||
/* identifiers */
|
/* identifiers */
|
||||||
ot->name = "Bridge Two Edge Loops";
|
ot->name = "Bridge Two Edge Loops";
|
||||||
ot->description = "Make faces between two edge loops";
|
ot->description = "Make faces between two edge loops";
|
||||||
ot->idname = "MESH_OT_bridge_edge_loops";
|
ot->idname = "MESH_OT_bridge_edge_loops";
|
||||||
@@ -4826,7 +4970,15 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
|
|||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
|
RNA_def_boolean(ot->srna, "n_gon", 0, "N-Gon optimization", "");
|
||||||
|
RNA_def_int(ot->srna, "Segmentation",1,1,1000,"Segmentation", "number of segments",0,50 );
|
||||||
|
RNA_def_enum(ot->srna,
|
||||||
|
"Interpolation",
|
||||||
|
prop_mesh_bridge_interpolation_types,
|
||||||
|
BRIDGE_LINEAR,
|
||||||
|
"Interpolation",
|
||||||
|
"Interpolation");
|
||||||
|
RNA_def_float(ot->srna, "Strenght", 0.5, -1.0f, 1.0f, "strenght", "strenght", -1.0f, 1.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -136,6 +136,7 @@ void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
|
|||||||
void MESH_OT_mark_seam(struct wmOperatorType *ot);
|
void MESH_OT_mark_seam(struct wmOperatorType *ot);
|
||||||
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
|
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
|
||||||
void MESH_OT_vertices_smooth(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_noise(struct wmOperatorType *ot);
|
||||||
void MESH_OT_flip_normals(struct wmOperatorType *ot);
|
void MESH_OT_flip_normals(struct wmOperatorType *ot);
|
||||||
void MESH_OT_solidify(struct wmOperatorType *ot);
|
void MESH_OT_solidify(struct wmOperatorType *ot);
|
||||||
|
@@ -132,6 +132,7 @@ void ED_operatortypes_mesh(void)
|
|||||||
WM_operatortype_append(MESH_OT_mark_seam);
|
WM_operatortype_append(MESH_OT_mark_seam);
|
||||||
WM_operatortype_append(MESH_OT_mark_sharp);
|
WM_operatortype_append(MESH_OT_mark_sharp);
|
||||||
WM_operatortype_append(MESH_OT_vertices_smooth);
|
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_noise);
|
||||||
WM_operatortype_append(MESH_OT_flip_normals);
|
WM_operatortype_append(MESH_OT_flip_normals);
|
||||||
//WM_operatortype_append(MESH_OT_knife_cut);
|
//WM_operatortype_append(MESH_OT_knife_cut);
|
||||||
|
@@ -401,7 +401,7 @@ void removeAspectRatio(TransInfo *t, float vec[2])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void viewRedrawForce(const bContext *C, TransInfo *t)
|
void viewRedrawForce(const bContext *C, TransInfo *t)
|
||||||
{
|
{
|
||||||
if (t->spacetype == SPACE_VIEW3D) {
|
if (t->spacetype == SPACE_VIEW3D) {
|
||||||
/* Do we need more refined tags? */
|
/* Do we need more refined tags? */
|
||||||
@@ -776,6 +776,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
|
|||||||
float mati[3][3] = MAT3_UNITY;
|
float mati[3][3] = MAT3_UNITY;
|
||||||
char cmode = constraintModeToChar(t);
|
char cmode = constraintModeToChar(t);
|
||||||
int handled = 1;
|
int handled = 1;
|
||||||
|
int snapping_handled = 0;
|
||||||
|
|
||||||
t->redraw |= handleMouseInput(t, &t->mouse, event);
|
t->redraw |= handleMouseInput(t, &t->mouse, event);
|
||||||
|
|
||||||
@@ -799,14 +800,20 @@ int transformEvent(TransInfo *t, wmEvent *event)
|
|||||||
t->redraw |= handleSnapping(t, event);
|
t->redraw |= handleSnapping(t, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snapping_handled = SnapSystem_Event(t->tsnap.ssystem, event);
|
||||||
|
|
||||||
/* handle modal keymap first */
|
/* handle modal keymap first */
|
||||||
if (event->type == EVT_MODAL_MAP) {
|
if (event->type == EVT_MODAL_MAP) {
|
||||||
switch (event->val) {
|
switch (event->val) {
|
||||||
case TFM_MODAL_CANCEL:
|
case TFM_MODAL_CANCEL:
|
||||||
t->state = TRANS_CANCEL;
|
if(!snapping_handled){
|
||||||
|
t->state = TRANS_CANCEL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TFM_MODAL_CONFIRM:
|
case TFM_MODAL_CONFIRM:
|
||||||
t->state = TRANS_CONFIRM;
|
if(!snapping_handled){
|
||||||
|
t->state = TRANS_CONFIRM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TFM_MODAL_TRANSLATE:
|
case TFM_MODAL_TRANSLATE:
|
||||||
/* only switch when... */
|
/* only switch when... */
|
||||||
@@ -1009,7 +1016,9 @@ int transformEvent(TransInfo *t, wmEvent *event)
|
|||||||
else if (event->val == KM_PRESS) {
|
else if (event->val == KM_PRESS) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case RIGHTMOUSE:
|
case RIGHTMOUSE:
|
||||||
t->state = TRANS_CANCEL;
|
if(!snapping_handled){
|
||||||
|
t->state = TRANS_CANCEL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
/* enforce redraw of transform when modifiers are used */
|
/* enforce redraw of transform when modifiers are used */
|
||||||
case LEFTSHIFTKEY:
|
case LEFTSHIFTKEY:
|
||||||
@@ -1924,7 +1933,7 @@ void transformApply(bContext *C, TransInfo *t)
|
|||||||
|
|
||||||
if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
|
if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
|
||||||
selectConstraint(t);
|
selectConstraint(t);
|
||||||
if (t->transform) {
|
if (t->transform && (SnapSystem_get_state(t->tsnap.ssystem) != SNAPSYSTEM_STATE_INIT_SNAP)) {
|
||||||
t->transform(t, t->mval); // calls recalcData()
|
t->transform(t, t->mval); // calls recalcData()
|
||||||
viewRedrawForce(C, t);
|
viewRedrawForce(C, t);
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#include "BLI_smallhash.h"
|
#include "BLI_smallhash.h"
|
||||||
#include "BKE_tessmesh.h"
|
#include "BKE_tessmesh.h"
|
||||||
|
#include "BKE_snap.h"
|
||||||
|
|
||||||
/* ************************** Types ***************************** */
|
/* ************************** Types ***************************** */
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ typedef struct TransSnapPoint {
|
|||||||
} TransSnapPoint;
|
} TransSnapPoint;
|
||||||
|
|
||||||
typedef struct TransSnap {
|
typedef struct TransSnap {
|
||||||
|
SnapSystem *ssystem;
|
||||||
short mode;
|
short mode;
|
||||||
short target;
|
short target;
|
||||||
short modePoint;
|
short modePoint;
|
||||||
@@ -82,6 +84,8 @@ typedef struct TransSnap {
|
|||||||
char snap_self;
|
char snap_self;
|
||||||
short peel;
|
short peel;
|
||||||
short status;
|
short status;
|
||||||
|
int r_dist;
|
||||||
|
float r_depth;
|
||||||
float snapPoint[3]; /* snapping from this point */
|
float snapPoint[3]; /* snapping from this point */
|
||||||
float snapTarget[3]; /* to this point */
|
float snapTarget[3]; /* to this point */
|
||||||
float snapNormal[3];
|
float snapNormal[3];
|
||||||
@@ -462,6 +466,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
|
|||||||
|
|
||||||
void applyAspectRatio(TransInfo *t, float *vec);
|
void applyAspectRatio(TransInfo *t, float *vec);
|
||||||
void removeAspectRatio(TransInfo *t, float *vec);
|
void removeAspectRatio(TransInfo *t, float *vec);
|
||||||
|
void viewRedrawForce(const bContext *C, TransInfo *t);
|
||||||
|
|
||||||
void initWarp(TransInfo *t);
|
void initWarp(TransInfo *t);
|
||||||
int handleEventWarp(TransInfo *t, struct wmEvent *event);
|
int handleEventWarp(TransInfo *t, struct wmEvent *event);
|
||||||
@@ -552,6 +557,24 @@ void drawPropCircle(const struct bContext *C, TransInfo *t);
|
|||||||
|
|
||||||
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
|
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
|
||||||
|
|
||||||
|
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
||||||
|
#define TFM_MODAL_CANCEL 1
|
||||||
|
#define TFM_MODAL_CONFIRM 2
|
||||||
|
#define TFM_MODAL_TRANSLATE 3
|
||||||
|
#define TFM_MODAL_ROTATE 4
|
||||||
|
#define TFM_MODAL_RESIZE 5
|
||||||
|
#define TFM_MODAL_SNAP_INV_ON 6
|
||||||
|
#define TFM_MODAL_SNAP_INV_OFF 7
|
||||||
|
#define TFM_MODAL_SNAP_TOGGLE 8
|
||||||
|
#define TFM_MODAL_AXIS_X 9
|
||||||
|
#define TFM_MODAL_AXIS_Y 10
|
||||||
|
#define TFM_MODAL_AXIS_Z 11
|
||||||
|
#define TFM_MODAL_PLANE_X 12
|
||||||
|
#define TFM_MODAL_PLANE_Y 13
|
||||||
|
#define TFM_MODAL_PLANE_Z 14
|
||||||
|
#define TFM_MODAL_CONS_OFF 15
|
||||||
|
#define TFM_MODAL_ADD_SNAP 16
|
||||||
|
#define TFM_MODAL_REMOVE_SNAP 17
|
||||||
|
|
||||||
/*********************** transform_conversions.c ********** */
|
/*********************** transform_conversions.c ********** */
|
||||||
struct ListBase;
|
struct ListBase;
|
||||||
@@ -623,6 +646,8 @@ void snapGridAction(TransInfo *t, float *val, GearsType action);
|
|||||||
int activeSnap(TransInfo *t);
|
int activeSnap(TransInfo *t);
|
||||||
int validSnap(TransInfo *t);
|
int validSnap(TransInfo *t);
|
||||||
|
|
||||||
|
void initSnappingSystem(TransInfo *t, bContext *C);
|
||||||
|
void runSnappingSystem(TransInfo *t, float *UNUSED);
|
||||||
void initSnapping(struct TransInfo *t, struct wmOperator *op);
|
void initSnapping(struct TransInfo *t, struct wmOperator *op);
|
||||||
void applyProject(TransInfo *t);
|
void applyProject(TransInfo *t);
|
||||||
void applySnapping(TransInfo *t, float *vec);
|
void applySnapping(TransInfo *t, float *vec);
|
||||||
|
@@ -1259,6 +1259,7 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTransformViewMatrices(t);
|
setTransformViewMatrices(t);
|
||||||
|
initSnappingSystem(t, C);
|
||||||
initNumInput(&t->num);
|
initNumInput(&t->num);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1327,6 +1328,8 @@ void postTrans(bContext *C, TransInfo *t)
|
|||||||
if (t->mouse.data) {
|
if (t->mouse.data) {
|
||||||
MEM_freeN(t->mouse.data);
|
MEM_freeN(t->mouse.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SnapSystem_free(t->tsnap.ssystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyTransObjects(TransInfo *t)
|
void applyTransObjects(TransInfo *t)
|
||||||
|
@@ -61,6 +61,8 @@
|
|||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_tessmesh.h"
|
#include "BKE_tessmesh.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
|
#include "BKE_snap.h"
|
||||||
|
#include "BKE_context.h"
|
||||||
|
|
||||||
#include "ED_armature.h"
|
#include "ED_armature.h"
|
||||||
#include "ED_image.h"
|
#include "ED_image.h"
|
||||||
@@ -78,6 +80,9 @@
|
|||||||
|
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
|
|
||||||
|
|
||||||
|
//#include "blendef.h" /* for selection modes */
|
||||||
|
|
||||||
#define USE_BVH_FACE_SNAP
|
#define USE_BVH_FACE_SNAP
|
||||||
|
|
||||||
/********************* PROTOTYPES ***********************/
|
/********************* PROTOTYPES ***********************/
|
||||||
@@ -154,9 +159,10 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
|
|||||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||||
float imat[4][4];
|
float imat[4][4];
|
||||||
float size;
|
float size;
|
||||||
|
|
||||||
|
SnapSystem_draw(t->tsnap.ssystem);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
|
size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
|
||||||
|
|
||||||
invert_m4_m4(imat, rv3d->viewmat);
|
invert_m4_m4(imat, rv3d->viewmat);
|
||||||
@@ -273,7 +279,7 @@ int handleSnapping(TransInfo *t, wmEvent *event)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (event->type == MOUSEMOVE) {
|
if (event->type == MOUSEMOVE) {
|
||||||
status |= updateSelectedSnapPoint(t);
|
//status |= updateSelectedSnapPoint(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -429,9 +435,15 @@ static void initSnappingMode(TransInfo *t)
|
|||||||
/* Exclude editmesh if using proportional edit */
|
/* Exclude editmesh if using proportional edit */
|
||||||
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
|
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
|
||||||
t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
|
t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
|
||||||
|
SnapSystem_set_mode_select(t->tsnap.ssystem, SNAPSYSTEM_MODE_SELECT_NOT_OBEDIT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
|
t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
|
||||||
|
if(t->tsnap.snap_self){
|
||||||
|
SnapSystem_set_mode_select(t->tsnap.ssystem, SNAPSYSTEM_MODE_SELECT_ALL);
|
||||||
|
}else{
|
||||||
|
SnapSystem_set_mode_select(t->tsnap.ssystem, SNAPSYSTEM_MODE_SELECT_NOT_OBEDIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Particles edit mode*/
|
/* Particles edit mode*/
|
||||||
@@ -439,12 +451,14 @@ static void initSnappingMode(TransInfo *t)
|
|||||||
(obedit == NULL && BASACT && BASACT->object && BASACT->object->mode & OB_MODE_PARTICLE_EDIT))
|
(obedit == NULL && BASACT && BASACT->object && BASACT->object->mode & OB_MODE_PARTICLE_EDIT))
|
||||||
{
|
{
|
||||||
t->tsnap.modeSelect = SNAP_ALL;
|
t->tsnap.modeSelect = SNAP_ALL;
|
||||||
|
SnapSystem_set_mode_select(t->tsnap.ssystem, SNAPSYSTEM_MODE_SELECT_ALL);
|
||||||
}
|
}
|
||||||
/* Object mode */
|
/* Object mode */
|
||||||
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
|
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
|
||||||
(obedit == NULL) ) // Object Mode
|
(obedit == NULL) ) // Object Mode
|
||||||
{
|
{
|
||||||
t->tsnap.modeSelect = SNAP_NOT_SELECTED;
|
t->tsnap.modeSelect = SNAP_NOT_SELECTED;
|
||||||
|
SnapSystem_set_mode_select(t->tsnap.ssystem, SNAPSYSTEM_MODE_SELECT_NOT_SELECTED);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Grid if snap is not possible */
|
/* Grid if snap is not possible */
|
||||||
@@ -468,6 +482,85 @@ static void initSnappingMode(TransInfo *t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//callback with no feedback, to prevent verts from moving from original position..
|
||||||
|
//maybe rename to resetfeedback
|
||||||
|
void SnappingNFBCallback(SnapSystem *ssystem, void* trans_info){
|
||||||
|
TransInfo* t = (TransInfo*)trans_info;
|
||||||
|
//TODO: find out where the snap point is applied and move it to the other callback functions
|
||||||
|
//below to prevent things moving after thiupdateSelectedSnapPoints function has been called.
|
||||||
|
restoreTransObjects(t); // calls recalcData()
|
||||||
|
viewRedrawForce(SnapSystem_get_C(ssystem), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnappingConfirmCallback(SnapSystem *ssystem, void* trans_info, SnapPoint sp){
|
||||||
|
TransInfo* t = (TransInfo*)trans_info;
|
||||||
|
copy_v3_v3(t->tsnap.snapPoint, sp.location);
|
||||||
|
copy_v3_v3(t->tsnap.snapNormal, sp.normal);
|
||||||
|
t->state = TRANS_CONFIRM;
|
||||||
|
t->redraw |= updateSelectedSnapPoint(t);
|
||||||
|
|
||||||
|
//TODO: clean this up and same with update function
|
||||||
|
//applyProject(TransInfo *t)
|
||||||
|
//t->tsnap.applySnap
|
||||||
|
|
||||||
|
// copy_v3_v3(t->tsnap.snapPoint, sp->location);
|
||||||
|
// copy_v3_v3(t->tsnap.snapNormal, sp->normal);
|
||||||
|
// if(retval){
|
||||||
|
// t->tsnap.status |= POINT_INIT;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// t->tsnap.status &= ~POINT_INIT;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnappingUpdateCallback(SnapSystem *ssystem, void* trans_info, SnapPoint sp){
|
||||||
|
TransInfo* t = (TransInfo*)trans_info;
|
||||||
|
//applyProject(TransInfo *t)
|
||||||
|
//t->tsnap.applySnap does this actuall fully apply it? (is it used while the mouse is moving?)
|
||||||
|
//applySnapping is another good function to look at, same as its callers Translation, Rotation and Scale
|
||||||
|
copy_v3_v3(t->tsnap.snapPoint, sp.location);
|
||||||
|
copy_v3_v3(t->tsnap.snapNormal, sp.normal);
|
||||||
|
t->redraw |= updateSelectedSnapPoint(t);
|
||||||
|
// if(retval){
|
||||||
|
// t->tsnap.status |= POINT_INIT;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// t->tsnap.status &= ~POINT_INIT;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnappingCancelCallback(SnapSystem* UNUSED(ssystem), void* trans_info){
|
||||||
|
/*TODO: fix this function to work properly in cancelling the snapping and resetting it*/
|
||||||
|
//TransInfo* t = (TransInfo*)trans_info;
|
||||||
|
//t->state = TRANS_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void runSnappingSystem(TransInfo *t, float *UNUSED){
|
||||||
|
SnapSystem_reset_snappoint(t->tsnap.ssystem);
|
||||||
|
SnapSystem_evaluate_stack(t->tsnap.ssystem);
|
||||||
|
|
||||||
|
|
||||||
|
if(SnapSystem_get_retval(t->tsnap.ssystem)){
|
||||||
|
t->tsnap.status |= POINT_INIT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t->tsnap.status &= ~POINT_INIT;
|
||||||
|
}
|
||||||
|
// SnapSystem_free(t->tsnap.ssystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initSnappingSystem(TransInfo *t, bContext *C){
|
||||||
|
t->tsnap.ssystem = SnapSystem_create(t->scene, t->view, t->ar, t->obedit, C, t,
|
||||||
|
SnappingUpdateCallback,
|
||||||
|
SnappingNFBCallback,
|
||||||
|
SnappingConfirmCallback,
|
||||||
|
SnappingCancelCallback);
|
||||||
|
// runSnappingSystem(t, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void initSnapping(TransInfo *t, wmOperator *op)
|
void initSnapping(TransInfo *t, wmOperator *op)
|
||||||
{
|
{
|
||||||
ToolSettings *ts = t->settings;
|
ToolSettings *ts = t->settings;
|
||||||
@@ -526,7 +619,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
|
|||||||
|
|
||||||
static void setSnappingCallback(TransInfo *t)
|
static void setSnappingCallback(TransInfo *t)
|
||||||
{
|
{
|
||||||
t->tsnap.calcSnap = CalcSnapGeometry;
|
t->tsnap.calcSnap = runSnappingSystem;//CalcSnapGeometry;
|
||||||
|
|
||||||
switch (t->tsnap.target) {
|
switch (t->tsnap.target) {
|
||||||
case SCE_SNAP_TARGET_CLOSEST:
|
case SCE_SNAP_TARGET_CLOSEST:
|
||||||
@@ -541,7 +634,6 @@ static void setSnappingCallback(TransInfo *t)
|
|||||||
case SCE_SNAP_TARGET_ACTIVE:
|
case SCE_SNAP_TARGET_ACTIVE:
|
||||||
t->tsnap.targetSnap = TargetSnapActive;
|
t->tsnap.targetSnap = TargetSnapActive;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (t->mode) {
|
switch (t->mode) {
|
||||||
@@ -805,8 +897,8 @@ static void UNUSED_FUNCTION(CalcSnapGrid) (TransInfo * t, float *UNUSED(vec))
|
|||||||
static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
|
static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
|
||||||
{
|
{
|
||||||
if (t->spacetype == SPACE_VIEW3D) {
|
if (t->spacetype == SPACE_VIEW3D) {
|
||||||
float loc[3];
|
float loc[3]; //temporary snapPoint location
|
||||||
float no[3];
|
float no[3]; //snapNormal
|
||||||
float mval[2];
|
float mval[2];
|
||||||
int found = 0;
|
int found = 0;
|
||||||
int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
|
int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
|
||||||
@@ -910,8 +1002,8 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
|
|||||||
copy_v3_v3(t->tsnap.snapTangent, tangent);
|
copy_v3_v3(t->tsnap.snapTangent, tangent);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_v3_v3(t->tsnap.snapPoint, loc);
|
//copy_v3_v3(t->tsnap.snapPoint, loc);
|
||||||
copy_v3_v3(t->tsnap.snapNormal, no);
|
// copy_v3_v3(t->tsnap.snapNormal, no); //disable current snapping system
|
||||||
|
|
||||||
t->tsnap.status |= POINT_INIT;
|
t->tsnap.status |= POINT_INIT;
|
||||||
}
|
}
|
||||||
@@ -1135,7 +1227,7 @@ static void TargetSnapClosest(TransInfo *t)
|
|||||||
}
|
}
|
||||||
/*================================================================*/
|
/*================================================================*/
|
||||||
#ifndef USE_BVH_FACE_SNAP
|
#ifndef USE_BVH_FACE_SNAP
|
||||||
static int snapFace(ARegion *ar, float v1co[3], float v2co[3], float v3co[3], float *v4co, float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float loc[3], float no[3], int *dist, float *depth)
|
//static int snapFace(ARegion *ar, float v1co[3], float v2co[3], float v3co[3], float *v4co, float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float loc[3], float no[3], int *dist, float *depth)
|
||||||
{
|
{
|
||||||
float lambda;
|
float lambda;
|
||||||
int result;
|
int result;
|
||||||
@@ -1269,6 +1361,54 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snapEdgeMiddle(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[][4], float timat[][3],
|
||||||
|
const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
|
||||||
|
float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
|
||||||
|
{
|
||||||
|
/*TODO: still need to calculate normal output properly using snapEdge code*/
|
||||||
|
float middle[3];
|
||||||
|
int retval = 0;
|
||||||
|
float dvec[3];
|
||||||
|
|
||||||
|
|
||||||
|
mid_v3_v3v3(middle, v1co, v2co); /*find the spot in the middle of the two edge vertices*/
|
||||||
|
|
||||||
|
sub_v3_v3v3(dvec, middle, ray_start_local);
|
||||||
|
|
||||||
|
if (dot_v3v3(ray_normal_local, dvec) > 0) {
|
||||||
|
float location[3];
|
||||||
|
float new_depth;
|
||||||
|
int screen_loc[2];
|
||||||
|
int new_dist;
|
||||||
|
|
||||||
|
copy_v3_v3(location, middle);
|
||||||
|
|
||||||
|
mul_m4_v3(obmat, location);
|
||||||
|
|
||||||
|
new_depth = len_v3v3(location, ray_start);
|
||||||
|
|
||||||
|
project_int(ar, location, screen_loc);
|
||||||
|
new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
|
||||||
|
|
||||||
|
if (new_dist <= *r_dist && new_depth < *r_depth) {
|
||||||
|
*r_depth = new_depth;
|
||||||
|
retval = 1;
|
||||||
|
|
||||||
|
copy_v3_v3(r_loc, location);
|
||||||
|
|
||||||
|
if (r_no) {
|
||||||
|
normal_short_to_float_v3(r_no, v1no);
|
||||||
|
mul_m3_v3(timat, r_no);
|
||||||
|
normalize_v3(r_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_dist = new_dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[][4], float timat[][3],
|
static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[][4], float timat[][3],
|
||||||
const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
|
const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2],
|
||||||
float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
|
float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
|
||||||
@@ -1584,7 +1724,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
|
|||||||
|
|
||||||
for (i = 0; i < totedge; i++) {
|
for (i = 0; i < totedge; i++) {
|
||||||
BMEdge *eed = NULL;
|
BMEdge *eed = NULL;
|
||||||
MEdge *e = edges + i;
|
MEdge *e = edges + i; //is this pointer arithmatic necessary? why not e = edges[i] ?
|
||||||
|
|
||||||
test = 1; /* reset for every vert */
|
test = 1; /* reset for every vert */
|
||||||
|
|
||||||
@@ -1602,6 +1742,8 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
|
|||||||
else {
|
else {
|
||||||
eed = EDBM_edge_at_index(em, index);
|
eed = EDBM_edge_at_index(em, index);
|
||||||
|
|
||||||
|
/*if edge is hidden, or vertex on either end of the edge is selected, then
|
||||||
|
don't use it to check for snapping*/
|
||||||
if (eed && (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
|
if (eed && (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
|
||||||
BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
|
BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
|
||||||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
|
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
|
||||||
@@ -1616,6 +1758,61 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (em != NULL) {
|
||||||
|
EDBM_index_arrays_free(em);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SCE_SNAP_MODE_EDGE_MIDDLE:
|
||||||
|
{
|
||||||
|
MVert *verts = dm->getVertArray(dm);
|
||||||
|
MEdge *edges = dm->getEdgeArray(dm);
|
||||||
|
int totedge = dm->getNumEdges(dm);
|
||||||
|
int *index_array = NULL;
|
||||||
|
int index = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (em != NULL) {
|
||||||
|
index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
|
||||||
|
EDBM_index_arrays_init(em, 0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < totedge; i++) {
|
||||||
|
BMEdge *eed = NULL;
|
||||||
|
MEdge *e = edges + i;
|
||||||
|
|
||||||
|
test = 1; /* reset for every vert */
|
||||||
|
|
||||||
|
if (em != NULL) {
|
||||||
|
if (index_array) {
|
||||||
|
index = index_array[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == ORIGINDEX_NONE) {
|
||||||
|
test = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eed = EDBM_edge_at_index(em, index);
|
||||||
|
|
||||||
|
/*if edge is hidden, or vertex on either end of the edge is selected, then
|
||||||
|
don't use it to check for snapping*/
|
||||||
|
if (eed && (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
|
||||||
|
BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
|
||||||
|
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
|
||||||
|
{
|
||||||
|
test = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test) {
|
||||||
|
retval |= snapEdgeMiddle(ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat, ray_start, ray_start_local, ray_normal_local, mval, r_loc, r_no, r_dist, r_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (em != NULL) {
|
if (em != NULL) {
|
||||||
EDBM_index_arrays_free(em);
|
EDBM_index_arrays_free(em);
|
||||||
}
|
}
|
||||||
@@ -1628,7 +1825,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[][4],
|
static int snapObject(Scene *scene, View3D *v3d, ARegion *ar, Object *ob, int editobject, float obmat[][4],
|
||||||
const float ray_start[3], const float ray_normal[3], const float mval[2],
|
const float ray_start[3], const float ray_normal[3], const float mval[2],
|
||||||
float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
|
float r_loc[3], float r_no[3], int *r_dist, float *r_depth)
|
||||||
{
|
{
|
||||||
@@ -1649,6 +1846,7 @@ static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, flo
|
|||||||
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
|
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
retval = snapDerivedMesh(ts->snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, r_depth);
|
retval = snapDerivedMesh(ts->snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, r_depth);
|
||||||
|
|
||||||
dm->release(dm);
|
dm->release(dm);
|
||||||
@@ -1673,7 +1871,7 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c
|
|||||||
if (mode == SNAP_ALL && obedit) {
|
if (mode == SNAP_ALL && obedit) {
|
||||||
Object *ob = obedit;
|
Object *ob = obedit;
|
||||||
|
|
||||||
retval |= snapObject(scene, ar, ob, 1, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
retval |= snapObject(scene, v3d, ar, ob, 1, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
|
/* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
|
||||||
@@ -1684,7 +1882,7 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c
|
|||||||
base = BASACT;
|
base = BASACT;
|
||||||
if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
|
if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
|
||||||
Object *ob = base->object;
|
Object *ob = base->object;
|
||||||
retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
retval |= snapObject(scene, v3d, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (base = FIRSTBASE; base != NULL; base = base->next) {
|
for (base = FIRSTBASE; base != NULL; base = base->next) {
|
||||||
@@ -1703,13 +1901,13 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c
|
|||||||
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
|
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
|
||||||
Object *dob = dupli_ob->ob;
|
Object *dob = dupli_ob->ob;
|
||||||
|
|
||||||
retval |= snapObject(scene, ar, dob, 0, dupli_ob->mat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
retval |= snapObject(scene, v3d, ar, dob, 0, dupli_ob->mat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_object_duplilist(lb);
|
free_object_duplilist(lb);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
retval |= snapObject(scene, v3d, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist, &depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -78,6 +78,7 @@ typedef enum ModifierType {
|
|||||||
eModifierType_DynamicPaint = 40,
|
eModifierType_DynamicPaint = 40,
|
||||||
eModifierType_Remesh = 41,
|
eModifierType_Remesh = 41,
|
||||||
eModifierType_Skin = 42,
|
eModifierType_Skin = 42,
|
||||||
|
eModifierType_LaplacianSmooth,
|
||||||
NUM_MODIFIER_TYPES
|
NUM_MODIFIER_TYPES
|
||||||
} ModifierType;
|
} ModifierType;
|
||||||
|
|
||||||
@@ -1093,4 +1094,17 @@ enum {
|
|||||||
MOD_SKIN_SMOOTH_SHADING = 1
|
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
|
#endif
|
||||||
|
@@ -1374,6 +1374,9 @@ typedef struct Scene {
|
|||||||
#define SCE_SNAP_MODE_NODE_X 5
|
#define SCE_SNAP_MODE_NODE_X 5
|
||||||
#define SCE_SNAP_MODE_NODE_Y 6
|
#define SCE_SNAP_MODE_NODE_Y 6
|
||||||
#define SCE_SNAP_MODE_NODE_XY 7
|
#define SCE_SNAP_MODE_NODE_XY 7
|
||||||
|
#define SCE_SNAP_MODE_EDGE_MIDDLE 8
|
||||||
|
#define SCE_SNAP_MODE_EDGE_PARALLEL 9
|
||||||
|
#define SCE_SNAP_MODE_PLANAR 10
|
||||||
|
|
||||||
/* toolsettings->selectmode */
|
/* toolsettings->selectmode */
|
||||||
#define SCE_SELECT_VERTEX 1 /* for mesh */
|
#define SCE_SELECT_VERTEX 1 /* for mesh */
|
||||||
|
@@ -477,6 +477,7 @@ extern StructRNA RNA_SmokeDomainSettings;
|
|||||||
extern StructRNA RNA_SmokeFlowSettings;
|
extern StructRNA RNA_SmokeFlowSettings;
|
||||||
extern StructRNA RNA_SmokeModifier;
|
extern StructRNA RNA_SmokeModifier;
|
||||||
extern StructRNA RNA_SmoothModifier;
|
extern StructRNA RNA_SmoothModifier;
|
||||||
|
extern StructRNA RNA_LaplacianSmoothModifier;
|
||||||
extern StructRNA RNA_SoftBodyModifier;
|
extern StructRNA RNA_SoftBodyModifier;
|
||||||
extern StructRNA RNA_SoftBodySettings;
|
extern StructRNA RNA_SoftBodySettings;
|
||||||
extern StructRNA RNA_SolidifyModifier;
|
extern StructRNA RNA_SolidifyModifier;
|
||||||
|
@@ -84,6 +84,7 @@ EnumPropertyItem modifier_type_items[] = {
|
|||||||
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
|
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
|
||||||
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
|
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
|
||||||
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
|
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
|
||||||
|
{eModifierType_LaplacianSmooth, "LAPLACIANSMOOTH", ICON_MOD_SMOOTH, "Laplacian Smooth", ""},
|
||||||
{eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""},
|
{eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""},
|
||||||
{eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""},
|
{eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""},
|
||||||
{eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
|
{eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
|
||||||
@@ -210,6 +211,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
|
|||||||
return &RNA_RemeshModifier;
|
return &RNA_RemeshModifier;
|
||||||
case eModifierType_Skin:
|
case eModifierType_Skin:
|
||||||
return &RNA_SkinModifier;
|
return &RNA_SkinModifier;
|
||||||
|
case eModifierType_LaplacianSmooth:
|
||||||
|
return &RNA_LaplacianSmoothModifier;
|
||||||
default:
|
default:
|
||||||
return &RNA_Modifier;
|
return &RNA_Modifier;
|
||||||
}
|
}
|
||||||
@@ -384,6 +387,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));
|
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)
|
static void rna_WaveModifier_vgroup_set(PointerRNA *ptr, const char *value)
|
||||||
{
|
{
|
||||||
WaveModifierData *lmd = (WaveModifierData *)ptr->data;
|
WaveModifierData *lmd = (WaveModifierData *)ptr->data;
|
||||||
@@ -1742,6 +1751,64 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
|
|||||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
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)
|
static void rna_def_modifier_cast(BlenderRNA *brna)
|
||||||
{
|
{
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
@@ -3356,6 +3423,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
|||||||
rna_def_modifier_ocean(brna);
|
rna_def_modifier_ocean(brna);
|
||||||
rna_def_modifier_remesh(brna);
|
rna_def_modifier_remesh(brna);
|
||||||
rna_def_modifier_skin(brna);
|
rna_def_modifier_skin(brna);
|
||||||
|
rna_def_modifier_laplaciansmooth(brna);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -132,7 +132,10 @@ EnumPropertyItem snap_element_items[] = {
|
|||||||
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
|
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
|
||||||
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
|
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
|
||||||
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
|
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
|
||||||
|
{SCE_SNAP_MODE_EDGE_MIDDLE, "EDGE_MIDDLE", ICON_SNAP_EDGE, "Edge Middle", "Snap to middle of edges"},
|
||||||
|
{SCE_SNAP_MODE_EDGE_PARALLEL, "EDGE_PARALLEL", ICON_SNAP_EDGE, "Edge Parallel", "Snap to the parallel of edge"},
|
||||||
{SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap to faces"},
|
{SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap to faces"},
|
||||||
|
{SCE_SNAP_MODE_PLANAR, "PLANAR", ICON_SNAP_FACE, "Planar", "Snap to plane picked from face"},
|
||||||
{SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"},
|
{SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"},
|
||||||
{0, NULL, 0, NULL, NULL}
|
{0, NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@@ -38,6 +38,7 @@ set(INC
|
|||||||
../render/extern/include
|
../render/extern/include
|
||||||
../../../intern/elbeem/extern
|
../../../intern/elbeem/extern
|
||||||
../../../intern/guardedalloc
|
../../../intern/guardedalloc
|
||||||
|
../../../intern/opennl/extern
|
||||||
)
|
)
|
||||||
|
|
||||||
set(INC_SYS
|
set(INC_SYS
|
||||||
@@ -64,6 +65,7 @@ set(SRC
|
|||||||
intern/MOD_fluidsim_util.c
|
intern/MOD_fluidsim_util.c
|
||||||
intern/MOD_hook.c
|
intern/MOD_hook.c
|
||||||
intern/MOD_lattice.c
|
intern/MOD_lattice.c
|
||||||
|
intern/MOD_laplaciansmooth.c
|
||||||
intern/MOD_mask.c
|
intern/MOD_mask.c
|
||||||
intern/MOD_meshdeform.c
|
intern/MOD_meshdeform.c
|
||||||
intern/MOD_mirror.c
|
intern/MOD_mirror.c
|
||||||
|
@@ -75,6 +75,7 @@ extern ModifierTypeInfo modifierType_WeightVGProximity;
|
|||||||
extern ModifierTypeInfo modifierType_DynamicPaint;
|
extern ModifierTypeInfo modifierType_DynamicPaint;
|
||||||
extern ModifierTypeInfo modifierType_Remesh;
|
extern ModifierTypeInfo modifierType_Remesh;
|
||||||
extern ModifierTypeInfo modifierType_Skin;
|
extern ModifierTypeInfo modifierType_Skin;
|
||||||
|
extern ModifierTypeInfo modifierType_LaplacianSmooth;
|
||||||
|
|
||||||
/* MOD_util.c */
|
/* MOD_util.c */
|
||||||
void modifier_type_init(ModifierTypeInfo *types[]);
|
void modifier_type_init(ModifierTypeInfo *types[]);
|
||||||
|
@@ -4,7 +4,7 @@ Import ('env')
|
|||||||
sources = env.Glob('intern/*.c')
|
sources = env.Glob('intern/*.c')
|
||||||
|
|
||||||
incs = '. ./intern'
|
incs = '. ./intern'
|
||||||
incs += ' #/intern/guardedalloc #/intern/decimation/extern #/intern/bsp/extern #/intern/elbeem/extern #/extern/glew/include'
|
incs += ' #/intern/guardedalloc #/intern/decimation/extern #/intern/bsp/extern #/intern/elbeem/extern #/extern/glew/include #/intern/opennl/extern'
|
||||||
incs += ' ../render/extern/include ../blenloader ../bmesh'
|
incs += ' ../render/extern/include ../blenloader ../bmesh'
|
||||||
incs += ' ../include ../blenlib ../blenfont ../makesdna ../makesrna ../blenkernel ../blenkernel/intern'
|
incs += ' ../include ../blenlib ../blenfont ../makesdna ../makesrna ../blenkernel ../blenkernel/intern'
|
||||||
incs += ' ../gpu'
|
incs += ' ../gpu'
|
||||||
|
697
source/blender/modifiers/intern/MOD_laplaciansmooth.c
Normal file
697
source/blender/modifiers/intern/MOD_laplaciansmooth.c
Normal file
@@ -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,
|
||||||
|
};
|
@@ -277,5 +277,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
|||||||
INIT_TYPE(DynamicPaint);
|
INIT_TYPE(DynamicPaint);
|
||||||
INIT_TYPE(Remesh);
|
INIT_TYPE(Remesh);
|
||||||
INIT_TYPE(Skin);
|
INIT_TYPE(Skin);
|
||||||
|
INIT_TYPE(LaplacianSmooth);
|
||||||
#undef INIT_TYPE
|
#undef INIT_TYPE
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user