UI: Improved "Area Close" Neighbor Selection

The new "Close Area" operator can let any neighbor replace the area to
be closed. This patch improves the selection of the best, and most-
aligned, neighbor.  It maximizes the ratio of the shared edge lengths,
rather than minimize the absolute amount of misalignment. This follows
our expectations closer because it takes into account the relative
sizes of the areas and their edges.

see D11143 for details and examples.

Differential Revision: https://developer.blender.org/D11143

Reviewed by Campbell Barton
This commit is contained in:
Harley Acheson 2021-05-12 16:52:43 -07:00
parent fa472d46fc
commit 06e62adfb8
Notes: blender-bot 2023-02-14 03:34:17 +01:00
Referenced by issue #89168, Blender cycles x - viewport denoise is showing weird effects on-screen
Referenced by issue #88219, Regression: Massive drops in Animation playback (fps) in the viewport
1 changed files with 17 additions and 22 deletions

View File

@ -534,7 +534,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
return screen_area_join_ex(C, screen, sa1, sa2, false);
}
/* Close a screen area, allowing any neighbor to take its place. */
/* Close a screen area, allowing most-aligned neighbor to take its place. */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
{
if (area == NULL) {
@ -542,32 +542,27 @@ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
}
ScrArea *sa2 = NULL;
float best_alignment = 0.0f;
/* Find the most-aligned joinable area. Larger size breaks ties. */
int min_alignment = INT_MAX;
int max_size = 0;
LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
int dir = area_getorientation(area, ar);
if (dir != -1) {
int offset1;
int offset2;
area_getoffsets(area, ar, dir, &offset1, &offset2);
int area_alignment = abs(offset1) + abs(offset2);
if (area_alignment < min_alignment) {
min_alignment = area_alignment;
max_size = ar->winx * ar->winy;
sa2 = ar;
}
else if (area_alignment == min_alignment) {
int area_size = ar->winx * ar->winy;
if (area_size > max_size) {
max_size = area_size;
sa2 = ar;
}
LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) {
int dir = area_getorientation(area, neighbor);
/* Must at least partially share an edge and not be a global area. */
if (dir != -1 && !neighbor->global) {
/* Winx/Winy might not be updated yet, so get lengths from verts. */
int area_length = ELEM(dir, 1, 3) ? area->v3->vec.x - area->v1->vec.x :
area->v3->vec.y - area->v1->vec.y;
int ar_length = ELEM(dir, 1, 3) ? neighbor->v3->vec.x - neighbor->v1->vec.x :
neighbor->v3->vec.y - neighbor->v1->vec.y;
/* Calculate the ratio of the lengths of the shared edges. */
float alignment = MIN2(area_length, ar_length) / (float)MAX2(area_length, ar_length);
if (alignment > best_alignment) {
best_alignment = alignment;
sa2 = neighbor;
}
}
}
/* Join from neighbor into this area to close it. */
return screen_area_join_ex(C, screen, sa2, area, true);
}