Skip to content

Instantly share code, notes, and snippets.

@KableM
Created April 18, 2019 06:53
Show Gist options
  • Save KableM/d0aea2d0cd902c6bc6a24acd90c22b68 to your computer and use it in GitHub Desktop.
Save KableM/d0aea2d0cd902c6bc6a24acd90c22b68 to your computer and use it in GitHub Desktop.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
* Run on the command line with:
* javac Tires.java
* java Tires
*
* @author @kable_codes
*/
public class Tires {
private final BufferedImage inputImage;
private final List<Tire> tires;
private final Color black = new Color(0x000000);
// 2018 tire colours
// private final List<Color> tireColors = Arrays.asList(new Color(0xEDC4F5),
// new Color(0xB32AF5),
// new Color(0xFFFFFF),
// new Color(0xFFE000),
// new Color(0xFF0700),
// new Color(0x1285FF),
// new Color(0xFF8503),
// black);
// 2019 tire colors
private final List<Color> tireColors = Arrays.asList(new Color(0xFFE000),
new Color(0xFFFFFF),
new Color(0xEE0700),
black);
private final int stageWidth;
private final int stageHeight;
private Point2D.Float cameraPosition;
private float cameraZoom = 80;
public Tires(File file) throws IOException {
inputImage = ImageIO.read(file);
this.stageWidth = inputImage.getWidth();
this.stageHeight = inputImage.getHeight();
cameraPosition = new Point2D.Float(stageWidth / 2f, stageHeight / 2f);
tires = new ArrayList<>();
float tireRadius = 3;
Random random = new Random();
for (int i = 0; i < 50000; i++) {
float x = random.nextFloat() * stageWidth;
float y = random.nextFloat() * stageHeight;
Color color = getColor((int) x, (int) y);
Color tireColor = getClosestTireColor(color);
if (tireColor != null) {
tires.add(new Tire(x, y, tireRadius, tireColor));
}
}
}
private Color getClosestTireColor(Color color) {
Color closestColor = null;
Double closestDisance = null;
for (Color compare : tireColors) {
double distance = colorDistance(color, compare);
if (closestDisance == null || distance < closestDisance) {
closestColor = compare;
closestDisance = distance;
}
}
// if (closestDisance > 35000) {
// return null;
// }
if (closestColor == black) {
return null;
}
return closestColor;
}
private Color getColor(int x, int y) {
if (x < 0 || x >= inputImage.getWidth() || y < 0 || y >= inputImage.getHeight()) {
return new Color(0x000000);
}
int rgb = inputImage.getRGB(x, y);
return new Color(rgb);
}
private double colorDistance(Color c1, Color c2) {
int rd = c2.getRed() - c1.getRed();
int gd = c2.getGreen() - c1.getGreen();
int bd = c2.getBlue() - c1.getBlue();
return rd * rd + gd * gd + bd * bd;
}
protected void step(float dt) {
cameraZoom *= (1 - dt * 0.0004);
if (cameraZoom < 1) {
cameraZoom = 1;
}
tires.forEach(tire -> tire.rotation += dt * tire.rSpeed);
}
protected void draw(Graphics2D graphics) {
graphics.setColor(new Color(0x111111));
graphics.fillRect(0, 0, stageWidth, stageHeight);
tires.forEach(tire -> tire.draw(graphics));
}
class Tire {
private float x;
private float y;
private float radius;
private float rSpeed = -0.9f;
private float rotation;
private Color color;
private final Color tireBase = new Color(0x222222);
private final Color wheelColor = new Color(0x888888);
private final Color wheelColor2 = new Color(0x666666);
public Tire(float x, float y, float radius, Color color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
}
public void draw(Graphics2D graphics) {
float renderX = (x - stageWidth / 2f) * (cameraZoom - 1) + stageWidth / 2f - cameraPosition.x + x;
float renderY = (y - stageHeight / 2f) * (cameraZoom - 1) + stageHeight / 2f - cameraPosition.y + y;
float renderRadius = radius * cameraZoom;
if (renderX + renderRadius < 0 ||
renderX - renderRadius > stageWidth ||
renderY + renderRadius < 0 ||
renderY - renderRadius > stageHeight) {
return;
}
Ellipse2D base = new Ellipse2D.Float(renderX - renderRadius, renderY - renderRadius, renderRadius * 2, renderRadius * 2);
RadialGradientPaint basePaint = new RadialGradientPaint(renderX, renderY, renderRadius,
new float[]{0.5f, 0.8f, 1f},
new Color[]{black, tireBase, black});
graphics.setPaint(basePaint);
graphics.fill(base);
float markRadius = renderRadius * 0.8f;
Arc2D.Float arc1 = new Arc2D.Float(renderX - markRadius, renderY - markRadius, markRadius * 2, markRadius * 2, rotation - 45, 100, Arc2D.OPEN);
Arc2D.Float arc2 = new Arc2D.Float(renderX - markRadius, renderY - markRadius, markRadius * 2, markRadius * 2, rotation + 135, 100, Arc2D.OPEN);
graphics.setColor(this.color);
graphics.setStroke(new BasicStroke(renderRadius * 0.1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
graphics.draw(arc1);
graphics.draw(arc2);
float wheelRadius = renderRadius * 0.6f;
Ellipse2D wheel = new Ellipse2D.Float(renderX - wheelRadius, renderY - wheelRadius, wheelRadius * 2, wheelRadius * 2);
RadialGradientPaint wheelPaint = new RadialGradientPaint(renderX, renderY, wheelRadius,
new float[]{0.1f, 0.15f, 0.2f, 0.25f, 0.8f, 0.85f},
new Color[]{wheelColor, black, wheelColor, black, black, wheelColor2});
graphics.setPaint(wheelPaint);
graphics.fill(wheel);
}
}
public static void main(String[] args) throws IOException {
String path = "/path/to/image";
if ("/path/to/image".equals(path)) {
throw new RuntimeException("Please set a path for the image");
}
Tires tires = new Tires(new File(path));
Preview preview = new Preview("Tires", tires, tires.stageWidth, tires.stageHeight, 30, true);
preview.start();
}
static class Preview extends JFrame {
private final Tires tires;
private final int width;
private final int height;
private Timer timer;
public Preview(String title,
Tires tires,
int width,
int height,
int frameRate,
boolean anitalias) throws HeadlessException {
super(title);
this.width = width;
this.height = height;
this.tires = tires;
float delay = 1000f / frameRate;
timer = new Timer((int) delay, e -> step(delay));
JPanel container = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
if (anitalias) {
RenderingHints hints = new RenderingHints(null);
hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHints(hints);
}
tires.draw((Graphics2D) g);
}
};
getContentPane().add(BorderLayout.CENTER, container);
}
public void start() {
EventQueue.invokeLater(() -> {
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
timer.start();
setVisible(true);
setPreferredSize(new Dimension(width, height + getInsets().top));
pack();
});
}
private void step(float dt) {
tires.step(dt);
repaint();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment