Haskell中基于坐标创建任意尺寸矩形栅格的技术问题
Let's break down what's going wrong with your current code and how to make it work for any rectangle size—whether that's 3x3, 4x4, 5x5, or beyond.
First: What's Wrong with the Existing Code
Your current implementation hardcodes 8 specific points, which only works for a 3x3 grid (since you're assuming x2 and y2 are both 2—adding that to x1/y1 gives you the opposite corner of a 3x3 square). This approach doesn't scale:
- It only covers a tiny subset of points (just corners and midpoints) instead of all edge points.
- It relies on fixed offsets that don't adapt when you pass different coordinate pairs.
- There's no logic to generate points along the full length of each rectangle edge.
Solution: Generate Edges Dynamically
The fix is to generate each edge of the rectangle programmatically, using list comprehensions to iterate over all relevant coordinates. I'll assume your Coord type represents two diagonal corners of the rectangle (e.g., top-left and bottom-right). We'll start by normalizing the coordinates to ensure a valid min/max range, then build each edge.
Step 1: Define Types (if you haven't already)
First, let's align on type definitions:
type Coord = (Int, Int) type Raster = [((Int, Int), Double)]
Step 2: The Universal Rectangle Raster Function
This function works for any rectangle size by generating all edge points:
rectangleRaster :: Coord -> Coord -> Raster rectangleRaster (x1, y1) (x2, y2) = let -- Normalize coordinates to handle reversed input pairs (minX, maxX) = (min x1 x2, max x1 x2) (minY, maxY) = (min y1 y2, max y1 y2) -- Generate top edge (all x from minX to maxX, fixed y = minY) topEdge = [((x, minY), 1.0) | x <- [minX..maxX]] -- Generate bottom edge (all x from minX to maxX, fixed y = maxY) bottomEdge = [((x, maxY), 1.0) | x <- [minX..maxX]] -- Generate left edge (exclude top/bottom to avoid duplicate points) leftEdge = [((minX, y), 1.0) | y <- [minY+1..maxY-1]] -- Generate right edge (exclude top/bottom to avoid duplicate points) rightEdge = [((maxX, y), 1.0) | y <- [minY+1..maxY-1]] in topEdge ++ bottomEdge ++ leftEdge ++ rightEdge
Step 3: Bonus: Filled Rectangle (If You Need It)
If you want a filled rectangle instead of just a border, the code is even simpler—generate every point within the coordinate range:
filledRectangleRaster :: Coord -> Coord -> Raster filledRectangleRaster (x1, y1) (x2, y2) = let (minX, maxX) = (min x1 x2, max x1 x2) (minY, maxY) = (min y1 y2, max y1 y2) in [((x, y), 1.0) | x <- [minX..maxX], y <- [minY..maxY]]
How This Works
- Normalization: The
min/maxcalls ensure the function works even if you pass coordinates in reverse order (e.g., bottom-right to top-left). - List Comprehensions: These let us iterate over all x or y values in the valid range, generating every point along each edge (or every point in the filled rectangle).
- No Hardcoding: The function adapts automatically to any input coordinates—pass
(0,0)and(3,3)for a 4x4 grid,(1,2)and(5,7)for a 5x6 grid, etc.
Test It Out
For a 3x3 grid (top-left (0,0), bottom-right (2,2)), running rectangleRaster (0,0) (2,2) will produce exactly the 8 points your original code did—but now if you run rectangleRaster (0,0) (3,3) for a 4x4 grid, it will generate all 12 edge points correctly.
内容的提问来源于stack exchange,提问作者goat

