Fix #140396: bmesh.ops.dissolve_edges fails to dissolve vertices

Support flagging BMesh operator slots as being used so it's possible
to use a non-zero fallback value for the edge-dissolve angle threshold.
This commit is contained in:
Campbell Barton
2025-06-15 17:17:27 +10:00
parent 074fcfe1a5
commit bd3a66a416
3 changed files with 55 additions and 6 deletions

View File

@@ -12,6 +12,7 @@
#include "BLI_utildefines.h"
#include <cstdarg>
#include <optional>
#include "bmesh_class.hh"
@@ -239,6 +240,15 @@ union eBMOpSlotSubType_Union {
eBMOpSlotSubType_Int intg;
};
enum eBMOpSlotFlag : uint8_t {
/**
* This flag is set when the operators value has been set.
* Use this so it's possible to have non-zero defaults for properties.
*/
BMO_OP_SLOT_FLAG_IS_SET = (1 << 0),
};
ENUM_OPERATORS(eBMOpSlotFlag, BMO_OP_SLOT_FLAG_IS_SET)
struct BMO_FlagSet {
int value;
const char *identifier;
@@ -252,8 +262,8 @@ struct BMOpSlot {
eBMOpSlotType slot_type;
eBMOpSlotSubType_Union slot_subtype;
eBMOpSlotFlag flag;
int len;
// int flag; /* UNUSED */
// int index; /* index within slot array */ /* UNUSED */
union {
int i;
@@ -549,10 +559,16 @@ void BMO_op_flag_disable(BMesh *bm, BMOperator *op, int op_flag);
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f);
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<float> BMO_slot_float_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i);
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<int> BMO_slot_int_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i);
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<bool> BMO_slot_bool_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
/**
* Return a copy of the element buffer.
*/

View File

@@ -295,6 +295,8 @@ void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
else {
slot_dst->data = slot_src->data;
}
slot_dst->flag = slot_src->flag;
}
/*
@@ -312,6 +314,7 @@ void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_n
}
slot->data.f = f;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
@@ -323,6 +326,7 @@ void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
}
slot->data.i = i;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
@@ -334,6 +338,7 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
}
slot->data.i = i;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
void BMO_slot_mat_set(BMOperator *op,
@@ -362,6 +367,7 @@ void BMO_slot_mat_set(BMOperator *op,
zero_m4(static_cast<float(*)[4]>(slot->data.p));
}
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -409,6 +415,7 @@ void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
}
slot->data.p = p;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -422,31 +429,51 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
}
copy_v3_v3(slot->data.vec, vec);
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
}
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_float_get_optional(slot_args, slot_name).value_or(0.0f);
}
std::optional<float> BMO_slot_float_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
if (!(slot->slot_type == BMO_OP_SLOT_FLT)) {
return 0.0f;
return std::nullopt;
}
if ((slot->flag & BMO_OP_SLOT_FLAG_IS_SET) == 0) {
return std::nullopt;
}
return slot->data.f;
}
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
std::optional<int> BMO_slot_int_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
if (!(slot->slot_type == BMO_OP_SLOT_INT)) {
return 0;
return std::nullopt;
}
if ((slot->flag & BMO_OP_SLOT_FLAG_IS_SET) == 0) {
return std::nullopt;
}
return slot->data.i;
}
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_int_get_optional(slot_args, slot_name).value_or(0);
}
std::optional<bool> BMO_slot_bool_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
@@ -456,6 +483,10 @@ bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
return slot->data.i;
}
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_bool_get_optional(slot_args, slot_name).value_or(false);
}
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
{

View File

@@ -387,7 +387,9 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
* This lets the test ignore that tiny bit of math error so users won't notice. */
const float angle_epsilon = RAD2DEGF(0.0001f);
const float angle_threshold = BMO_slot_float_get(op->slots_in, "angle_threshold");
/* When unset, don't limit dissolving vertices at all. */
const float angle_threshold =
BMO_slot_float_get_optional(op->slots_in, "angle_threshold").value_or(M_PI);
/* Use verts when told to... except, do *not* use verts when angle_threshold is 0.0. */
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts") &&