rasterize/
rasterize.rs

1//! Rasterization logic
2//!
3//! This module include two rasterizers:
4//!   - Signed difference rasterizer
5//!   - Active-Edge rasterizer
6//!
7//! ## Signed difference rasterizer
8//! It works in two steps, first going over all lines and writing signed difference
9//! (difference value represents how to adjust winding number from one pixel to another).
10//! And on the second step it goes over all pixels and accumulates winding number, and
11//! depending on the fill rule produces alpha map of the path.
12//!
13//! Features:
14//!  - this method is fast
15//!  - requires memory equal to the size of the image
16//!
17//! ## Active-Edge-Table rasterizer
18//! This method is based on the data structure Edge-Table which keeps all lines ordered by
19//! lower y coordinate, and then scanning over all pixels line by line, once lower pixel of a
20//! line is reached line is activated and put into Active-Edge-Table, and later deactivated once
21//! once scan line covers point with the highest y coordinate.
22//!
23//! Reference: Computer graphics principles and practice (by Foley) 3.6 Filling Polygons.
24//!
25//! Features:
26//!  - this method is slower
27//!  - but requires less memory
28use crate::{
29    Color, Curve, DEFAULT_FLATNESS, EPSILON, EPSILON_SQRT, FillRule, ImageMut, ImageOwned,
30    LinColor, Line, Path, Point, Scalar, Transform,
31};
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34use std::{cmp::min, fmt, rc::Rc, sync::Arc};
35
36/// Size of the rectangular area with integer width and height
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
38pub struct Size {
39    pub width: usize,
40    pub height: usize,
41}
42
43/// Basic rasterizer interface
44pub trait Rasterizer {
45    /// Name of the rasterizer (useful for debugging)
46    fn name(&self) -> &str;
47
48    /// Rasterize provided path as mask with transformation applied, and
49    /// specified fill rule.
50    fn mask(
51        &self,
52        path: &Path,
53        tr: Transform,
54        img: &mut dyn ImageMut<Pixel = Scalar>,
55        fill_rule: FillRule,
56    );
57
58    /// Iterator over rasterized mask pixels
59    ///
60    /// This iterator should never return pixels outside of provided size region
61    fn mask_iter(
62        &self,
63        path: &Path,
64        tr: Transform,
65        size: Size,
66        fill_rule: FillRule,
67    ) -> Box<dyn Iterator<Item = Pixel> + '_>;
68
69    /// Fill path with the provided paint
70    fn fill(
71        &self,
72        path: &Path,
73        tr: Transform,
74        fill_rule: FillRule,
75        paint: &dyn Paint,
76        img: &mut dyn ImageMut<Pixel = LinColor>,
77    ) {
78        let pixels = self.mask_iter(path, tr, img.size(), fill_rule);
79        match paint.units() {
80            None => {
81                let color = paint.at(Point::new(0.0, 0.0));
82                fill_impl(pixels, img, |_| color);
83            }
84            Some(units) => {
85                let units_tr = match units {
86                    Units::UserSpaceOnUse => tr * paint.transform(),
87                    Units::BoundingBox => match path.bbox(Transform::identity()) {
88                        None => return,
89                        Some(bbox) => tr * bbox.unit_transform() * paint.transform(),
90                    },
91                };
92                if let Some(pixel_tr) = units_tr.invert() {
93                    fill_impl(pixels, img, |pixel| {
94                        let point = Point::new(pixel.x as Scalar + 0.5, pixel.y as Scalar + 0.5);
95                        paint.at(pixel_tr.apply(point))
96                    })
97                }
98            }
99        }
100    }
101}
102
103fn fill_impl(
104    pixels: impl Iterator<Item = Pixel>,
105    mut img: impl ImageMut<Pixel = LinColor>,
106    color_at: impl Fn(Pixel) -> LinColor,
107) {
108    let shape = img.shape();
109    let data = img.data_mut();
110    for pixel in pixels {
111        let dst = &mut data[shape.offset(pixel.y, pixel.x)];
112        let color = color_at(pixel);
113        *dst = dst.blend_over(color.with_alpha(pixel.alpha));
114    }
115}
116
117impl<R: Rasterizer + ?Sized> Rasterizer for &R {
118    fn mask(
119        &self,
120        path: &Path,
121        tr: Transform,
122        img: &mut dyn ImageMut<Pixel = Scalar>,
123        fill_rule: FillRule,
124    ) {
125        (**self).mask(path, tr, img, fill_rule)
126    }
127
128    fn mask_iter(
129        &self,
130        path: &Path,
131        tr: Transform,
132        size: Size,
133        fill_rule: FillRule,
134    ) -> Box<dyn Iterator<Item = Pixel> + '_> {
135        (**self).mask_iter(path, tr, size, fill_rule)
136    }
137
138    fn name(&self) -> &str {
139        (**self).name()
140    }
141}
142
143impl Rasterizer for Box<dyn Rasterizer> {
144    fn mask(
145        &self,
146        path: &Path,
147        tr: Transform,
148        img: &mut dyn ImageMut<Pixel = Scalar>,
149        fill_rule: FillRule,
150    ) {
151        (**self).mask(path, tr, img, fill_rule)
152    }
153
154    fn mask_iter(
155        &self,
156        path: &Path,
157        tr: Transform,
158        size: Size,
159        fill_rule: FillRule,
160    ) -> Box<dyn Iterator<Item = Pixel> + '_> {
161        (**self).mask_iter(path, tr, size, fill_rule)
162    }
163
164    fn name(&self) -> &str {
165        (**self).name()
166    }
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
170#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
171pub enum Units {
172    #[cfg_attr(feature = "serde", serde(rename = "userSpaceOnUse"))]
173    #[default]
174    UserSpaceOnUse,
175    #[cfg_attr(feature = "serde", serde(rename = "objectBoundingBox"))]
176    BoundingBox,
177}
178
179/// Common interface for anything that can be used to fill an area
180pub trait Paint: fmt::Debug {
181    // Get color at specified point
182    fn at(&self, point: Point) -> LinColor;
183
184    // Units used for the point passed to `Self::at` method
185    fn units(&self) -> Option<Units>;
186
187    // Additional transformation to be applied to the paint
188    fn transform(&self) -> Transform;
189
190    /// Convert paint to JSON value
191    #[cfg(feature = "serde")]
192    fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError>;
193}
194
195impl<P: Paint> Paint for &P {
196    fn at(&self, point: Point) -> LinColor {
197        (**self).at(point)
198    }
199
200    fn units(&self) -> Option<Units> {
201        (**self).units()
202    }
203
204    fn transform(&self) -> Transform {
205        (**self).transform()
206    }
207
208    #[cfg(feature = "serde")]
209    fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
210        (**self).to_json()
211    }
212}
213
214impl Paint for Box<dyn Paint> {
215    fn at(&self, point: Point) -> LinColor {
216        (**self).at(point)
217    }
218
219    fn units(&self) -> Option<Units> {
220        (**self).units()
221    }
222
223    fn transform(&self) -> Transform {
224        (**self).transform()
225    }
226
227    #[cfg(feature = "serde")]
228    fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
229        (**self).to_json()
230    }
231}
232
233impl Paint for Rc<dyn Paint> {
234    fn at(&self, point: Point) -> LinColor {
235        (**self).at(point)
236    }
237
238    fn units(&self) -> Option<Units> {
239        (**self).units()
240    }
241
242    fn transform(&self) -> Transform {
243        (**self).transform()
244    }
245
246    #[cfg(feature = "serde")]
247    fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
248        (**self).to_json()
249    }
250}
251
252impl Paint for Arc<dyn Paint> {
253    fn at(&self, point: Point) -> LinColor {
254        (**self).at(point)
255    }
256
257    fn units(&self) -> Option<Units> {
258        (**self).units()
259    }
260
261    fn transform(&self) -> Transform {
262        (**self).transform()
263    }
264
265    #[cfg(feature = "serde")]
266    fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
267        (**self).to_json()
268    }
269}
270
271pub type ArcPaint = Arc<dyn Paint + Send + Sync + 'static>;
272
273/// Signed difference based rasterizer
274#[derive(Debug, Clone)]
275pub struct SignedDifferenceRasterizer {
276    flatness: Scalar,
277}
278
279impl SignedDifferenceRasterizer {
280    pub fn new(flatness: Scalar) -> Self {
281        Self { flatness }
282    }
283}
284
285impl Default for SignedDifferenceRasterizer {
286    fn default() -> Self {
287        Self {
288            flatness: DEFAULT_FLATNESS,
289        }
290    }
291}
292
293impl Rasterizer for SignedDifferenceRasterizer {
294    fn mask(
295        &self,
296        path: &Path,
297        tr: Transform,
298        img: &mut dyn ImageMut<Pixel = Scalar>,
299        fill_rule: FillRule,
300    ) {
301        let mut img = img.as_mut();
302        for line in path.flatten(tr, self.flatness, true) {
303            signed_difference_line(&mut img, line);
304        }
305        signed_difference_to_mask(img, fill_rule);
306    }
307
308    fn mask_iter(
309        &self,
310        path: &Path,
311        tr: Transform,
312        size: Size,
313        fill_rule: FillRule,
314    ) -> Box<dyn Iterator<Item = Pixel> + '_> {
315        if size.width == 0 || size.height == 0 {
316            return Box::new(std::iter::empty());
317        }
318        let width = size.width;
319        // allocate extra column to account for anti-aliased pixels
320        let size = Size {
321            width: width + 1,
322            height: size.height,
323        };
324        let mut img = ImageOwned::new_default(size);
325        for line in path.flatten(tr, self.flatness, true) {
326            signed_difference_line(&mut img, line);
327        }
328        let mut winding = 0.0;
329        let iter =
330            img.into_vec()
331                .into_iter()
332                .enumerate()
333                .filter_map(move |(index, winding_diff)| {
334                    let y = index / size.width;
335                    let x = index - y * size.width;
336                    if x == 0 {
337                        winding = 0.0;
338                    } else if x >= width {
339                        return None;
340                    }
341                    winding += winding_diff;
342                    let alpha = fill_rule.alpha_from_winding(winding);
343                    if alpha.abs() < 1e-6 {
344                        None
345                    } else {
346                        Some(Pixel { x, y, alpha })
347                    }
348                });
349        Box::new(iter)
350    }
351
352    fn name(&self) -> &str {
353        "signed-difference"
354    }
355}
356
357/// Update provided image with the signed difference of the line
358///
359/// Signed difference is a difference between adjacent pixels introduced by the line.
360fn signed_difference_line(mut img: impl ImageMut<Pixel = Scalar>, line: Line) {
361    // y - is a row
362    // x - is a column
363    let Line([p0, p1]) = line;
364
365    // handle lines that are intersecting `x == img.width()`
366    // - just throw away part that has `x > img.width()` for all points
367    let width = img.width() as Scalar - 1.0;
368    let line = if p0.x() > width || p1.x() > width {
369        if p0.x() > width && p1.x() > width {
370            Line::new((width - 0.001, p0.y()), (width - 0.001, p1.y()))
371        } else {
372            let t = (p0.x() - width) / (p0.x() - p1.x());
373            let mid = Point::new(width, (1.0 - t) * p0.y() + t * p1.y());
374            if p0.x() < width {
375                Line::new(p0, mid)
376            } else {
377                Line::new(mid, p1)
378            }
379        }
380    } else {
381        line
382    };
383
384    // handle lines that are intersecting `x == 0.0`
385    let (line, rest) = split_at_zero_x(line);
386    if let Some(rest) = rest {
387        signed_difference_line(img.as_mut(), rest);
388    }
389
390    let Line([p0, p1]) = line;
391    let shape = img.shape();
392    let data = img.data_mut();
393    let stride = shape.col_stride;
394
395    if (p0.y() - p1.y()).abs() < EPSILON {
396        // line does not introduce any signed coverage
397        return;
398    }
399    // always iterate from the point with the smallest y coordinate
400    let (dir, p0, p1) = if p0.y() < p1.y() {
401        (1.0, p0, p1)
402    } else {
403        (-1.0, p1, p0)
404    };
405    let dxdy = (p1.x() - p0.x()) / (p1.y() - p0.y());
406    // find first point to trace. since we are going to iterate over y's
407    // we should pick min(y , p0.y) as a starting y point, and adjust x
408    // accordingly
409    let y = p0.y().max(0.0) as usize;
410    let mut x = if p0.y() < 0.0 {
411        p0.x() - p0.y() * dxdy
412    } else {
413        p0.x()
414    };
415    let mut x_next = x;
416    for y in y..min(shape.height, p1.y().ceil().max(0.0) as usize) {
417        x = x_next;
418        let row_offset = shape.offset(y, 0); // current line offset in the data array
419        let dy = ((y + 1) as Scalar).min(p1.y()) - (y as Scalar).max(p0.y());
420        // signed y difference
421        let d = dir * dy;
422        // find next x position
423        x_next = x + dxdy * dy;
424        // order (x, x_next) from smaller value x0 to bigger x1
425        let (x0, x1) = if x < x_next { (x, x_next) } else { (x_next, x) };
426        // lower bound of effected x pixels
427        let x0_floor = x0.floor().max(0.0);
428        let x0i = x0_floor as i32;
429        // upper bound of effected x pixels
430        let x1_ceil = x1.ceil().min(width);
431        let x1i = x1_ceil as i32;
432        if x1i <= x0i + 1 {
433            // only goes through one pixel (with the total coverage of `d` spread over two pixels)
434            let xmf = 0.5 * (x + x_next) - x0_floor; // effective height
435            data[row_offset + (x0i as usize) * stride] += d * (1.0 - xmf);
436            let offset = row_offset + ((x0i + 1) as usize) * stride;
437            if crate::utils::likely(offset < data.len()) {
438                data[offset] += d * xmf;
439            }
440        } else {
441            let s = (x1 - x0).recip();
442            let x0f = x0 - x0_floor; // fractional part of x0
443            let x1f = x1 - x1_ceil + 1.0; // fractional part of x1
444            let a0 = 0.5 * s * (1.0 - x0f) * (1.0 - x0f); // fractional area of the pixel with smallest x
445            let am = 0.5 * s * x1f * x1f; // fractional area of the pixel with largest x
446            data[row_offset + (x0i as usize) * stride] += d * a0;
447            if x1i == x0i + 2 {
448                // only two pixels are covered
449                data[row_offset + ((x0i + 1) as usize) * stride] += d * (1.0 - a0 - am);
450            } else {
451                // second pixel
452                let a1 = s * (1.5 - x0f);
453                data[row_offset + ((x0i + 1) as usize) * stride] += d * (a1 - a0);
454                // (second, last) pixels
455                for xi in x0i + 2..x1i - 1 {
456                    data[row_offset + (xi as usize) * stride] += d * s;
457                }
458                // last pixel
459                let a2 = a1 + (x1i - x0i - 3) as Scalar * s;
460                data[row_offset + ((x1i - 1) as usize) * stride] += d * (1.0 - a2 - am);
461            }
462            data[row_offset + (x1i as usize) * stride] += d * am
463        }
464    }
465}
466
467/// Convert signed difference image to a mask
468fn signed_difference_to_mask(mut img: impl ImageMut<Pixel = Scalar>, fill_rule: FillRule) {
469    let shape = img.shape();
470    let data = img.data_mut();
471    match fill_rule {
472        FillRule::NonZero => {
473            for y in 0..shape.height {
474                let mut acc = 0.0;
475                for x in 0..shape.width {
476                    let offset = shape.offset(y, x);
477                    acc += data[offset];
478
479                    let value = acc.abs();
480                    data[offset] = if value > 1.0 {
481                        1.0
482                    } else if value < 1e-6 {
483                        0.0
484                    } else {
485                        value
486                    };
487                }
488            }
489        }
490        FillRule::EvenOdd => {
491            for y in 0..shape.height {
492                let mut acc = 0.0;
493                for x in 0..shape.width {
494                    let offset = shape.offset(y, x);
495                    acc += data[offset];
496
497                    data[offset] = ((acc + 1.0).rem_euclid(2.0) - 1.0).abs()
498                }
499            }
500        }
501    }
502}
503
504/// Active-Edge rasterizer
505///
506/// This method is based on the data structure Edge-Table which keeps all lines ordered by
507/// lower y coordinate, and then scanning over all pixels line by line, once lower pixel of a
508/// line is reached line is activated and put into Active-Edge-Table, and later deactivated once
509/// once scan line covers point with the highest y coordinate.
510///
511/// Reference: Computer graphics principles and practice (by Foley) 3.6 Filling Polygons.
512#[derive(Debug, Clone)]
513pub struct ActiveEdgeRasterizer {
514    flatness: Scalar,
515}
516
517impl ActiveEdgeRasterizer {
518    pub fn new(flatness: Scalar) -> Self {
519        Self { flatness }
520    }
521}
522
523impl Default for ActiveEdgeRasterizer {
524    fn default() -> Self {
525        Self {
526            flatness: DEFAULT_FLATNESS,
527        }
528    }
529}
530
531impl Rasterizer for ActiveEdgeRasterizer {
532    fn mask(
533        &self,
534        path: &Path,
535        tr: Transform,
536        img: &mut dyn ImageMut<Pixel = Scalar>,
537        fill_rule: FillRule,
538    ) {
539        let shape = img.shape();
540        let data = img.data_mut();
541        for pixel in ActiveEdgeIter::new(
542            Size {
543                width: shape.width,
544                height: shape.height,
545            },
546            fill_rule,
547            path.flatten(tr, self.flatness, true),
548        ) {
549            data[shape.offset(pixel.y, pixel.x)] = pixel.alpha;
550        }
551    }
552
553    fn mask_iter(
554        &self,
555        path: &Path,
556        tr: Transform,
557        size: Size,
558        fill_rule: FillRule,
559    ) -> Box<dyn Iterator<Item = Pixel> + '_> {
560        Box::new(ActiveEdgeIter::new(
561            size,
562            fill_rule,
563            path.flatten(tr, self.flatness, true),
564        ))
565    }
566
567    fn name(&self) -> &str {
568        "active-edge"
569    }
570}
571
572/// Iterator over rasterized pixels, by active-edge rasterizer
573pub struct ActiveEdgeIter {
574    // all edges sorted by `Edge::row` in descending order
575    edge_inactive: Vec<Edge>,
576    // edge is activated when `Edge::row` is reached
577    edge_active: Vec<Edge>,
578    // row iterators are created for all active edges on
579    iters_inactive: Vec<EdgeRowIter>,
580    // accumulated iterator over all active (x >= EdgeRowIter::column) row iterators
581    iters_active: EdgeAccIter,
582    // currently accumulated winding number
583    winding: Scalar,
584    // fill rule to be used
585    fill_rule: FillRule,
586    // size of the output image
587    size: Size,
588    // current column (x - coordinate)
589    column: usize,
590    // current row (y - coordinate)
591    row: usize,
592}
593
594impl ActiveEdgeIter {
595    pub fn new(size: Size, fill_rule: FillRule, lines: impl Iterator<Item = Line>) -> Self {
596        let mut edge_inactive: Vec<Edge> = lines
597            .flat_map(|line| {
598                let (line, rest) = split_at_zero_x(line);
599                std::iter::once(line).chain(rest)
600            })
601            .filter_map(|line| {
602                let edge = Edge::new(line)?;
603                (edge.row < size.height).then_some(edge)
604            })
605            .collect();
606        edge_inactive.sort_unstable_by(|l, r| l.row.cmp(&r.row).reverse());
607        let mut this = Self {
608            edge_inactive,
609            edge_active: Default::default(),
610            iters_inactive: Default::default(),
611            iters_active: EdgeAccIter::new(),
612            winding: 0.0,
613            fill_rule,
614            size,
615            column: 0,
616            row: 0,
617        };
618        this.next_row();
619        this
620    }
621
622    /// Switch to the next row
623    fn next_row(&mut self) {
624        // clear all iterators
625        self.iters_inactive.clear();
626        self.iters_active.clear();
627
628        // create new row iterators for all active edges
629        self.edge_active.retain_mut(|edge| {
630            // split edge into row iterator and the rest part
631            if let Some((edge_rest, iter)) = edge.next_row() {
632                self.iters_inactive.push(iter);
633                *edge = edge_rest;
634                true
635            } else {
636                false
637            }
638        });
639
640        // activate new edges
641        let activate_index = self
642            .edge_inactive
643            .partition_point(|edge| edge.row > self.row);
644        self.edge_inactive
645            .drain(activate_index..)
646            .filter_map(|edge| edge.next_row())
647            .for_each(|(edge, iter)| {
648                self.iters_inactive.push(iter);
649                self.edge_active.push(edge);
650            });
651
652        // sort iterator by column
653        self.iters_inactive
654            .sort_unstable_by(|a, b| b.column.cmp(&a.column));
655    }
656}
657
658/// Rasterized pixel
659#[derive(Debug, Clone, Copy)]
660pub struct Pixel {
661    /// x-axis coordinate (horizontal coordinate/column)
662    pub x: usize,
663    /// y-axis coordinate (vertical coordinate/row)
664    pub y: usize,
665    /// alpha value of the pixel
666    pub alpha: Scalar,
667}
668
669impl Iterator for ActiveEdgeIter {
670    type Item = Pixel;
671
672    fn next(&mut self) -> Option<Self::Item> {
673        loop {
674            if self.row >= self.size.height {
675                return None;
676            }
677
678            // find activated iterators
679            while let Some(iter) = self.iters_inactive.pop() {
680                if iter.column <= self.column {
681                    self.iters_active.push(iter);
682                } else {
683                    self.iters_inactive.push(iter);
684                    break;
685                }
686            }
687
688            // progress active row iterators
689            match self.iters_active.next() {
690                Some(winding_delta) => self.winding += winding_delta,
691                None if self.winding.abs() < EPSILON_SQRT => {
692                    // skip forward to the first activated iterator
693                    match self.iters_inactive.last() {
694                        Some(iter) if iter.column < self.size.width => {
695                            self.column = iter.column;
696                        }
697                        _ => {
698                            self.column = 0;
699                            self.row += 1;
700                            self.winding = 0.0;
701                            self.next_row();
702                        }
703                    }
704                    continue;
705                }
706                None => {}
707            }
708
709            let pixel = Pixel {
710                x: self.column,
711                y: self.row,
712                alpha: self.fill_rule.alpha_from_winding(self.winding),
713            };
714
715            // update position
716            self.column += 1;
717            if self.column >= self.size.width {
718                self.column = 0;
719                self.row += 1;
720                self.winding = 0.0;
721                self.next_row();
722            }
723
724            return Some(pixel);
725        }
726    }
727}
728
729#[inline]
730fn next_ceil(value: Scalar) -> Scalar {
731    value.floor() + 1.0
732}
733
734/// Edge represents unconsumed part of the line segments
735///
736/// `Edge::line` is always directed from point with lower to higher `y` coordinate.
737#[derive(Debug, Clone, Copy)]
738struct Edge {
739    // unconsumed part of the line segment
740    line: Line,
741    // `dx/dy` slope of the edge
742    dxdy: Scalar,
743    // `dy/dx` slope of the edge, it is empty for vertical lines
744    dydx: Option<Scalar>,
745    // `1.0` if edge is going from lower to higher `y`, `-1.0` otherwise
746    dir: Scalar,
747    // first (with minimal value) row that will be effected by this edge
748    row: usize,
749}
750
751impl Edge {
752    /// Create edge from the line
753    ///
754    /// Returns constructed `Edge` and lowest row effected by it.
755    fn new(line: Line) -> Option<Self> {
756        let Line([p0, p1]) = line;
757        if (p0.y() - p1.y()).abs() < EPSILON {
758            // horizontal lines have no effect
759            return None;
760        }
761        // order from lower to higher y coordinate
762        let (dir, p0, p1) = if p0.y() <= p1.y() {
763            (1.0, p0, p1)
764        } else {
765            (-1.0, p1, p0)
766        };
767        let dx = p1.x() - p0.x();
768        let dy = p1.y() - p0.y();
769        let dxdy = dx / dy;
770        // BUG: https://github.com/rust-lang/rust-clippy/issues/9422
771        #[allow(clippy::unnecessary_lazy_evaluations)]
772        let dydx = (dxdy.abs() > EPSILON_SQRT).then(|| dy / dx);
773        // throw away part with negative `y`
774        let p0 = if p0.y() < 0.0 {
775            Point::new(p0.x() - p0.y() * dxdy, 0.0)
776        } else {
777            p0
778        };
779        Some(Self {
780            line: Line::new(p0, p1),
781            dxdy,
782            dydx,
783            dir,
784            row: p0.y().floor() as usize,
785        })
786    }
787
788    /// Split edge into row iterator and reminder of the edge not covered by
789    /// the row iterator.
790    fn next_row(&self) -> Option<(Edge, EdgeRowIter)> {
791        EdgeRowIter::new(*self)
792    }
793}
794
795/// Iterator that calculates winding difference introduced by the line
796///
797/// This iterator is activated once rasterizer reaches `EdgeRowIter::column`,
798/// and for each subsequent pixel `EdgeRowIter::next` is called, which returns
799/// winding difference introduce by the line.
800#[derive(Debug)]
801struct EdgeRowIter {
802    // line segment that will effect winding number of current
803    line: Option<Line>,
804    // difference introduced by previous pixel
805    reminder: Option<Scalar>,
806    // `dy/dx` slope of the line
807    dydx: Option<Scalar>,
808    // first effected column
809    column: usize,
810    // direction of the line
811    dir: Scalar,
812}
813
814impl EdgeRowIter {
815    fn new(mut edge: Edge) -> Option<(Edge, Self)> {
816        let Line([p0, p1]) = edge.line;
817        if p1.y() - p0.y() < EPSILON {
818            // edge is fully consumed and should be removed
819            return None;
820        }
821
822        // intersection with lower edge of the next row
823        let y_split = next_ceil(p0.y()).min(p1.y());
824        let x_split = p0.x() + edge.dxdy * (y_split - p0.y());
825        let p_split = Point::new(x_split, y_split);
826
827        // reduce the size of the edge
828        edge.line = Line::new(p_split, p1);
829
830        // direct from lower to higher x coordinate
831        let (dir, line) = if p0.x() <= p_split.x() {
832            (edge.dir, Line::new(p0, p_split))
833        } else {
834            (-edge.dir, Line::new(p_split, p0))
835        };
836
837        let iter = Self {
838            line: Some(line),
839            reminder: None,
840            dydx: edge.dydx,
841            column: line.start().x() as usize,
842            dir,
843        };
844        Some((edge, iter))
845    }
846}
847
848impl Iterator for EdgeRowIter {
849    type Item = Scalar;
850
851    fn next(&mut self) -> Option<Self::Item> {
852        if let Some(Line([p0, p1])) = self.line.take() {
853            let x_ceil = next_ceil(p0.x());
854            let x = x_ceil.min(p1.x());
855            let h = match self.dydx {
856                Some(dydx) => dydx * (x - p0.x()),
857                None => next_ceil(p0.y()).min(p1.y()) - p0.y(),
858            };
859            let y = p0.y() + h;
860            let s0 = (2.0 * x_ceil - x - p0.x()) * h / 2.0;
861            let s1 = h - s0;
862            if p1.x() > x {
863                self.line = Some(Line::new((x, y), p1));
864            }
865            let s_prev = self.reminder.replace(self.dir * s1).unwrap_or(0.0);
866            Some(self.dir * s0 + s_prev)
867        } else {
868            self.reminder.take()
869        }
870    }
871}
872
873/// Accumulator iterator
874///
875/// Sums all values returned by sub-iterators and returns it as an item.
876struct EdgeAccIter {
877    iters: Vec<EdgeRowIter>,
878}
879
880impl EdgeAccIter {
881    fn new() -> Self {
882        Self {
883            iters: Default::default(),
884        }
885    }
886
887    // push new row iterator
888    fn push(&mut self, iter: EdgeRowIter) {
889        self.iters.push(iter)
890    }
891
892    // remove all row iterator
893    fn clear(&mut self) {
894        self.iters.clear()
895    }
896}
897
898impl Iterator for EdgeAccIter {
899    type Item = Scalar;
900
901    fn next(&mut self) -> Option<Self::Item> {
902        if self.iters.is_empty() {
903            return None;
904        }
905        let mut acc = 0.0;
906        self.iters.retain_mut(|iter| match iter.next() {
907            Some(value) => {
908                acc += value;
909                true
910            }
911            None => false,
912        });
913        Some(acc)
914    }
915}
916
917/// Split line at x == 0, part with x < 0.0 is converted to vertical line with x = 0.0
918fn split_at_zero_x(line: Line) -> (Line, Option<Line>) {
919    let Line([p0, p1]) = line;
920    if p0.x() >= 0.0 && p1.x() >= 0.0 {
921        return (line, None);
922    }
923    if p0.x() <= 0.0 && p1.x() <= 0.0 {
924        return (Line::new((0.0, p0.y()), (0.0, p1.y())), None);
925    }
926    let mid = line.at(p0.x() / (p0.x() - p1.x()));
927    if p0.x() < 0.0 {
928        (Line::new(mid, p1), Some(Line::new((0.0, p0.y()), mid)))
929    } else {
930        (Line::new(p0, mid), Some(Line::new(mid, (0.0, p1.y()))))
931    }
932}
933
934#[cfg(test)]
935mod tests {
936    use super::*;
937    use crate::{Image, assert_approx_eq};
938    type Error = Box<dyn std::error::Error>;
939
940    #[test]
941    fn test_signed_difference_line() {
942        let mut img = ImageOwned::new_default(Size {
943            height: 2,
944            width: 5,
945        });
946
947        // line covers many columns but just one row
948        signed_difference_line(&mut img, Line::new((0.5, 1.0), (3.5, 0.0)));
949        // covered areas per-pixel
950        let a0 = (0.5 * (1.0 / 6.0)) / 2.0;
951        let a1 = ((1.0 / 6.0) + (3.0 / 6.0)) / 2.0;
952        let a2 = ((3.0 / 6.0) + (5.0 / 6.0)) / 2.0;
953        assert_approx_eq!(*img.get(0, 0).unwrap(), -a0);
954        assert_approx_eq!(*img.get(0, 1).unwrap(), a0 - a1);
955        assert_approx_eq!(*img.get(0, 2).unwrap(), a1 - a2);
956        assert_approx_eq!(*img.get(0, 3).unwrap(), a0 - a1);
957        assert_approx_eq!(*img.get(0, 4).unwrap(), -a0);
958        // total difference
959        let a: Scalar = img.iter().sum();
960        assert_approx_eq!(a, -1.0);
961        img.clear();
962
963        // out of bound line (intersects x = 0.0)
964        signed_difference_line(&mut img, Line::new((-1.0, 0.0), (1.0, 1.0)));
965        assert_approx_eq!(*img.get(0, 0).unwrap(), 3.0 / 4.0);
966        assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 / 4.0);
967        img.clear();
968
969        // multiple rows diag
970        signed_difference_line(&mut img, Line::new((0.0, -0.5), (2.0, 1.5)));
971        assert_approx_eq!(*img.get(0, 0).unwrap(), 1.0 / 8.0);
972        assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 - 2.0 / 8.0);
973        assert_approx_eq!(*img.get(0, 2).unwrap(), 1.0 / 8.0);
974        assert_approx_eq!(*img.get(1, 1).unwrap(), 1.0 / 8.0);
975        assert_approx_eq!(*img.get(1, 2).unwrap(), 0.5 - 1.0 / 8.0);
976        img.clear();
977
978        // only two pixels covered
979        signed_difference_line(&mut img, Line::new((0.1, 0.1), (1.9, 0.9)));
980        assert_approx_eq!(*img.get(0, 0).unwrap(), 0.18);
981        assert_approx_eq!(*img.get(0, 1).unwrap(), 0.44);
982        assert_approx_eq!(*img.get(0, 2).unwrap(), 0.18);
983        img.clear();
984
985        // single pixel covered
986        signed_difference_line(&mut img, Line::new((0.1, 0.1), (0.9, 0.9)));
987        assert_approx_eq!(*img.get(0, 0).unwrap(), 0.4);
988        assert_approx_eq!(*img.get(0, 1).unwrap(), 0.8 - 0.4);
989        img.clear();
990
991        // multiple rows vertical
992        signed_difference_line(&mut img, Line::new((0.5, 0.5), (0.5, 1.75)));
993        assert_approx_eq!(*img.get(0, 0).unwrap(), 1.0 / 4.0);
994        assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 / 4.0);
995        assert_approx_eq!(*img.get(1, 0).unwrap(), 3.0 / 8.0);
996        assert_approx_eq!(*img.get(1, 1).unwrap(), 3.0 / 8.0);
997        img.clear();
998    }
999
1000    #[test]
1001    fn test_edge_iter() {
1002        let line = Line::new((0.0, 0.0), (6.0, 2.0));
1003        let edge = Edge::new(line).unwrap();
1004        assert_eq!(edge.row, 0);
1005        // first row
1006        let (edge, mut iter) = edge.next_row().unwrap();
1007        assert_eq!(iter.column, 0);
1008        assert_approx_eq!(iter.next().unwrap(), 1.0 / 6.0);
1009        assert_approx_eq!(iter.next().unwrap(), 2.0 / 6.0);
1010        assert_approx_eq!(iter.next().unwrap(), 2.0 / 6.0);
1011        assert_approx_eq!(iter.next().unwrap(), 1.0 / 6.0);
1012        assert!(iter.next().is_none());
1013        // second row
1014        let (edge, iter) = edge.next_row().unwrap();
1015        assert_eq!(iter.column, 3);
1016        assert_approx_eq!(iter.sum::<Scalar>(), 1.0);
1017        // should not return next row
1018        assert!(edge.next_row().is_none());
1019
1020        let line = Line::new((1.0, 1.0), (4.0, 0.0));
1021        let edge = Edge::new(line).unwrap();
1022        assert_eq!(edge.row, 0);
1023        // first row
1024        let (edge, mut iter) = edge.next_row().unwrap();
1025        assert_eq!(iter.column, 1);
1026        assert_approx_eq!(iter.next().unwrap(), -1.0 / 6.0);
1027        assert_approx_eq!(iter.next().unwrap(), -2.0 / 6.0);
1028        assert_approx_eq!(iter.next().unwrap(), -2.0 / 6.0);
1029        assert_approx_eq!(iter.next().unwrap(), -1.0 / 6.0);
1030        // should not return next row
1031        assert!(edge.next_row().is_none());
1032
1033        // vertical line
1034        let line = Line::new((0.5, 0.5), (0.5, 1.5));
1035        let edge = Edge::new(line).unwrap();
1036        assert_eq!(edge.row, 0);
1037        // first row
1038        let (edge, mut iter) = edge.next_row().unwrap();
1039        assert_eq!(iter.column, 0);
1040        assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0);
1041        assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0);
1042        assert!(iter.next().is_none());
1043        // second row
1044        let (edge, iter) = edge.next_row().unwrap();
1045        assert_approx_eq!(iter.sum::<Scalar>(), 0.5);
1046        // should not return next row
1047        assert!(edge.next_row().is_none());
1048
1049        let line = Line::new((0.5, 0.2), (0.5 + EPSILON_SQRT, 0.7));
1050        let edge = Edge::new(line).unwrap();
1051        assert_eq!(edge.row, 0);
1052        let (edge, mut iter) = edge.next_row().unwrap();
1053        assert_eq!(iter.column, 0);
1054        assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0, 1e-6);
1055        assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0, 1e-6);
1056        assert!(iter.next().is_none());
1057        assert!(edge.next_row().is_none());
1058    }
1059
1060    fn test_rasterizer(rasterizer: &dyn Rasterizer) -> Result<(), Error> {
1061        #[rustfmt::skip]
1062        let expected = [
1063        //x 0    1    2     3     4    5     6     7    8
1064            0.0, 1.0, 1.0,  1.0,  1.0, 1.0,  1.0,  1.0, 0.0, // 0
1065            0.0, 0.5, 1.0,  1.0,  1.0, 1.0,  1.0,  0.5, 0.0, // 1
1066            0.0, 0.0, 0.25, 0.75, 1.0, 0.75, 0.25, 0.0, 0.0, // 2
1067            0.0, 0.0, 0.0,  0.0,  0.0, 0.0,  0.0,  0.0, 0.0, // 3
1068        ];
1069
1070        let path = Path::builder()
1071            .move_to((1.0, 0.0))
1072            .line_to((1.0, 1.0))
1073            .line_to((2.0, 2.0))
1074            .line_to((4.0, 3.0))
1075            .line_to((5.0, 3.0))
1076            .line_to((7.0, 2.0))
1077            .line_to((8.0, 1.0))
1078            .line_to((8.0, 0.0))
1079            .close()
1080            .build();
1081
1082        let mut img = ImageOwned::new_default(Size {
1083            width: 9,
1084            height: 4,
1085        });
1086        rasterizer.mask(&path, Transform::identity(), &mut img, FillRule::EvenOdd);
1087        for (expected, pixel) in expected.iter().zip(img.data()) {
1088            assert_approx_eq!(expected, pixel);
1089        }
1090
1091        // square that goes exactly through the sides of the image
1092        let path: Path = "M1,1 v2 h1 v-2 Z".parse()?;
1093        let mut img = ImageOwned::new_default(Size {
1094            width: 3,
1095            height: 3,
1096        });
1097        rasterizer.mask(&path, Transform::identity(), &mut img, FillRule::EvenOdd);
1098
1099        {
1100            let file = std::fs::File::create("/tmp/bla.bmp")?;
1101            img.write_bmp(file)?;
1102        }
1103
1104        Ok(())
1105    }
1106
1107    #[test]
1108    fn test_active_edge_rasterizer() -> Result<(), Error> {
1109        test_rasterizer(&ActiveEdgeRasterizer::default())
1110    }
1111
1112    #[test]
1113    fn test_sigend_difference_rasterizer() -> Result<(), Error> {
1114        test_rasterizer(&SignedDifferenceRasterizer::default())
1115    }
1116
1117    #[test]
1118    fn test_fill_rule() {
1119        let tr = Transform::identity();
1120        let path: Path = r#"
1121            M50,0 21,90 98,35 2,35 79,90z
1122            M110,0 h90 v90 h-90z
1123            M130,20 h50 v50 h-50 z
1124            M210,0  h90 v90 h-90 z
1125            M230,20 v50 h50 v-50 z
1126        "#
1127        .parse()
1128        .expect("failed to parse path");
1129        let (size, tr, _) = path.size(tr).expect("path is empty");
1130        let mut img = ImageOwned::new_default(size);
1131
1132        let y = 50;
1133        let x0 = 50; // middle of the star
1134        let x1 = 150; // middle of the first box
1135        let x2 = 250; // middle of the second box
1136
1137        let r0: Box<dyn Rasterizer> = Box::new(SignedDifferenceRasterizer::default());
1138        let r1: Box<dyn Rasterizer> = Box::new(ActiveEdgeRasterizer::default());
1139        for rasterizer in &[r0, r1] {
1140            img.clear();
1141            path.mask(rasterizer, tr, FillRule::EvenOdd, &mut img);
1142            assert_approx_eq!(img.get(y, x0).unwrap(), 0.0, 1e-6);
1143            assert_approx_eq!(img.get(y, x1).unwrap(), 0.0, 1e-6);
1144            assert_approx_eq!(img.get(y, x2).unwrap(), 0.0, 1e-6);
1145            let area = img.iter().sum::<Scalar>();
1146            assert_approx_eq!(area, 13130.0, 1.0);
1147
1148            img.clear();
1149            path.mask(rasterizer, tr, FillRule::NonZero, &mut img);
1150            assert_approx_eq!(img.get(y, x0).unwrap(), 1.0, 1e-6);
1151            assert_approx_eq!(img.get(y, x1).unwrap(), 1.0, 1e-6);
1152            assert_approx_eq!(img.get(y, x2).unwrap(), 0.0, 1e-6);
1153            let area = img.iter().sum::<Scalar>();
1154            assert_approx_eq!(area, 16492.5, 1.0);
1155        }
1156    }
1157}