Select Similar for edit-curve
authorCampbell Barton <ideasman42@gmail.com>
Wed, 8 Jul 2015 16:58:40 +0000 (02:58 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 8 Jul 2015 17:03:19 +0000 (03:03 +1000)
D1381 by @johnroper100 with edits

release/scripts/startup/bl_ui/space_view3d.py
source/blender/editors/curve/curve_intern.h
source/blender/editors/curve/curve_ops.c
source/blender/editors/curve/editcurve_select.c

index 8b388b9c4b10a51f91232043c8b46a2983d72856..b936e2df165e45dea0bb29b05b98c76b80581106 100644 (file)
@@ -730,6 +730,7 @@ class VIEW3D_MT_select_edit_curve(Menu):
         layout.operator("curve.select_random")
         layout.operator("curve.select_nth")
         layout.operator("curve.select_linked", text="Select Linked")
+        layout.operator("curve.select_similar", text="Select Similar")
 
         layout.separator()
 
@@ -760,6 +761,7 @@ class VIEW3D_MT_select_edit_surface(Menu):
         layout.operator("curve.select_random")
         layout.operator("curve.select_nth")
         layout.operator("curve.select_linked", text="Select Linked")
+        layout.operator("curve.select_similar", text="Select Similar")
 
         layout.separator()
 
index bb0abf4474426c3b6d35301b7150a6d383cbca37..86d7c4e8cb987226864907735ede5f5ddd7e4142 100644 (file)
@@ -150,6 +150,7 @@ void CURVE_OT_select_more(struct wmOperatorType *ot);
 void CURVE_OT_select_less(struct wmOperatorType *ot);
 void CURVE_OT_select_random(struct wmOperatorType *ot);
 void CURVE_OT_select_nth(struct wmOperatorType *ot);
+void CURVE_OT_select_similar(struct wmOperatorType *ot);
 
 /* editcurve_add.c */
 void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot);
index 4bcb16d31ef8dd851f61f78def4e8eca4cb6be4a..64ca4466b6f6e07b0e3e4d7778718cb4f40ccee9 100644 (file)
@@ -128,6 +128,7 @@ void ED_operatortypes_curve(void)
        WM_operatortype_append(CURVE_OT_select_less);
        WM_operatortype_append(CURVE_OT_select_random);
        WM_operatortype_append(CURVE_OT_select_nth);
+       WM_operatortype_append(CURVE_OT_select_similar);
 
        WM_operatortype_append(CURVE_OT_switch_direction);
        WM_operatortype_append(CURVE_OT_subdivide);
@@ -241,6 +242,7 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "CURVE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "CURVE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "CURVE_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "CURVE_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
 
        kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
        RNA_boolean_set(kmi->ptr, "deselect", false);
index 0a8c05ba16d274f3382b23f33f3371e2dca4d3e9..b5fa66bab2ccf1f196b1e62791deefe7b7f2c0d8 100644 (file)
@@ -20,7 +20,7 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): none yet.
+ * Contributor(s): John Roper
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -1154,3 +1154,347 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
        RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
        RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
 }
+
+
+/* -------------------------------------------------------------------- */
+/* Select Similar */
+
+/** \name Select Similar
+ * \{ */
+
+enum {
+       SIM_CMP_EQ = 0,
+       SIM_CMP_GT,
+       SIM_CMP_LT,
+};
+
+static EnumPropertyItem curve_prop_similar_compare_types[] = {
+       {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+       {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+       {SIM_CMP_LT, "LESS", 0, "Less", ""},
+
+       {0, NULL, 0, NULL, NULL}
+};
+
+enum {
+       SIMCURHAND_TYPE = 0,
+       SIMCURHAND_RADIUS,
+       SIMCURHAND_WEIGHT,
+       SIMCURHAND_DIRECTION,
+};
+
+static EnumPropertyItem curve_prop_similar_types[] = {
+       {SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
+       {SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
+       {SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
+       {SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
+{
+       switch (compare) {
+               case SIM_CMP_EQ:
+                       return (fabsf(delta) <= thresh);
+               case SIM_CMP_GT:
+                       return ((delta + thresh) >= 0.0f);
+               case SIM_CMP_LT:
+                       return ((delta - thresh) <= 0.0f);
+               default:
+                       BLI_assert(0);
+                       return 0;
+       }
+}
+
+
+static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
+{
+       BezTriple *bezt;
+       int i;
+
+       for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+               if (!bezt->hide) {
+                       float dir[3];
+                       BKE_nurb_bezt_calc_normal(nu, bezt, dir);
+                       if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
+                               select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static void curve_select_similar_direction__bp(Nurb *nu, const float dir_ref[3], float angle_cos)
+{
+       BPoint *bp;
+       int i;
+
+       for (i = nu->pntsu, bp = nu->bp; i--; bp++) {
+               if (!bp->hide) {
+                       float dir[3];
+                       BKE_nurb_bpoint_calc_normal(nu, bp, dir);
+                       if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
+                               select_bpoint(bp, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static bool curve_select_similar_direction(ListBase *editnurb, Curve *cu, float thresh)
+{
+       Nurb *nu, *act_nu;
+       void *act_vert;
+       float dir[3];
+       float angle_cos;
+
+       if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
+               return false;
+       }
+
+       if (act_nu->type == CU_BEZIER) {
+               BKE_nurb_bezt_calc_normal(act_nu, act_vert, dir);
+       }
+       else {
+               BKE_nurb_bpoint_calc_normal(act_nu, act_vert, dir);
+       }
+
+       /* map 0-1 to radians, 'cos' for comparison */
+       angle_cos = cosf(thresh * M_PI_2);
+
+       for (nu = editnurb->first; nu; nu = nu->next) {
+               if (nu->type == CU_BEZIER) {
+                       curve_select_similar_direction__bezt(nu, dir, angle_cos);
+               }
+               else {
+                       curve_select_similar_direction__bp(nu, dir, angle_cos);
+               }
+       }
+
+       return true;
+}
+
+static void curve_select_similar_radius__bezt(Nurb *nu, float radius_ref, int compare, float thresh)
+{
+       BezTriple *bezt;
+       int i;
+
+       for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+               if (!bezt->hide) {
+                       if (curve_select_similar_cmp_fl(bezt->radius - radius_ref, thresh, compare)) {
+                               select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
+{
+       BPoint *bp;
+       int i;
+
+       for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+               if (!bp->hide) {
+                       if (curve_select_similar_cmp_fl(bp->radius - radius_ref, thresh, compare)) {
+                               select_bpoint(bp, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static bool curve_select_similar_radius(ListBase *editnurb, Curve *cu, float compare, float thresh)
+{
+       Nurb *nu, *act_nu;
+       void *act_vert;
+       float radius_ref;
+
+       if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
+               return false;
+       }
+
+       if (act_nu->type == CU_BEZIER) {
+               radius_ref = ((BezTriple *)act_vert)->radius;
+       }
+       else {
+               radius_ref = ((BPoint *)act_vert)->radius;
+       }
+
+       /* make relative */
+       thresh *= radius_ref;
+
+       for (nu = editnurb->first; nu; nu = nu->next) {
+               if (nu->type == CU_BEZIER) {
+                       curve_select_similar_radius__bezt(nu, radius_ref, compare, thresh);
+               }
+               else {
+                       curve_select_similar_radius__bp(nu, radius_ref, compare, thresh);
+               }
+       }
+
+       return true;
+}
+
+static void curve_select_similar_weight__bezt(Nurb *nu, float weight_ref, int compare, float thresh)
+{
+       BezTriple *bezt;
+       int i;
+
+       for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+               if (!bezt->hide) {
+                       if (curve_select_similar_cmp_fl(bezt->weight - weight_ref, thresh, compare)) {
+                               select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static void curve_select_similar_weight__bp(Nurb *nu, float weight_ref, int compare, float thresh)
+{
+       BPoint *bp;
+       int i;
+
+       for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+               if (!bp->hide) {
+                       if (curve_select_similar_cmp_fl(bp->weight - weight_ref, thresh, compare)) {
+                               select_bpoint(bp, SELECT, SELECT, VISIBLE);
+                       }
+               }
+       }
+}
+
+static bool curve_select_similar_weight(ListBase *editnurb, Curve *cu, float compare, float thresh)
+{
+       Nurb *nu, *act_nu;
+       void *act_vert;
+       float weight_ref;
+
+       if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert))
+               return false;
+
+       if (act_nu->type == CU_BEZIER) {
+               weight_ref = ((BezTriple *)act_vert)->weight;
+       }
+       else {
+               weight_ref = ((BPoint *)act_vert)->weight;
+       }
+
+       for (nu = editnurb->first; nu; nu = nu->next) {
+               if (nu->type == CU_BEZIER) {
+                       curve_select_similar_weight__bezt(nu, weight_ref, compare, thresh);
+               }
+               else {
+                       curve_select_similar_weight__bp(nu, weight_ref, compare, thresh);
+               }
+       }
+
+       return true;
+}
+
+static void curve_select_all__bezt(Nurb *nu)
+{
+       BezTriple *bezt;
+       int i;
+
+       for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+               if (!bezt->hide) {
+                       select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+               }
+       }
+}
+
+static void curve_select_all__bp(Nurb *nu)
+{
+       BPoint *bp;
+       int i;
+
+       for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+               if (!bp->hide) {
+                       select_bpoint(bp, SELECT, SELECT, VISIBLE);
+               }
+       }
+}
+
+static bool curve_select_similar_type(ListBase *editnurb, Curve *cu)
+{
+       Nurb *nu, *act_nu;
+       int type_ref;
+
+       /* Get active nurb type */
+       act_nu = BKE_curve_nurb_active_get(cu);
+
+       if (!act_nu)
+               return false;
+
+       /* Get the active nurb type */
+       type_ref = act_nu->type;
+
+       for (nu = editnurb->first; nu; nu = nu->next) {
+               if (nu->type == type_ref) {
+                       if (type_ref == CU_BEZIER) {
+                               curve_select_all__bezt(nu);
+                       }
+                       else {
+                               curve_select_all__bp(nu);
+                       }
+               }
+       }
+
+       return true;
+}
+
+static int curve_select_similar_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit = CTX_data_edit_object(C);
+       Curve *cu = obedit->data;
+       ListBase *editnurb = object_editcurve_get(obedit);
+       bool changed = false;
+
+       /* Get props */
+       const int type = RNA_enum_get(op->ptr, "type");
+       const float thresh = RNA_float_get(op->ptr, "threshold");
+       const int compare = RNA_enum_get(op->ptr, "compare");
+
+       switch (type) {
+               case SIMCURHAND_TYPE:
+                       changed = curve_select_similar_type(editnurb, cu);
+                       break;
+               case SIMCURHAND_RADIUS:
+                       changed = curve_select_similar_radius(editnurb, cu, compare, thresh);
+                       break;
+               case SIMCURHAND_WEIGHT:
+                       changed = curve_select_similar_weight(editnurb, cu, compare, thresh);
+                       break;
+               case SIMCURHAND_DIRECTION:
+                       changed = curve_select_similar_direction(editnurb, cu, thresh);
+                       break;
+       }
+
+       if (changed) {
+               WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+               return OPERATOR_FINISHED;
+       }
+       else {
+               return OPERATOR_CANCELLED;
+       }
+}
+
+void CURVE_OT_select_similar(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Select Similar";
+       ot->idname = "CURVE_OT_select_similar";
+       ot->description = "Select similar curve points by property type";
+
+       /* api callbacks */
+       ot->invoke = WM_menu_invoke;
+       ot->exec = curve_select_similar_exec;
+       ot->poll = ED_operator_editsurfcurve;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* properties */
+       ot->prop = RNA_def_enum(ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
+       RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+       RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
+}
+
+/** \} */