diff options
author | YimingWu <xp8110@outlook.com> | 2022-05-13 19:55:18 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2022-05-13 19:56:09 +0300 |
commit | 7c9b6cc3802982bfb7a13aed37d4a032d9166fbc (patch) | |
tree | 385f5dcd17466730448e1f0593f8dfd45eb129c1 /source | |
parent | ee363ee7b3a26e3236f2107b8a8324877404db04 (diff) |
LineArt: Better behavior of smooth tolerance.
This fixes the smooth tolerance feature in master where sometimes you could
get over simplified chains and lose the shape it's supposed to be originally.
Reviewed By: Sebastian Parborg (zeddb)
Differential Revision: https://developer.blender.org/D14929
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index b666eb677eb..d7b370ef5e5 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -971,27 +971,67 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) { LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { - LineartEdgeChainItem *next_eci; - for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) { - next_eci = eci->next; - LineartEdgeChainItem *eci2, *eci3, *eci4; - - /* Not enough point to do simplify. */ - if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) { - continue; - } - - /* No need to care for different line types/occlusion and so on, because at this stage they - * are all the same within a chain. */ - - /* If p3 is within the p1-p2 segment of a width of "tolerance". */ - if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) { - /* And if p4 is on the extension of p1-p2 , we remove p3. */ - if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) { - BLI_remlink(&ec->chain, eci3); - next_eci = eci; + /* Go through the chain two times, once from each direction. */ + for (int times = 0; times < 2; times++) { + for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci; + eci = next_eci) { + LineartEdgeChainItem *eci2, *eci3, *eci4; + + if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) { + /* Not enough points to simplify. */ + next_eci = eci->next; + continue; } + /* No need to care for different line types/occlusion and so on, because at this stage they + * are all the same within a chain. + * + * We need to simplify a chain from this: + * 1-----------2 + * 3-----------4 + * to this: + * 1-----------2--_ + * `--4 */ + + /* If p3 is within the p1-p2 segment of a width of "tolerance", in other words, p3 is + * approximately on the segment of p1-p2. */ + if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) { + float vec2[2], vec3[2], v2n[2], ratio, len2; + sub_v2_v2v2(vec2, eci2->pos, eci->pos); + sub_v2_v2v2(vec3, eci3->pos, eci->pos); + normalize_v2_v2(v2n, vec2); + ratio = dot_v2v2(v2n, vec3); + len2 = len_v2(vec2); + /* Because this smoothing applies on geometries of different scales in the same scene, + * some small scale features (e.g. the "tails" on the inner ring of a torus geometry) + * could be completely erased if the tolerance value is set for accomondating the entire + * scene. Those situations typically result in (ratio << 0), looks like this: + * 1---2 + * 3-------------------------------4 + * (this sort of long zig zag obviously are "features" that can't be erased) + * setting a ratio of -10 turned out to be a reasonabe threshold in tests. */ + if (ratio < len2 && ratio > -len2 * 10) { + /* We only remove p3 if p4 is on the extension of p1->p2. */ + if ((eci4 = eci3->next) && + (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) { + BLI_remlink(&ec->chain, eci3); + next_eci = eci; + continue; + } + if (!eci4) { + /* See if the last segment's direction is reversed, if so remove that. + * Basically we don't need to preserve p3 if the entire chain looked like this: + * ...----1----3===2 */ + if (len_v2(vec2) > len_v2(vec3)) { + BLI_remlink(&ec->chain, eci3); + } + next_eci = NULL; + continue; + } + } + } + next_eci = eci->next; } + BLI_listbase_reverse(&ec->chain); } } } |