Skip to content

Instantly share code, notes, and snippets.

@chausen
Created April 9, 2025 05:47
Show Gist options
  • Save chausen/7f914189009818662f8237a24ff76fd3 to your computer and use it in GitHub Desktop.
Save chausen/7f914189009818662f8237a24ff76fd3 to your computer and use it in GitHub Desktop.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LayeredCrosshatchDemo {
// Suppose we have enumerated density levels
public enum DensityLevel {
LOW,
MEDIUM,
HIGH
}
// A region’s data structure: set of pixel coordinates + which density it should be
public static class Region {
private Set<Point> pixelCoordinates;
private DensityLevel densityLevel;
public Region(Set<Point> pixels, DensityLevel densityLevel) {
this.pixelCoordinates = pixels;
this.densityLevel = densityLevel;
}
public Set<Point> getPixelCoordinates() {
return pixelCoordinates;
}
public DensityLevel getDensityLevel() {
return densityLevel;
}
}
public static void main(String[] args) {
int width = 600;
int height = 400;
// 1) Generate 3 separate "layer" images, one for each density
// All have ARGB so we can do transparency (alpha)
BufferedImage layerLow = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage layerMedium = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage layerHigh = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// 2) For each layer, fill with crosshatching at the appropriate spacing
// but fill the entire image with that pattern. We'll mask out unwanted areas later.
drawCrosshatchesFull(layerLow, 15); // bigger spacing => sparser
drawCrosshatchesFull(layerMedium, 8);
drawCrosshatchesFull(layerHigh, 4); // smaller spacing => denser
// 3) Construct some example Region data
Region regionA = makeRegion( 50,50, 100,60, DensityLevel.LOW); // a rectangle for demonstration
Region regionB = makeRegion(150,80, 80,50, DensityLevel.MEDIUM);
Region regionC = makeRegion(300,120, 50, 60, DensityLevel.HIGH);
List<Region> allRegions = List.of(regionA, regionB, regionC);
// 4) For each region, we "unmask" the corresponding layer in its pixelCoordinates
// and set the rest to transparent. Or equivalently, we can set all pixels
// outside the region to 0 alpha in that layer.
// We'll do it by clearing the alpha outside of the region.
maskLayersByRegion(allRegions, layerLow, layerMedium, layerHigh);
// 5) Finally, create the final image with white background (or anything).
BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D gFinal = finalImage.createGraphics();
try {
// White background
gFinal.setColor(Color.WHITE);
gFinal.fillRect(0, 0, width, height);
// Draw each layer on top
gFinal.drawImage(layerLow, 0, 0, null);
gFinal.drawImage(layerMedium, 0, 0, null);
gFinal.drawImage(layerHigh, 0, 0, null);
// At this point, finalImage is complete.
// You can write it out or display it, e.g.:
// ImageIO.write(finalImage, "PNG", new File("crosshatchedResult.png"));
} catch (Exception e) {
e.printStackTrace();
} finally {
gFinal.dispose();
}
}
/**
* Draws crosshatches across the entire buffered image at the given spacing.
* We'll assume black crosshatches on a transparent background.
* (i.e., everything else is 0 alpha).
*/
private static void drawCrosshatchesFull(BufferedImage layer, int spacing) {
int width = layer.getWidth();
int height = layer.getHeight();
Graphics2D g = layer.createGraphics();
try {
// Start with a fully transparent background
g.setComposite(AlphaComposite.Clear);
g.fillRect(0, 0, width, height);
// Now switch to "SrcOver" so we can draw the lines in black
g.setComposite(AlphaComposite.SrcOver);
// Optionally set stroke to 1 pixel or thinner
g.setStroke(new BasicStroke(1.0f));
g.setColor(Color.BLACK);
// For "/" diagonals
for (int y = 0; y <= height; y += spacing) {
drawOneDiagonalLineFull(g, 0, y, width, height, +1);
}
for (int x = 0; x <= width; x += spacing) {
drawOneDiagonalLineFull(g, x, height, width, height, +1);
}
// For "\" diagonals
for (int y = 0; y <= height; y += spacing) {
drawOneDiagonalLineFull(g, 0, y, width, height, -1);
}
for (int x = 0; x <= width; x += spacing) {
drawOneDiagonalLineFull(g, x, 0, width, height, -1);
}
} finally {
g.dispose();
}
}
/**
* Draws one diagonal line from (startX, startY) in either "/" or "\" direction
* all the way across the image.
*/
private static void drawOneDiagonalLineFull(Graphics2D g,
int startX, int startY,
int width, int height,
int direction) {
// direction = +1 => "/"
// direction = -1 => "\"
// We'll step in increments of 1 pixel until we're out of the image bounds
int x = startX;
int y = startY;
int stepCount = width + height; // worst case diagonal length
for (int i = 0; i < stepCount; i++) {
// If out of bounds, break
if (x < 0 || x >= width || y < 0 || y >= height) {
break;
}
// Draw a tiny line from (x, y) to (x, y).
// Actually, we can just do g.drawLine(x, y, x, y).
g.drawLine(x, y, x, y);
// Move diagonally
x += 1 * direction; // +/-1 in the x-direction
y -= 1; // always up 1 in y for "/"
// or if direction=-1 => that changes the diagonal slope
// (this is the same logic we used before, just in "full layer" context)
}
}
/**
* For each region in the list, keep the crosshatching in the appropriate layer
* within region pixels, and set everything else to transparent in that layer.
*/
private static void maskLayersByRegion(List<Region> regions,
BufferedImage layerLow,
BufferedImage layerMedium,
BufferedImage layerHigh) {
// We'll do a quick pass creating a large sets of region pixels
// for each density.
Set<Point> lowSet = new HashSet<>();
Set<Point> mediumSet = new HashSet<>();
Set<Point> highSet = new HashSet<>();
for (Region region : regions) {
switch (region.getDensityLevel()) {
case LOW -> lowSet.addAll(region.getPixelCoordinates());
case MEDIUM -> mediumSet.addAll(region.getPixelCoordinates());
case HIGH -> highSet.addAll(region.getPixelCoordinates());
}
}
// Now we’ll mask each layer by iterating over every pixel.
maskLayer(layerLow, lowSet);
maskLayer(layerMedium, mediumSet);
maskLayer(layerHigh, highSet);
}
/**
* Sets all pixels *not in the given set* to fully transparent (ARGB=0)
* so that only region pixels remain.
*/
private static void maskLayer(BufferedImage layer, Set<Point> regionPoints) {
int width = layer.getWidth();
int height = layer.getHeight();
// For quick membership checks:
// regionPoints is a set of (x,y).
// If you have extremely large images, you might prefer a scanline approach.
// But let's keep it straightforward for demonstration.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (!regionPoints.contains(new Point(x, y))) {
// Set alpha to 0
layer.setRGB(x, y, 0x00000000);
}
}
}
}
/**
* Helper method to create a simple rectangular region.
* This is just for the demo; in your code, you'd have real shapes.
*/
private static Region makeRegion(int startX, int startY, int w, int h, DensityLevel density) {
Set<Point> coords = new HashSet<>();
for (int y = startY; y < startY + h; y++) {
for (int x = startX; x < startX + w; x++) {
coords.add(new Point(x, y));
}
}
return new Region(coords, density);
}
}
@MRKEN11
Copy link

MRKEN11 commented Apr 9, 2025

I NEED A PROGRAMMER

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment