Hair edit: Add operator to uniform length of selected hairs

Request by Andy, should help him a lot doing weird and wonderful hair styles.

A bit experimental yet, details of behavior might be changed after some real
usage feedback.
This commit is contained in:
Sergey Sharybin 2016-04-26 16:05:52 +02:00
parent 96392c33ef
commit ab500eb3f3
4 changed files with 116 additions and 0 deletions

View File

@ -1902,6 +1902,7 @@ class VIEW3D_MT_particle(Menu):
if particle_edit.select_mode == 'POINT':
layout.operator("particle.subdivide")
layout.operator("particle.unify_length")
layout.operator("particle.rekey")
layout.operator("particle.weight_set")
@ -1921,6 +1922,7 @@ class VIEW3D_MT_particle_specials(Menu):
layout.operator("particle.rekey")
layout.operator("particle.delete")
layout.operator("particle.remove_doubles")
layout.operator("particle.unify_length")
if particle_edit.select_mode == 'POINT':
layout.operator("particle.subdivide")

View File

@ -4809,3 +4809,113 @@ void PARTICLE_OT_edited_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ Unify length operator ************************/
static float calculate_point_length(PTCacheEditPoint *point)
{
float length = 0.0f;
KEY_K;
LOOP_KEYS {
if (k > 0) {
length += len_v3v3((key - 1)->co, key->co);;
}
}
return length;
}
static float calculate_average_length(PTCacheEdit *edit)
{
int num_selected = 0;
float total_length = 0;
POINT_P;
LOOP_SELECTED_POINTS {
total_length += calculate_point_length(point);
++num_selected;
}
if (num_selected == 0) {
return 0.0f;
}
return total_length / num_selected;
}
static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
float orig_prev_co[3], prev_co[3];
KEY_K;
LOOP_KEYS {
if (k == 0) {
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(prev_co, key->co);
}
else {
float new_co[3];
float delta[3];
sub_v3_v3v3(delta, key->co, orig_prev_co);
mul_v3_fl(delta, factor);
add_v3_v3v3(new_co, prev_co, delta);
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(key->co, new_co);
copy_v3_v3(prev_co, key->co);
}
}
point->flag |= PEP_EDIT_RECALC;
}
static void scale_point_to_length(PTCacheEditPoint *point, float length)
{
const float point_length = calculate_point_length(point);
if (point_length != 0.0f) {
const float factor = length / point_length;
scale_point_factor(point, factor);
}
}
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
POINT_P;
LOOP_SELECTED_POINTS {
scale_point_to_length(point, length);
}
recalc_lengths(edit);
}
static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
PTCacheEdit *edit = PE_get_current(scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
return OPERATOR_CANCELLED;
}
scale_points_to_length(edit, average_length);
PE_update_object(scene, ob, 1);
if (edit->psys) {
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
}
else {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
}
return OPERATOR_FINISHED;
}
void PARTICLE_OT_unify_length(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Unify Length";
ot->idname = "PARTICLE_OT_unify_length";
ot->description = "Make selected hair the same length";
/* api callbacks */
ot->exec = unify_length_exec;
ot->poll = PE_poll_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}

View File

@ -61,6 +61,8 @@ void PARTICLE_OT_shape_cut(struct wmOperatorType *ot);
void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot);
void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);

View File

@ -69,6 +69,8 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
WM_operatortype_append(PARTICLE_OT_edited_clear);
WM_operatortype_append(PARTICLE_OT_unify_length);
WM_operatortype_append(OBJECT_OT_particle_system_add);
WM_operatortype_append(OBJECT_OT_particle_system_remove);