Fix T86753: Connected Proportional editing with individual origins using different orientation than set

The problem happened when the selection only allowed "single_islands"
(only vertices are selected, no edges or faces).

The result of `is_zero_v3(v->no)` was erroneously being compared to `0.0f`

This commit corrects the wrong condition and optimizes it by adding a
earlier return when the islands don't need to be calculated.

(It also improves the code's readability by joining some variables in the
`struct TransIslandData`).
This commit is contained in:
Germano Cavalcante 2021-03-23 15:32:48 -03:00
parent 3a68dcb1e6
commit 3ea1779365
Notes: blender-bot 2023-02-14 05:37:19 +01:00
Referenced by issue #86895, Crash! (2.83—2.93): bpy.ops.curve.select_all(action='INVERT')
Referenced by issue #86863, Edit mode: Fill region operator wrong behavior.
Referenced by issue #86871, Crash with to_mesh() on tapered bezier curve
Referenced by issue #86753, Edit Transform Vertex or Face with mouse in Normal Orientation is inconsistent with visual Gizmo under certain conditions.
1 changed files with 112 additions and 107 deletions

View File

@ -60,127 +60,133 @@ void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
const bool calc_island_axismtx,
struct TransIslandData *r_island_data)
{
struct TransIslandData data = {NULL};
BMesh *bm = em->bm;
char htype;
char itype;
int i;
/* group vars */
float(*center)[3] = NULL;
float(*axismtx)[3][3] = NULL;
int *groups_array;
int(*group_index)[2];
int group_tot;
void **ele_array;
int *groups_array = NULL;
int(*group_index)[2] = NULL;
int *vert_map;
if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
group_tot = BM_mesh_calc_edge_groups(
bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
htype = BM_EDGE;
itype = BM_VERTS_OF_EDGE;
}
else { /* (bm->selectmode & SCE_SELECT_FACE) */
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
group_tot = BM_mesh_calc_face_groups(
bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
htype = BM_FACE;
itype = BM_VERTS_OF_FACE;
bool has_only_single_islands = bm->totedgesel == 0 && bm->totfacesel == 0;
if (has_only_single_islands && !calc_single_islands) {
return;
}
if (calc_island_center) {
center = MEM_mallocN(sizeof(*center) * group_tot, __func__);
}
if (calc_island_axismtx) {
axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__);
}
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
data.island_vert_map = MEM_mallocN(sizeof(*data.island_vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
* its possible we have a selected vertex that's not in a face,
* for now best not crash in that case. */
copy_vn_i(vert_map, bm->totvert, -1);
copy_vn_i(data.island_vert_map, bm->totvert, -1);
BM_mesh_elem_table_ensure(bm, htype);
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
if (!has_only_single_islands) {
if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
data.island_tot = BM_mesh_calc_edge_groups(
bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
BM_mesh_elem_index_ensure(bm, BM_VERT);
htype = BM_EDGE;
itype = BM_VERTS_OF_EDGE;
}
else { /* (bm->selectmode & SCE_SELECT_FACE) */
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
data.island_tot = BM_mesh_calc_face_groups(
bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
/* may be an edge OR a face array */
for (i = 0; i < group_tot; i++) {
BMEditSelection ese = {NULL};
htype = BM_FACE;
itype = BM_VERTS_OF_FACE;
}
const int fg_sta = group_index[i][0];
const int fg_len = group_index[i][1];
float co[3], no[3], tangent[3];
int j;
BLI_assert(data.island_tot);
if (calc_island_center) {
data.center = MEM_mallocN(sizeof(*data.center) * data.island_tot, __func__);
}
zero_v3(co);
zero_v3(no);
zero_v3(tangent);
if (calc_island_axismtx) {
data.axismtx = MEM_mallocN(sizeof(*data.axismtx) * data.island_tot, __func__);
}
ese.htype = htype;
BM_mesh_elem_table_ensure(bm, htype);
/* loop on each face or edge in this group:
* - assign r_vert_map
* - calculate (co, no)
*/
for (j = 0; j < fg_len; j++) {
ese.ele = ele_array[groups_array[fg_sta + j]];
void **ele_array;
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
if (center) {
float tmp_co[3];
BM_editselection_center(&ese, tmp_co);
add_v3_v3(co, tmp_co);
}
BM_mesh_elem_index_ensure(bm, BM_VERT);
if (axismtx) {
float tmp_no[3], tmp_tangent[3];
BM_editselection_normal(&ese, tmp_no);
BM_editselection_plane(&ese, tmp_tangent);
add_v3_v3(no, tmp_no);
add_v3_v3(tangent, tmp_tangent);
}
/* may be an edge OR a face array */
for (i = 0; i < data.island_tot; i++) {
BMEditSelection ese = {NULL};
{
/* setup vertex map */
BMIter iter;
BMVert *v;
const int fg_sta = group_index[i][0];
const int fg_len = group_index[i][1];
float co[3], no[3], tangent[3];
int j;
/* connected edge-verts */
BM_ITER_ELEM (v, &iter, ese.ele, itype) {
vert_map[BM_elem_index_get(v)] = i;
zero_v3(co);
zero_v3(no);
zero_v3(tangent);
ese.htype = htype;
/* loop on each face or edge in this group:
* - assign r_vert_map
* - calculate (co, no)
*/
for (j = 0; j < fg_len; j++) {
ese.ele = ele_array[groups_array[fg_sta + j]];
if (data.center) {
float tmp_co[3];
BM_editselection_center(&ese, tmp_co);
add_v3_v3(co, tmp_co);
}
if (data.axismtx) {
float tmp_no[3], tmp_tangent[3];
BM_editselection_normal(&ese, tmp_no);
BM_editselection_plane(&ese, tmp_tangent);
add_v3_v3(no, tmp_no);
add_v3_v3(tangent, tmp_tangent);
}
{
/* setup vertex map */
BMIter iter;
BMVert *v;
/* connected edge-verts */
BM_ITER_ELEM (v, &iter, ese.ele, itype) {
data.island_vert_map[BM_elem_index_get(v)] = i;
}
}
}
}
if (center) {
mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len);
}
if (axismtx) {
if (createSpaceNormalTangent(axismtx[i], no, tangent)) {
/* pass */
if (data.center) {
mul_v3_v3fl(data.center[i], co, 1.0f / (float)fg_len);
}
else {
if (normalize_v3(no) != 0.0f) {
axis_dominant_v3_to_m3(axismtx[i], no);
invert_m3(axismtx[i]);
if (data.axismtx) {
if (createSpaceNormalTangent(data.axismtx[i], no, tangent)) {
/* pass */
}
else {
unit_m3(axismtx[i]);
if (normalize_v3(no) != 0.0f) {
axis_dominant_v3_to_m3(data.axismtx[i], no);
invert_m3(data.axismtx[i]);
}
else {
unit_m3(data.axismtx[i]);
}
}
}
}
}
MEM_freeN(groups_array);
MEM_freeN(group_index);
MEM_freeN(groups_array);
MEM_freeN(group_index);
}
/* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
if (calc_single_islands) {
@ -189,45 +195,44 @@ void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
int group_tot_single = 0;
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (data.island_vert_map[i] == -1)) {
group_tot_single += 1;
}
}
if (group_tot_single != 0) {
if (center) {
center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single));
if (calc_island_center) {
data.center = MEM_reallocN(data.center,
sizeof(*data.center) * (data.island_tot + group_tot_single));
}
if (axismtx) {
axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single));
if (calc_island_axismtx) {
data.axismtx = MEM_reallocN(data.axismtx,
sizeof(*data.axismtx) * (data.island_tot + group_tot_single));
}
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
vert_map[i] = group_tot;
if (center) {
copy_v3_v3(center[group_tot], v->co);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (data.island_vert_map[i] == -1)) {
data.island_vert_map[i] = data.island_tot;
if (data.center) {
copy_v3_v3(data.center[data.island_tot], v->co);
}
if (axismtx) {
if (is_zero_v3(v->no) != 0.0f) {
axis_dominant_v3_to_m3(axismtx[group_tot], v->no);
invert_m3(axismtx[group_tot]);
if (data.axismtx) {
if (is_zero_v3(v->no) == false) {
axis_dominant_v3_to_m3(data.axismtx[data.island_tot], v->no);
invert_m3(data.axismtx[data.island_tot]);
}
else {
unit_m3(axismtx[group_tot]);
unit_m3(data.axismtx[data.island_tot]);
}
}
group_tot += 1;
data.island_tot += 1;
}
}
}
}
r_island_data->axismtx = axismtx;
r_island_data->center = center;
r_island_data->island_tot = group_tot;
r_island_data->island_vert_map = vert_map;
*r_island_data = data;
}
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data)