Skip to content

Commit

Permalink
Introduce test scenes that demonstrates conflation artifacts
Browse files Browse the repository at this point in the history
Added two scenes that demonstrate conflation artifacts as described in
linebender#49. The first scene
demonstrates adjacent triangles and rects that belong to the same path
and use opposite winding.

The second scene demonstrates strokes with overlapping square caps
(these strokes are currently expressed as rects painted with the NonZero
fill rule).
  • Loading branch information
armansito committed Feb 3, 2023
1 parent 9721d4a commit 827e839
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 1 deletion.
4 changes: 3 additions & 1 deletion examples/with_winit/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async fn run(event_loop: EventLoop<UserEvent>, window: Window, args: Args) {
let device_handle = &render_cx.devices[surface.dev_id];
let mut builder = SceneBuilder::for_scene(&mut scene);

const N_SCENES: i32 = 6;
const N_SCENES: i32 = 8;
// Allow looping forever
scene_ix = scene_ix.rem_euclid(N_SCENES);
// Remainder operation allows negative results, which isn't the right semantics
Expand All @@ -181,6 +181,8 @@ async fn run(event_loop: EventLoop<UserEvent>, window: Window, args: Args) {
3 => test_scene::render_brush_transform(&mut builder, current_frame),
4 => test_scene::render_funky_paths(&mut builder),
5 => test_scene::render_scene(&mut builder),
6 => test_scene::render_conflation_test(&mut builder),
7 => test_scene::render_labyrinth(&mut builder),
_ => unreachable!("N_SCENES is too large"),
}
builder.finish();
Expand Down
145 changes: 145 additions & 0 deletions examples/with_winit/src/test_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,151 @@ pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize)
);
}

pub fn render_conflation_test(sb: &mut SceneBuilder) {
use PathEl::*;
const N: f64 = 50.0;
const S: f64 = 4.0;

let scale = Affine::scale(S);
let mut y = N;

// Two adjacent triangles touching at diagonal edge with opposing winding numbers
sb.fill(
Fill::NonZero,
Affine::translate((N, y)) * scale,
Color::RED,
None,
&[
MoveTo((0.0, 0.0).into()), LineTo((N, N).into()),
LineTo((0.0, N).into()), LineTo((0.0, 0.0).into()),

MoveTo((0.0, 0.0).into()), LineTo((N, N).into()),
LineTo((N, 0.0).into()), LineTo((0.0, 0.0).into()),
]
);

// Adjacent rects, opposite winding, non-axis-aligned seam
y += S * N + 10.0;
sb.fill(
Fill::EvenOdd,
Affine::translate((N, y)) * scale,
Color::RED,
None,
&Rect::new(0.0, 0.0, N, N),
);
sb.fill(
Fill::EvenOdd,
Affine::translate((N, y)) * scale,
Color::GREEN,
None,
&[
MoveTo((0.0, 0.0).into()), LineTo((0.0, N).into()),
LineTo((N * 0.5 - 0.1, N).into()), LineTo((N * 0.5, 0.0).into()),

MoveTo((N * 0.5, 0.0).into()), LineTo((N, 0.0).into()),
LineTo((N, N).into()), LineTo((N * 0.5 - 0.1, N).into()),
]
);

// Adjacent rects, same winding, non-axis-aligned seam
y += S * N + 10.0;
sb.fill(
Fill::EvenOdd,
Affine::translate((N, y)) * scale,
Color::RED,
None,
&Rect::new(0.0, 0.0, N, N),
);
sb.fill(
Fill::EvenOdd,
Affine::translate((N, y)) * scale,
Color::GREEN,
None,
&[
MoveTo((0.0, 0.0).into()), LineTo((0.0, N).into()),
LineTo((N * 0.5 - 0.1, N).into()), LineTo((N * 0.5, 0.0).into()),

MoveTo((N * 0.5, 0.0).into()), LineTo((N * 0.5 - 0.1, N).into()),
LineTo((N, N).into()), LineTo((N, 0.0).into()),
]
);
}

pub fn render_labyrinth(sb: &mut SceneBuilder) {
use PathEl::*;

let rows: &[[u8; 12]] = &[
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1],
[1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
[1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1],
[0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
let cols: &[[u8; 10]] = &[
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
[0, 0, 1, 0, 0, 0, 1, 1, 1, 0],
[0, 1, 1, 0, 1, 1, 1, 0, 0, 1],
[1, 1, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 1],
[0, 0, 1, 1, 1, 0, 0, 0, 1, 0],
[0, 1, 0, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
[1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 1, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
];
let mut path = BezPath::new();
for (y, row) in rows.iter().enumerate() {
for (x, flag) in row.iter().enumerate() {
let x = x as f64;
let y = y as f64;
if *flag == 1 {
path.push(MoveTo((x - 0.1, y + 0.1).into()));
path.push(LineTo((x + 1.1, y + 0.1).into()));
path.push(LineTo((x + 1.1, y - 0.1).into()));
path.push(LineTo((x - 0.1, y - 0.1).into()));

// The above is equivalent to the following stroke with width 0.2 and square
// caps.
//path.push(MoveTo((x, y).into()));
//path.push(LineTo((x + 1.0, y).into()));
}
}
}
for (x, col) in cols.iter().enumerate() {
for (y, flag) in col.iter().enumerate() {
let x = x as f64;
let y = y as f64;
if *flag == 1 {
path.push(MoveTo((x - 0.1, y - 0.1).into()));
path.push(LineTo((x - 0.1, y + 1.1).into()));
path.push(LineTo((x + 0.1, y + 1.1).into()));
path.push(LineTo((x + 0.1, y - 0.1).into()));
// The above is equivalent to the following stroke with width 0.2 and square
// caps.
//path.push(MoveTo((x, y).into()));
//path.push(LineTo((x, y + 1.0).into()));
}
}
}

sb.fill(
Fill::NonZero,
Affine::translate((10.5, 10.5)) * Affine::scale(80.0),
Color::rgba8(0x70, 0x80, 0x80, 0xff),
None,
&path,
)
}

#[allow(unused)]
pub fn render_brush_transform(sb: &mut SceneBuilder, i: usize) {
let th = (std::f64::consts::PI / 180.0) * (i as f64);
Expand Down

0 comments on commit 827e839

Please sign in to comment.