Fix #139664: bevel weight is now used for offset collisions #140436.

Problem - offset collision check for bevels did not consider the reduced
offset when using bevel edge weights, thus greatly reducing the allowed offset.
Solution - calculate the offset check using the weighted value and not
the full offset.
Alternatives - Since this error was introduced in the patch dd334faa58
a solution would be to revert the patch. This is not optimum since the
patch did correct the inf/inf condition in the offset calculation (ex at
90 degs, tan is 1/0).
Limitations - This patch is a correction to return the bevel function to
it's previous abilities. Further work is needed to properly handle edge
offset interference when looking at n-gons with reflex angles. There are
also situations where the bevel operation exceeds the checked offset distance
(exs. inner arc spread and bevel profiles that are not normal to the bevelled edge).
This commit is contained in:
Rob Blair
2025-06-23 21:15:48 -04:00
committed by Howard Trickey
parent 7274fdb377
commit 379fffaf0d

View File

@@ -19,6 +19,7 @@
#include "BLI_alloca.h"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_math_base_safe.h"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
@@ -7700,7 +7701,8 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
* The intersection of these two corner vectors is the collapse point.
* The length of edge B divided by the projection of these vectors onto edge B
* is the number of 'offsets' that can be accommodated. */
float offsets_projected_on_B = (ka + cos1 * kb) / sin1 + (kc + cos2 * kb) / sin2;
float offsets_projected_on_B = safe_divide(ka + cos1 * kb, sin1) +
safe_divide(kc + cos2 * kb, sin2);
if (offsets_projected_on_B > BEVEL_EPSILON) {
offsets_projected_on_B = bp->offset * (len_v3v3(vb->co, vc->co) / offsets_projected_on_B);
if (offsets_projected_on_B > BEVEL_EPSILON) {
@@ -7713,48 +7715,54 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
* iterating until we find a return edge (not in line with B) to provide a minimum offset
* to the far side of the N-gon. This is not perfect, but is simpler and will catch many
* more overlap issues. */
if (ka == 0.0f && kb > FLT_EPSILON) {
BMLoop *la = BM_face_edge_share_loop(eb->fnext, ea->e);
if (la) {
float A_side_slide = 0.0f;
float exterior_angle = 0.0f;
bool first = true;
while (exterior_angle < 0.0001f) {
if (first) {
exterior_angle = float(M_PI) - th1;
first = false;
}
else {
la = la->prev;
exterior_angle += float(M_PI) -
angle_v3v3v3(la->v->co, la->next->v->co, la->next->next->v->co);
}
A_side_slide += BM_edge_calc_length(la->e) * sinf(exterior_angle);
}
limit = std::min(A_side_slide, limit);
}
}
if (kb > FLT_EPSILON && (ka == 0.0f || kc == 0.0f)) {
// use bevel weight offsets and not the full offset where weights are used
kb = bp->offset / kb;
if (kb > FLT_EPSILON && kc == 0.0f) {
BMLoop *lc = BM_face_edge_share_loop(eb->fnext, eb->e);
if (lc) {
lc = lc->next;
float C_side_slide = 0.0f;
float exterior_angle = 0.0f;
bool first = true;
while (exterior_angle < 0.0001f) {
if (first) {
exterior_angle = float(M_PI) - th2;
first = false;
if (ka == 0.0f) {
BMLoop *la = BM_face_edge_share_loop(eb->fnext, ea->e);
if (la) {
float A_side_slide = 0.0f;
float exterior_angle = 0.0f;
bool first = true;
while (exterior_angle < 0.0001f) {
if (first) {
exterior_angle = float(M_PI) - th1;
first = false;
}
else {
la = la->prev;
exterior_angle += float(M_PI) -
angle_v3v3v3(la->v->co, la->next->v->co, la->next->next->v->co);
}
A_side_slide += BM_edge_calc_length(la->e) * sinf(exterior_angle);
}
else {
lc = lc->next;
exterior_angle += float(M_PI) -
angle_v3v3v3(lc->prev->v->co, lc->v->co, lc->next->v->co);
}
C_side_slide += BM_edge_calc_length(lc->e) * sinf(exterior_angle);
limit = std::min(A_side_slide * kb, limit);
}
}
if (kc == 0.0f) {
BMLoop *lc = BM_face_edge_share_loop(eb->fnext, eb->e);
if (lc) {
lc = lc->next;
float C_side_slide = 0.0f;
float exterior_angle = 0.0f;
bool first = true;
while (exterior_angle < 0.0001f) {
if (first) {
exterior_angle = float(M_PI) - th2;
first = false;
}
else {
lc = lc->next;
exterior_angle += float(M_PI) -
angle_v3v3v3(lc->prev->v->co, lc->v->co, lc->next->v->co);
}
C_side_slide += BM_edge_calc_length(lc->e) * sinf(exterior_angle);
}
limit = std::min(C_side_slide * kb, limit);
}
limit = std::min(C_side_slide, limit);
}
}
return limit;