Fix #125024: Bevel offset - eliminate divide by 0.
From Rob Blair's PR https://projects.blender.org/blender/blender/pulls/126309 . In the code that clamps the bevel amount, the existing code could get a denominator of 0 (from a tangent of a certain angle). This code uses a different calculation (diagram in the PR) that clamps when the projections of four specific edges onto another edge consumes the whole length of that edge.
This commit is contained in:
committed by
Howard Trickey
parent
30d606ea86
commit
dd334faa58
@@ -7545,45 +7545,78 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
|
|||||||
if (ea->e == eb->e || (ec && ec->e == eb->e)) {
|
if (ea->e == eb->e || (ec && ec->e == eb->e)) {
|
||||||
return no_collide_offset;
|
return no_collide_offset;
|
||||||
}
|
}
|
||||||
ka = ka / bp->offset;
|
|
||||||
kb = kb / bp->offset;
|
|
||||||
kc = kc / bp->offset;
|
|
||||||
float th1 = angle_v3v3v3(va->co, vb->co, vc->co);
|
float th1 = angle_v3v3v3(va->co, vb->co, vc->co);
|
||||||
float th2 = angle_v3v3v3(vb->co, vc->co, vd->co);
|
float th2 = angle_v3v3v3(vb->co, vc->co, vd->co);
|
||||||
|
|
||||||
/* First calculate offset at which edge B collapses, which happens
|
/* First calculate offset at which edge B collapses, which happens
|
||||||
* when advancing clones of A, B, C all meet at a point.
|
* when advancing clones of A, B, C all meet at a point.*/
|
||||||
* This only happens if at least two of those three edges have non-zero k's. */
|
|
||||||
float sin1 = sinf(th1);
|
float sin1 = sinf(th1);
|
||||||
float sin2 = sinf(th2);
|
float sin2 = sinf(th2);
|
||||||
if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) {
|
float cos1 = cosf(th1);
|
||||||
float tan1 = tanf(th1);
|
float cos2 = cosf(th2);
|
||||||
float tan2 = tanf(th2);
|
/*the side offsets, overlap at the two corners, to create two corner vectors.
|
||||||
float g = tan1 * tan2;
|
*the intersection of these two corner vectors is the collapse point.
|
||||||
float h = sin1 * sin2;
|
*The length of edge B divided by the projection of these vectors onto edge B
|
||||||
float den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2);
|
*is the number of 'offsets' that can be accomodated*/
|
||||||
if (den != 0.0f) {
|
float offsets_projected_on_B = (ka + cos1 * kb) / sin1 + (kc + cos2 * kb) / sin2;
|
||||||
float t = BM_edge_calc_length(eb->e);
|
if (offsets_projected_on_B > BEVEL_EPSILON) {
|
||||||
t *= g * h / den;
|
offsets_projected_on_B = bp->offset * (len_v3v3(vb->co, vc->co) / offsets_projected_on_B);
|
||||||
if (t >= 0.0f) {
|
if (offsets_projected_on_B > BEVEL_EPSILON) {
|
||||||
limit = t;
|
limit = offsets_projected_on_B;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check edge slide cases.
|
||||||
|
* where side edges are in line with edge B and are not beveled, we should continue
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
if (A_side_slide < limit) {
|
||||||
|
limit = A_side_slide;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now check edge slide cases. */
|
if (kb > FLT_EPSILON && kc == 0.0f) {
|
||||||
if (kb > 0.0f && ka == 0.0f /* `&& bvb->selcount == 1 && bvb->edgecount > 2` */) {
|
BMLoop *lc = BM_face_edge_share_loop(eb->fnext, eb->e);
|
||||||
float t = BM_edge_calc_length(ea->e);
|
if (lc) {
|
||||||
t *= sin1 / kb;
|
lc = lc->next;
|
||||||
if (t >= 0.0f && t < limit) {
|
float C_side_slide = 0.0f;
|
||||||
limit = t;
|
float exterior_angle = 0.0f;
|
||||||
}
|
bool first = true;
|
||||||
}
|
while (exterior_angle < 0.0001f) {
|
||||||
if (kb > 0.0f && kc == 0.0f /* `&& bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2` */) {
|
if (first) {
|
||||||
float t = BM_edge_calc_length(ec->e);
|
exterior_angle = (float)M_PI - th2;
|
||||||
t *= sin2 / kb;
|
first = false;
|
||||||
if (t >= 0.0f && t < limit) {
|
}
|
||||||
limit = t;
|
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);
|
||||||
|
}
|
||||||
|
if (C_side_slide < limit) {
|
||||||
|
limit = C_side_slide;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return limit;
|
return limit;
|
||||||
|
|||||||
Reference in New Issue
Block a user