Graphics2D: How to create consistent fill around irregular shape?

I am using Java Graphics2D to create this card with a touch of red overlay over it. As you can see, the overlay is cropped along the border of the image on the left side: -

enter image description here

After demonstrating this project to my interested parties to the project, they want this overlay to be copied along the border of the map with some consistent addition around it. A simple reason for this is to let users know that the overlay extends beyond the map.

So, my initial thought was to “scale and shift” by creating another large map that serves as a “cookie cutter”, here is my simplified code: -

// polygon of the map Polygon minnesotaPolygon = ...; // convert polygon to area Area minnesotaArea = new Area(); minnesotaArea.add(new Area(minnesotaPolygon)); // this represents the whole image Area wholeImageArea = new Area(new Rectangle(mapWidth, mapHeight)); // zoom in by 8% double zoom = 1.08; // performing "zoom and shift" Rectangle bound = minnesotaArea.getBounds(); AffineTransform affineTransform = new AffineTransform(g.getTransform()); affineTransform.translate(-((bound.getWidth() * zoom) - bound.getWidth()) / 2, -((bound.getHeight() * zoom) - bound.getHeight()) / 2); affineTransform.scale(zoom, zoom); minnesotaArea.transform(affineTransform); // using it as a cookie cutter wholeImageArea.subtract(minnesotaArea); g.setColor(Color.GREEN); g.fill(wholeImageArea); 

The reason I fill the outside with green is to let me see if the cookie cutter is made correctly. Here is the result: -

enter image description here

As you can see, “scaling and shifting” does not work in this case. There is no gasket in the lower right corner. Then I realized that this technique would not work for an irregular shape, such as a map ... and it only works on simpler shapes like square, circle, etc.

What I want is to create a consistent addition / mark around the map before trimming the rest. To make sure you understand what I'm saying here, I put this snapshot below (although I did it poorly) to explain what I'm trying to do here: -

enter image description here

I'm not sure how to proceed from here, and I hope you guys can give me some tips on this.

Thanks.

+4
source share
1 answer

I’ll just explain the logic, because I don’t have time to write the code myself. The short answer is that you have to go through each pixel of the map image, and if any pixels in the vicinity (that is, at some distance) are considered "ground", then you register the current pixel as part of the fill area.

For a long answer, here are 9 steps to achieve your goal.

1. Determine the size of the gasket. Say 6 pixels.

2. Create a map image in monochrome (black - "water", white - "earth"). Leave a margin of at least 6 pixels along the edge. This is the input image: (it does not scale)

black and white map

3. Create an image of a circle with a diameter of 11 pixels (11 = 6 * 2-1). Again, black is empty / transparent, white is solid. This is the image of the hit area:

11 pixel wide circle

4. Create a third picture that is all black (for starters). Make it the same size as the input image. It will be used as the output image.

5. Iterate each pixel of the input image.

6. The image of the hit area is superimposed on this pixel (just do it practically by calculation) so that the center of the hit area (white circle) is above the current pixel of the input image.

7. Now iterate over each pixel in the hit area image.

8. If any white pixel of the image of the hit area intersects the white pixel of the input image, then draw a white pixel (where the center of the circle) on the output image.

9. Go to step 5.

Admittedly, starting from step 6 is not so simple, but it is quite easy to implement. Hope you understand the logic. If my explanation is too confusing (sorry), I could spend some time writing a complete solution (in Javascript, C # or Haskell).

+1
source

Source: https://habr.com/ru/post/1468971/


All Articles