Multi-Objects: CURVE_OT_select_similar
Implemented the following methods: * SIMCURHAND_TYPE * SIMCURHAND_RADIUS * SIMCURHAND_WEIGHT * SIMCURHAND_DIRECTION Limits: * DIRECTION does not support surfaces, because `BKE_nurb_bpoint_calc_normal` does not work with Nurbs of type `CU_CARDINAL`. This also didn't work prior to this patch, so we wait until surfaces are properly supported in EditMode. * Also DIRECTION should take scaling into consideration. We need our own versions of BKE_nurb_bpoint_calc_normal/bezt. * Threshold default is too large. Not sure if it's better to change the default or scale the threshold in code. Differential Revision: https://developer.blender.org/D3846 Changes from committer (Dalai Felinto): * Moved nurb_bpoint_direction_worldspace_get/bezt to functions. * Comments hinting at the mode (direction) that require scaling to be taken into account - to be addressed by patch creator in a future patch.
This commit is contained in:
parent
c19dafd2a6
commit
4e9911663a
Notes:
blender-bot
2023-02-14 06:00:51 +01:00
Referenced by issue #57677, Hardware acceleration in blender not working correctly while gizmos are present (noticeable lag) Referenced by issue #57670, Shader to RGB is not rendering on Eevee Referenced by issue #54648, Multi-Object-Mode: Edit Curve Tools
|
@ -39,12 +39,14 @@
|
|||
#include "BLI_rand.h"
|
||||
#include "BLI_heap.h"
|
||||
#include "BLI_heap_simple.h"
|
||||
#include "BLI_kdtree.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
@ -218,6 +220,18 @@ void ED_curve_nurb_deselect_all(Nurb *nu)
|
|||
}
|
||||
}
|
||||
|
||||
int ED_curve_select_count(View3D *v3d, struct EditNurb *editnurb)
|
||||
{
|
||||
int sel = 0;
|
||||
Nurb *nu;
|
||||
|
||||
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
||||
sel += ED_curve_nurb_select_count(v3d, nu);
|
||||
}
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
|
||||
{
|
||||
Nurb *nu;
|
||||
|
@ -1316,12 +1330,6 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
|
|||
/** \name Select Similar
|
||||
* \{ */
|
||||
|
||||
enum {
|
||||
SIM_CMP_EQ = 0,
|
||||
SIM_CMP_GT,
|
||||
SIM_CMP_LT,
|
||||
};
|
||||
|
||||
static const EnumPropertyItem curve_prop_similar_compare_types[] = {
|
||||
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
|
||||
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
|
||||
|
@ -1345,261 +1353,301 @@ static const EnumPropertyItem curve_prop_similar_types[] = {
|
|||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
|
||||
/** Note: This function should actually take scaling into consideration. */
|
||||
static void nurb_bezt_direction_worldspace_get(Object *ob, Nurb *nu, BezTriple *bezt, float r_dir[3])
|
||||
{
|
||||
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;
|
||||
}
|
||||
float rmat[3][3];
|
||||
BKE_nurb_bezt_calc_normal(nu, bezt, r_dir);
|
||||
BKE_object_rot_to_mat3(ob, rmat, true);
|
||||
mul_m3_v3(rmat, r_dir);
|
||||
}
|
||||
|
||||
|
||||
static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
|
||||
/** Note: This function should actually take scaling into consideration. */
|
||||
static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *bp, float r_dir[3])
|
||||
{
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
float rmat[3][3];
|
||||
BKE_nurb_bpoint_calc_normal(nu, bp, r_dir);
|
||||
BKE_object_rot_to_mat3(ob, rmat, true);
|
||||
mul_m3_v3(rmat, r_dir);
|
||||
}
|
||||
|
||||
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_nurb_selected_type_get(Object *ob, Nurb *nu, const int type, KDTree *r_tree)
|
||||
{
|
||||
float tree_entry[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
if (nu->type == CU_BEZIER) {
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
int tree_index = 0;
|
||||
|
||||
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
||||
if ((!bezt->hide) && (bezt->f1 & SELECT)) {
|
||||
|
||||
switch (type) {
|
||||
case SIMCURHAND_RADIUS:
|
||||
{
|
||||
float radius_ref = bezt->radius;
|
||||
tree_entry[0] = radius_ref;
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_WEIGHT:
|
||||
{
|
||||
float weight_ref = bezt->weight;
|
||||
tree_entry[0] = weight_ref;
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_DIRECTION:
|
||||
{
|
||||
nurb_bezt_direction_worldspace_get(ob, nu, bezt, tree_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_kdtree_insert(r_tree, tree_index++, tree_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 * nu->pntsv, 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);
|
||||
}
|
||||
BPoint *bp;
|
||||
int i;
|
||||
int tree_index=0;
|
||||
|
||||
/* map 0-1 to radians, 'cos' for comparison */
|
||||
angle_cos = cosf(thresh * (float)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);
|
||||
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
||||
if (!bp->hide && bp->f1 & SELECT) {
|
||||
switch (type) {
|
||||
case SIMCURHAND_RADIUS:
|
||||
{
|
||||
float radius_ref = bp->radius;
|
||||
tree_entry[0] = radius_ref;
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_WEIGHT:
|
||||
{
|
||||
float weight_ref = bp->weight;
|
||||
tree_entry[0] = weight_ref;
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_DIRECTION:
|
||||
{
|
||||
nurb_bpoint_direction_worldspace_get(ob, nu, bp, tree_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_kdtree_insert(r_tree, tree_index++, tree_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
|
||||
static bool curve_nurb_select_similar_type(
|
||||
Object *ob, Nurb *nu, const int type,
|
||||
const KDTree *tree, const float thresh, const int compare)
|
||||
{
|
||||
BPoint *bp;
|
||||
int i;
|
||||
const float thresh_cos = cosf(thresh * (float)M_PI_2);
|
||||
bool changed = false;
|
||||
|
||||
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);
|
||||
if (nu->type == CU_BEZIER) {
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
|
||||
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
||||
if (!bezt->hide) {
|
||||
bool select = false;
|
||||
|
||||
switch (type) {
|
||||
case SIMCURHAND_RADIUS:
|
||||
{
|
||||
float radius_ref = bezt->radius;
|
||||
if (ED_select_similar_compare_float_tree(tree, radius_ref, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_WEIGHT:
|
||||
{
|
||||
float weight_ref = bezt->weight;
|
||||
if (ED_select_similar_compare_float_tree(tree, weight_ref, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_DIRECTION:
|
||||
{
|
||||
float dir[3];
|
||||
nurb_bezt_direction_worldspace_get(ob, nu, bezt, dir);
|
||||
KDTreeNearest nearest;
|
||||
if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
|
||||
float orient = angle_normalized_v3v3(dir, nearest.co);
|
||||
float delta = thresh_cos - fabsf(cosf(orient));
|
||||
if (ED_select_similar_compare_float(delta, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (select) {
|
||||
select_beztriple(bezt, SELECT, SELECT, VISIBLE);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
BPoint *bp;
|
||||
int i;
|
||||
|
||||
/* make relative */
|
||||
thresh *= radius_ref;
|
||||
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
||||
if (!bp->hide) {
|
||||
bool select = false;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case SIMCURHAND_RADIUS:
|
||||
{
|
||||
float radius_ref = bp->radius;
|
||||
if (ED_select_similar_compare_float_tree(tree, radius_ref, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_WEIGHT:
|
||||
{
|
||||
float weight_ref = bp->weight;
|
||||
if (ED_select_similar_compare_float_tree(tree, weight_ref, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_DIRECTION:
|
||||
{
|
||||
float dir[3];
|
||||
nurb_bpoint_direction_worldspace_get(ob, nu, bp, dir);
|
||||
KDTreeNearest nearest;
|
||||
if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
|
||||
float orient = angle_normalized_v3v3(dir, nearest.co);
|
||||
float delta = fabsf(cosf(orient)) - thresh_cos;
|
||||
if (ED_select_similar_compare_float(delta, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (select) {
|
||||
select_bpoint(bp, SELECT, SELECT, VISIBLE);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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) {
|
||||
ED_curve_nurb_select_all(nu);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return changed;
|
||||
}
|
||||
|
||||
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");
|
||||
/* Get props. */
|
||||
const int optype = 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;
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
int tot_nurbs_selected_all = 0;
|
||||
uint objects_len = 0;
|
||||
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
Curve *cu = obedit->data;
|
||||
tot_nurbs_selected_all += ED_curve_select_count(v3d, cu->editnurb);
|
||||
}
|
||||
|
||||
if (tot_nurbs_selected_all == 0) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No control point selected");
|
||||
MEM_freeN(objects);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
KDTree *tree = NULL;
|
||||
short type_ref = 0;
|
||||
|
||||
switch (optype) {
|
||||
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);
|
||||
tree = BLI_kdtree_new(tot_nurbs_selected_all);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
||||
return OPERATOR_FINISHED;
|
||||
/* Get type of selected control points. */
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
Curve *cu = obedit->data;
|
||||
EditNurb *editnurb = cu->editnurb;
|
||||
|
||||
Nurb *nu;
|
||||
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
||||
if (!ED_curve_nurb_select_check(v3d, nu)) {
|
||||
continue;
|
||||
}
|
||||
switch (optype) {
|
||||
case SIMCURHAND_TYPE:
|
||||
{
|
||||
type_ref |= nu->type;
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_RADIUS:
|
||||
case SIMCURHAND_WEIGHT:
|
||||
case SIMCURHAND_DIRECTION:
|
||||
curve_nurb_selected_type_get(obedit, nu, optype, tree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if (tree != NULL) {
|
||||
BLI_kdtree_balance(tree);
|
||||
}
|
||||
|
||||
/* Select control points with desired type. */
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
Curve *cu = obedit->data;
|
||||
EditNurb *editnurb = cu->editnurb;
|
||||
bool changed = false;
|
||||
Nurb *nu;
|
||||
|
||||
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
||||
switch (optype) {
|
||||
case SIMCURHAND_TYPE:
|
||||
{
|
||||
if (nu->type & type_ref) {
|
||||
ED_curve_nurb_select_all(nu);
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCURHAND_RADIUS:
|
||||
case SIMCURHAND_WEIGHT:
|
||||
case SIMCURHAND_DIRECTION:
|
||||
changed = curve_nurb_select_similar_type(obedit, nu, optype, tree, thresh, compare);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(objects);
|
||||
if (tree != NULL) {
|
||||
BLI_kdtree_free(tree);
|
||||
}
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
}
|
||||
|
||||
void CURVE_OT_select_similar(wmOperatorType *ot)
|
||||
|
|
|
@ -74,6 +74,7 @@ void ED_curve_deselect_all(struct EditNurb *editnurb);
|
|||
void ED_curve_deselect_all_multi(struct Object **objects, int objects_len);
|
||||
void ED_curve_select_all(struct EditNurb *editnurb);
|
||||
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
|
||||
int ED_curve_select_count(struct View3D *v3d, struct EditNurb *editnurb);
|
||||
|
||||
/* editcurve_undo.c */
|
||||
void ED_curve_undosys_type(struct UndoType *ut);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef __ED_SELECT_UTILS_H__
|
||||
#define __ED_SELECT_UTILS_H__
|
||||
|
||||
struct KDTree;
|
||||
|
||||
enum {
|
||||
SEL_TOGGLE = 0,
|
||||
SEL_SELECT = 1,
|
||||
|
@ -41,6 +43,13 @@ typedef enum {
|
|||
SEL_OP_XOR,
|
||||
} eSelectOp;
|
||||
|
||||
/* Select Similar */
|
||||
enum {
|
||||
SIM_CMP_EQ = 0,
|
||||
SIM_CMP_GT,
|
||||
SIM_CMP_LT
|
||||
};
|
||||
|
||||
#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND))
|
||||
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
|
||||
#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD))
|
||||
|
@ -49,4 +58,6 @@ typedef enum {
|
|||
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
|
||||
int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside);
|
||||
|
||||
int ED_select_similar_compare_float(const float delta, const float thresh, const int compare);
|
||||
bool ED_select_similar_compare_float_tree(const struct KDTree *tree, const float length, const float thresh, const int compare);
|
||||
#endif /* __ED_SELECT_UTILS_H__ */
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
|
||||
#include "mesh_intern.h" /* own include */
|
||||
|
||||
|
@ -58,12 +59,6 @@
|
|||
/** \name Select Similar (Vert/Edge/Face) Operator - common
|
||||
* \{ */
|
||||
|
||||
enum {
|
||||
SIM_CMP_EQ = 0,
|
||||
SIM_CMP_GT,
|
||||
SIM_CMP_LT
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_similar_compare_types[] = {
|
||||
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
|
||||
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
|
||||
|
@ -105,21 +100,6 @@ static const EnumPropertyItem prop_similar_types[] = {
|
|||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static int mesh_select_similar_compare_float(const float delta, const float thresh, const int compare)
|
||||
{
|
||||
switch (compare) {
|
||||
case SIM_CMP_EQ:
|
||||
return (fabsf(delta) < thresh + FLT_EPSILON);
|
||||
case SIM_CMP_GT:
|
||||
return ((delta + thresh) > -FLT_EPSILON);
|
||||
case SIM_CMP_LT:
|
||||
return ((delta - thresh) < FLT_EPSILON);
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int mesh_select_similar_compare_int(const int delta, const int compare)
|
||||
{
|
||||
switch (compare) {
|
||||
|
@ -135,42 +115,6 @@ static int mesh_select_similar_compare_int(const int delta, const int compare)
|
|||
}
|
||||
}
|
||||
|
||||
static bool mesh_select_similar_compare_float_tree(const KDTree *tree, const float length, const float thresh, const int compare)
|
||||
{
|
||||
/* Length of the edge we want to compare against. */
|
||||
float nearest_edge_length;
|
||||
|
||||
switch (compare) {
|
||||
case SIM_CMP_EQ:
|
||||
/* Compare to the edge closest to the current edge. */
|
||||
nearest_edge_length = length;
|
||||
break;
|
||||
case SIM_CMP_GT:
|
||||
/* Compare against the shortest edge. */
|
||||
/* -FLT_MAX leads to some precision issues and the wrong edge being selected.
|
||||
* For example, in a tree with 1, 2 and 3, which is stored squared as 1, 4, 9, it returns as the nearest
|
||||
* length/node the "4" instead of "1". */
|
||||
nearest_edge_length = -1.0f;
|
||||
break;
|
||||
case SIM_CMP_LT:
|
||||
/* Compare against the longest edge. */
|
||||
nearest_edge_length = FLT_MAX;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
KDTreeNearest nearest;
|
||||
float dummy[3] = {nearest_edge_length, 0.0f, 0.0f};
|
||||
if (BLI_kdtree_find_nearest(tree, dummy, &nearest) != -1) {
|
||||
float delta = length - nearest.co[0];
|
||||
return mesh_select_similar_compare_float(delta, thresh, compare);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -497,7 +441,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
|
|||
case SIMFACE_AREA:
|
||||
{
|
||||
float area = BM_face_calc_area(face);
|
||||
if (mesh_select_similar_compare_float_tree(tree, area, thresh, compare)) {
|
||||
if (ED_select_similar_compare_float_tree(tree, area, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
|
@ -505,7 +449,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
|
|||
case SIMFACE_PERIMETER:
|
||||
{
|
||||
float perimeter = BM_face_calc_perimeter(face);
|
||||
if (mesh_select_similar_compare_float_tree(tree, perimeter, thresh, compare)) {
|
||||
if (ED_select_similar_compare_float_tree(tree, perimeter, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
|
@ -904,7 +848,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
/* Proceed only if we have to select all the edges that have custom data value of 0.0f.
|
||||
* In this case we will just select all the edges.
|
||||
* Otherwise continue the for loop. */
|
||||
if (!mesh_select_similar_compare_float_tree(tree, 0.0f, thresh, compare)) {
|
||||
if (!ED_select_similar_compare_float_tree(tree, 0.0f, thresh, compare)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -952,7 +896,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
case SIMEDGE_LENGTH:
|
||||
{
|
||||
float length = edge_length_squared_worldspace_get(ob, edge);
|
||||
if (mesh_select_similar_compare_float_tree(tree, length, thresh, compare)) {
|
||||
if (ED_select_similar_compare_float_tree(tree, length, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
|
@ -961,7 +905,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
if (BM_edge_face_count_at_most(edge, 2) == 2) {
|
||||
float angle = BM_edge_calc_face_angle(edge);
|
||||
if (mesh_select_similar_compare_float_tree(tree, angle, thresh, SIM_CMP_EQ)) {
|
||||
if (ED_select_similar_compare_float_tree(tree, angle, thresh, SIM_CMP_EQ)) {
|
||||
select = true;
|
||||
}
|
||||
}
|
||||
|
@ -1008,7 +952,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
const float *value = CustomData_bmesh_get(&bm->edata, edge->head.data, custom_data_type);
|
||||
if (mesh_select_similar_compare_float_tree(tree, *value, thresh, compare)) {
|
||||
if (ED_select_similar_compare_float_tree(tree, *value, thresh, compare)) {
|
||||
select = true;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -23,9 +23,13 @@
|
|||
*/
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "ED_select_utils.h"
|
||||
|
||||
#include "float.h"
|
||||
|
||||
/** 1: select, 0: deselect, -1: pass. */
|
||||
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
|
||||
{
|
||||
|
@ -68,3 +72,54 @@ int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select,
|
|||
BLI_assert(!"invalid sel_op");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
|
||||
{
|
||||
switch (compare) {
|
||||
case SIM_CMP_EQ:
|
||||
return (fabsf(delta) < thresh + FLT_EPSILON);
|
||||
case SIM_CMP_GT:
|
||||
return ((delta + thresh) > -FLT_EPSILON);
|
||||
case SIM_CMP_LT:
|
||||
return ((delta - thresh) < FLT_EPSILON);
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ED_select_similar_compare_float_tree(const KDTree *tree, const float length, const float thresh, const int compare)
|
||||
{
|
||||
/* Length of the edge we want to compare against. */
|
||||
float nearest_edge_length;
|
||||
|
||||
switch (compare) {
|
||||
case SIM_CMP_EQ:
|
||||
/* Compare to the edge closest to the current edge. */
|
||||
nearest_edge_length = length;
|
||||
break;
|
||||
case SIM_CMP_GT:
|
||||
/* Compare against the shortest edge. */
|
||||
/* -FLT_MAX leads to some precision issues and the wrong edge being selected.
|
||||
* For example, in a tree with 1, 2 and 3, which is stored squared as 1, 4, 9, it returns as the nearest
|
||||
* length/node the "4" instead of "1". */
|
||||
nearest_edge_length = -1.0f;
|
||||
break;
|
||||
case SIM_CMP_LT:
|
||||
/* Compare against the longest edge. */
|
||||
nearest_edge_length = FLT_MAX;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
KDTreeNearest nearest;
|
||||
float dummy[3] = {nearest_edge_length, 0.0f, 0.0f};
|
||||
if (BLI_kdtree_find_nearest(tree, dummy, &nearest) != -1) {
|
||||
float delta = length - nearest.co[0];
|
||||
return ED_select_similar_compare_float(delta, thresh, compare);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue