package edu.gatech.cs2340.trydent.sample;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import edu.gatech.cs2340.trydent.math.curve.Curve;
import edu.gatech.cs2340.trydent.math.curve.IndexWrapMode;
/**
* Class to visually test the shapes of various interpolation curves.
*/
public class IndexWrapExample extends JComponent {
private static final long serialVersionUID = 7283474201296522376L;
public static void main(String[] args) {
int width = 800;
int height = 750;
final IndexWrapExample example = new IndexWrapExample(width, height);
example.clear();
double[] domain = new double[1001];
for (int i = 0; i < domain.length; i++) {
domain[i] = 50 * i / (domain.length - 1.0);
}
Curve<Double> sinCurve = new Curve<Double>() {
@Override
public Double sample(double t) {
return Math.sin(t * Math.PI * 3 / 50);
}
};
example.render("sin(x)", Color.BLUE, example.new Rectangle(30, 30, width / 4, height / 4), -1, 1, sinCurve,
domain);
Curve<Double> clampCurve = new Curve<Double>() {
@Override
public Double sample(double t) {
return (double) IndexWrapMode.CLAMP.handle((int) t, 10);
}
};
example.render("clamp(x, 10)", Color.BLUE, example.new Rectangle(30 + width / 2, 30, width / 4, height / 4), 0,
10, clampCurve, domain);
Curve<Double> wrapCurve = new Curve<Double>() {
@Override
public Double sample(double t) {
return (double) IndexWrapMode.WRAP.handle((int) t, 10);
}
};
example.render("wrap(x, 10)", Color.BLUE, example.new Rectangle(30, 30 + height / 2, width / 4, height / 4), 0,
10, wrapCurve, domain);
Curve<Double> reflectCurve = new Curve<Double>() {
@Override
public Double sample(double t) {
return (double) IndexWrapMode.REFLECT.handle((int) t, 10);
}
};
example.render("reflect(x, 10)", Color.BLUE, example.new Rectangle(30 + width / 2, 30 + height / 2, width / 4,
height / 4), 0, 10, reflectCurve, domain);
JFrame frame = new JFrame("Index Wrapping Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException x) {
}
example.repaint();
}
}
}).start();
}
private BufferedImage frameBuffer;
private Graphics2D graphics;
private List<Runnable> renderActions;
public IndexWrapExample(int width, int height) {
frameBuffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
graphics = frameBuffer.createGraphics();
setPreferredSize(new Dimension(width, height));
renderActions = new LinkedList<>();
}
@Override
public void paint(Graphics g) {
for (Runnable r : renderActions) {
r.run();
}
g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this);
}
private void addRenderAction(Runnable r) {
renderActions.add(r);
r.run();
}
private void clear() {
addRenderAction(new Runnable() {
@Override
public void run() {
graphics.setColor(Color.WHITE);
graphics.fillRect(-1, -1, frameBuffer.getWidth() + 2, frameBuffer.getHeight() + 2);
}
});
}
private void render(final String label, final Color color, final Rectangle chart, final double minRange,
final double maxRange, final Curve<Double> function, final double... independent) {
addRenderAction(new Runnable() {
@Override
public void run() {
doRender(label, color, chart, minRange, maxRange, function, independent);
}
});
}
private void doRender(String label, Color color, Rectangle chart, double minRange, double maxRange,
Curve<Double> function, double... independent) {
Graphics2D g = this.graphics;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Arrays.sort(independent);
double[] dependent = new double[independent.length];
for (int i = 0; i < independent.length; i++) {
dependent[i] = function.sample(independent[i]);
if (dependent[i] < minRange)
minRange = dependent[i];
if (dependent[i] > maxRange)
maxRange = dependent[i];
}
g.setStroke(new BasicStroke(1.0f));
g.setColor(Color.GRAY);
int lines = 10;
for (int i = 0; i < lines; i++) {
double s = (i + 1.0) / (lines);
int y = (int) Math.round(chart.y + s * chart.height);
g.drawLine(chart.x, y, chart.x + chart.width, y);
}
g.setStroke(new BasicStroke(2.0f));
g.setColor(color);
for (int i = 0; i < independent.length - 1; i++) {
int x0 = (int) Math.round(chart.x + chart.width * (independent[i] - independent[0])
/ (independent[independent.length - 1] - independent[0]));
int y0 = (int) Math.round(chart.y + chart.height - chart.height * (dependent[i] - minRange)
/ (maxRange - minRange));
int x1 = (int) Math.round(chart.x + chart.width * (independent[i + 1] - independent[0])
/ (independent[independent.length - 1] - independent[0]));
int y1 = (int) Math.round(chart.y + chart.height - chart.height * (dependent[i + 1] - minRange)
/ (maxRange - minRange));
g.drawLine(x0, y0, x1, y1);
}
g.setStroke(new BasicStroke(1.0f));
g.setColor(Color.BLACK);
g.drawRect(chart.x, chart.y, chart.width, chart.height);
String s = null;
s = String.valueOf(maxRange);
g.drawString(s, chart.x - g.getFontMetrics().stringWidth(s), chart.y);
s = String.valueOf(minRange);
g.drawString(s, chart.x - g.getFontMetrics().stringWidth(s), chart.y + chart.height);
s = String.valueOf(independent[0]);
g.drawString(s, chart.x, chart.y + chart.height + g.getFontMetrics().getHeight());
s = String.valueOf(independent[1]);
g.drawString(s, chart.x + chart.width, chart.y + chart.height + g.getFontMetrics().getHeight());
s = label;
g.drawString(s, chart.x + chart.width / 2 - g.getFontMetrics().stringWidth(s) / 2, chart.y
- g.getFontMetrics().getDescent() - 2);
}
/**
* Integer rectangle class just for organizing charts. Just an information
* holder, so I don't need or want the whole javafx node version.
*/
class Rectangle {
protected int x, y, width, height;
Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
}