Skip to content

proposal: image: add (Rectangle).PointsBy for iterating over points as iter.Seq[Point] #69254

Open
@tomocy

Description

@tomocy

Proposal Details

Summary

I propose adding a new method PointsBy to image.Rectangle
that returns an iter.Seq[image.Point] for points within the rectangle.
This function would allow developers to directly iterate over points in a rectangle,
making the code more straightforward and reducing potential errors.

The PointsBy can be implemented as follows.

func (r Rectangle) PointsBy(delta Point) iter.Seq[Point] {
    return func(yield func(Point) bool) {
        for y := r.Min.Y; y < r.Max.Y; y += delta.Y {
            for x := r.Min.X; x < r.Max.X; x += delta.X {
                if !yield(image.Pt(x, y)) {
                    return
                }
            }
        }
    }
}

By this function, the common pattern with a image.Rectangle r

for y := r.Min.Y; y < r.Max.Y; y++ {
    for x := r.Min.X; x < r.Max.X; x++ {
        p := image.Pt(x, y)
        // Do something with p.
    }
}

could be simplified to

for p := range r.PointsBy(image.Pt(1, 1)) {
    // Do something with p.
}

Background

  • Iterating over points within a rectangle is a common operation in image processing tasks.

  • This operation requires manually writing nested loops every time.
    While not complex, it can indeed be cumbersome and repetitive.

  • Since image.Rectangle does not necessarily start at (0, 0), it's crucial to loop from Min to Max, as documented.
    However, there are cases where developers mistakenly start from 0.

Given this background, it may be beneficial to provide a dedicated API from the image package
to better address this demand for iterating over points.

Benefits

  • Provides a direct API for iterating over image.Points not over Xs and Ys within an image.Rectangle.

  • Eliminates the need for additional labels when breaking out of nested loops under specific conditions, such as

pointsLoop:
    for y := r.Min.Y; y < r.Max.Y; y++ {
        for x := r.Min.X; x < r.Max.X; x++ {
            // if (x, y) meets a certain condition
            break pointsLoop
        }
    }

    // then
  • Supports non-unit steps (e.g., y += 2, x += 3) by taking a delta parameter, keeping flexibility.

  • Aligns well with the iter package, enhancing integration with the iterator-based approach.

Considerations

Beyond this proposal, a few additional considerations might be relevant.

  • Whether to use image.Point to express delta (as image.Rectangle.Size does with func() image.Point) or x, y int (as image.Image.At does with func(x, y int) color.Color).

  • The iter package was added recently, and its adoption and consensus within the community might still be evolving.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions