Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c')
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c78
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..28fd8ff01b9 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 accommodating the entire
+ * scene. Those situations typically result in (ratio << 0), looks like this:
+ * 1---2
+ * 3-------------------------------4
+ * (this sort of long zigzag obviously are "features" that can't be erased)
+ * setting a ratio of -10 turned out to be a reasonable 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);
}
}
}