Added shape interface to clean up code and added ellipse class

pull/35/head
James Ball 2020-02-05 23:47:27 +00:00
rodzic 45b66fa4a5
commit 2b6f2932c7
7 zmienionych plików z 143 dodań i 56 usunięć

Wyświetl plik

@ -1,5 +1,6 @@
package audio; package audio;
import shapes.Ellipse;
import shapes.Shapes; import shapes.Shapes;
import shapes.Vector; import shapes.Vector;
@ -12,10 +13,11 @@ public class AudioClient {
AudioPlayer player = new AudioPlayer(); AudioPlayer player = new AudioPlayer();
AudioPlayer.FORMAT = AudioPlayer.defaultFormat(SAMPLE_RATE); AudioPlayer.FORMAT = AudioPlayer.defaultFormat(SAMPLE_RATE);
AudioPlayer.addLines(Shapes.generatePolygon(100, 0.5, 60)); AudioPlayer.addShapes(Shapes.generatePolygon(100, 0.5, 60));
AudioPlayer.addLines(Shapes.generatePolygram(5, 3, 0.5, 60)); AudioPlayer.addShapes(Shapes.generatePolygram(5, 3, 0.5, 60));
AudioPlayer.addShape(new Ellipse(0.5, 0.5));
AudioPlayer.setRotateSpeed(0.8); AudioPlayer.setRotateSpeed(-0.8);
AudioPlayer.setTranslation(4, new Vector(1, 1)); AudioPlayer.setTranslation(4, new Vector(1, 1));
AudioPlayer.setScale(0.5); AudioPlayer.setScale(0.5);

Wyświetl plik

@ -1,21 +1,23 @@
package audio; package audio;
import com.xtaudio.xt.*; import com.xtaudio.xt.*;
import shapes.Ellipse;
import shapes.Line; import shapes.Line;
import shapes.Shape;
import shapes.Vector; import shapes.Vector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AudioPlayer extends Thread { public class AudioPlayer extends Thread {
public static XtFormat FORMAT;
private static volatile boolean stopped = false; private static volatile boolean stopped = false;
private static List<Line> lines = new ArrayList<>(); private static List<Shape> shapes = new ArrayList<>();
private static int currentLine = 0; private static int currentShape = 0;
private static int framesDrawn = 0; private static int framesDrawn = 0;
private static double[] phases = new double[2]; private static double[] phases = new double[2];
public static XtFormat FORMAT;
private static double TRANSLATE_SPEED = 0; private static double TRANSLATE_SPEED = 0;
private static Vector TRANSLATE_VECTOR; private static Vector TRANSLATE_VECTOR;
private static final int TRANSLATE_PHASE_INDEX = 0; private static final int TRANSLATE_PHASE_INDEX = 0;
@ -28,81 +30,77 @@ public class AudioPlayer extends Thread {
XtFormat format = stream.getFormat(); XtFormat format = stream.getFormat();
for (int f = 0; f < frames; f++) { for (int f = 0; f < frames; f++) {
Line line = currentLine(); Shape shape = currentShape();
line = scale(line); shape = scale(shape);
line = rotate(line, stream.getFormat().mix.rate); shape = rotate(shape, stream.getFormat().mix.rate);
line = translate(line, stream.getFormat().mix.rate); shape = translate(shape, stream.getFormat().mix.rate);
int framesToDraw = (int) (line.length * line.getWeight()); double framesToDraw = shape.getLength() * shape.getWeight();
double drawingProgress = framesDrawn / framesToDraw;
for (int c = 0; c < format.outputs; c++) { for (int c = 0; c < format.outputs; c++) {
((float[]) output)[f * format.outputs] = nextX(line, framesToDraw); ((float[]) output)[f * format.outputs] = shape.nextX(drawingProgress);
((float[]) output)[f * format.outputs + 1] = nextY(line, framesToDraw); ((float[]) output)[f * format.outputs + 1] = shape.nextY(drawingProgress);
} }
framesDrawn++; framesDrawn++;
if (framesDrawn > framesToDraw) { if (framesDrawn > framesToDraw) {
framesDrawn = 0; framesDrawn = 0;
currentLine++; currentShape++;
} }
} }
} }
static float nextTheta(double sampleRate, double frequency, int phaseIndex) { static double nextTheta(double sampleRate, double frequency, int phaseIndex) {
phases[phaseIndex] += frequency / sampleRate; phases[phaseIndex] += frequency / sampleRate;
if (phases[phaseIndex] >= 1.0)
if (phases[phaseIndex] >= 1.0) {
phases[phaseIndex] = -1.0; phases[phaseIndex] = -1.0;
return (float) (phases[phaseIndex] * Math.PI);
} }
private static float nextX(Line line, double framesToDraw) { return phases[phaseIndex] * Math.PI;
return (float) (line.getX1() + (line.getX2() - line.getX1()) * framesDrawn / framesToDraw);
} }
private static float nextY(Line line, double framesToDraw) { private static Shape scale(Shape shape) {
return (float) (line.getY1() + (line.getY2() - line.getY1()) * framesDrawn / framesToDraw);
}
private static Line scale(Line line) {
if (SCALE != 1) { if (SCALE != 1) {
return line.scale(SCALE); return shape.scale(SCALE);
} }
return line; return shape;
} }
private static Line rotate(Line line, double sampleRate) { private static Shape rotate(Shape shape, double sampleRate) {
if (ROTATE_SPEED != 0) { if (ROTATE_SPEED != 0) {
line = line.rotate( shape = shape.rotate(
nextTheta(sampleRate, ROTATE_SPEED, TRANSLATE_PHASE_INDEX) nextTheta(sampleRate, ROTATE_SPEED, TRANSLATE_PHASE_INDEX)
); );
} }
return line; return shape;
} }
private static Line translate(Line line, double sampleRate) { private static Shape translate(Shape shape, double sampleRate) {
if (TRANSLATE_SPEED != 0 && !TRANSLATE_VECTOR.equals(new Vector())) { if (TRANSLATE_SPEED != 0 && !TRANSLATE_VECTOR.equals(new Vector())) {
return line.translate(TRANSLATE_VECTOR.scale( return shape.translate(TRANSLATE_VECTOR.scale(
Math.sin(nextTheta(sampleRate, TRANSLATE_SPEED, ROTATE_PHASE_INDEX)) Math.sin(nextTheta(sampleRate, TRANSLATE_SPEED, ROTATE_PHASE_INDEX))
)); ));
} }
return line; return shape;
} }
public static void addLine(Line line) { public static void addShape(Shape shape) {
AudioPlayer.lines.add(line); AudioPlayer.shapes.add(shape);
} }
public static void addLines(List<Line> lines) { public static void addShapes(List<Shape> shapes) {
AudioPlayer.lines.addAll(lines); AudioPlayer.shapes.addAll(shapes);
} }
private static Line currentLine() { private static Shape currentShape() {
return lines.get(currentLine % lines.size()); return shapes.get(currentShape % shapes.size());
} }
public static void setRotateSpeed(double speed) { public static void setRotateSpeed(double speed) {

Wyświetl plik

@ -27,8 +27,8 @@ public class Graph {
Node nodeA = nodes.get(line.getA()); Node nodeA = nodes.get(line.getA());
Node nodeB = nodes.get(line.getB()); Node nodeB = nodes.get(line.getB());
nodeA.addAdjacent(nodeB, line.length); nodeA.addAdjacent(nodeB, line.getLength());
nodeB.addAdjacent(nodeA, line.length); nodeB.addAdjacent(nodeA, line.getLength());
} }
} }
} }

Wyświetl plik

@ -0,0 +1,57 @@
package shapes;
public class Ellipse implements Shape {
private final double a;
private final double b;
private final double weight;
private final double length;
public Ellipse(double a, double b, double weight) {
this.a = a;
this.b = b;
this.weight = weight;
// Approximation of length.
this.length = 2 * Math.PI * Math.sqrt((this.a * this.a + this.b * this.b) / 2);
}
public Ellipse(double a, double b) {
this(a, b, 100);
}
@Override
public float nextX(double drawingProgress) {
return (float) (a * Math.sin(2 * Math.PI * drawingProgress));
}
@Override
public float nextY(double drawingProgress) {
return (float) (b * Math.cos(2 * Math.PI * drawingProgress));
}
// TODO: Implement ellipse rotation.
@Override
public Shape rotate(double theta) {
return this;
}
@Override
public Shape scale(double factor) {
return new Ellipse(a * factor, b * factor, weight);
}
// TODO: Implement ellipse translation.
@Override
public Shape translate(Vector vector) {
return this;
}
@Override
public double getWeight() {
return weight;
}
@Override
public double getLength() {
return length;
}
}

Wyświetl plik

@ -1,12 +1,12 @@
package shapes; package shapes;
public class Line { public class Line implements Shape {
private final Vector a; private final Vector a;
private final Vector b; private final Vector b;
private final double weight; private final double weight;
// Storing the length to save on repeat calculations. // Storing the length to save on repeat calculations.
public final double length; private final double length;
public static final double DEFAULT_WEIGHT = 100; public static final double DEFAULT_WEIGHT = 100;
@ -33,14 +33,17 @@ public class Line {
return Math.sqrt(Math.pow(getX1() - getX2(), 2) + Math.pow(getY1() - getY2(), 2)); return Math.sqrt(Math.pow(getX1() - getX2(), 2) + Math.pow(getY1() - getY2(), 2));
} }
@Override
public Line rotate(double theta) { public Line rotate(double theta) {
return new Line(getA().rotate(theta), getB().rotate(theta), getWeight()); return new Line(getA().rotate(theta), getB().rotate(theta), getWeight());
} }
@Override
public Line translate(Vector vector) { public Line translate(Vector vector) {
return new Line(getA().add(vector), getB().add(vector)); return new Line(getA().add(vector), getB().add(vector));
} }
@Override
public Line scale(double factor) { public Line scale(double factor) {
return new Line(getA().scale(factor), getB().scale(factor)); return new Line(getA().scale(factor), getB().scale(factor));
} }
@ -49,6 +52,16 @@ public class Line {
return new Line(getA().copy(), getB().copy(), getWeight()); return new Line(getA().copy(), getB().copy(), getWeight());
} }
@Override
public float nextX(double drawingProgress) {
return (float) (getX1() + (getX2() - getX1()) * drawingProgress);
}
@Override
public float nextY(double drawingProgress) {
return (float) (getY1() + (getY2() - getY1()) * drawingProgress);
}
public Vector getA() { public Vector getA() {
return a; return a;
} }
@ -89,10 +102,16 @@ public class Line {
return new Line(getX1(), getY1(), getX2(), y2); return new Line(getX1(), getY1(), getX2(), y2);
} }
@Override
public double getWeight() { public double getWeight() {
return weight; return weight;
} }
@Override
public double getLength() {
return length;
}
public Line setWeight(double weight) { public Line setWeight(double weight) {
return new Line(getX1(), getY1(), getX2(), getY2(), weight); return new Line(getX1(), getY1(), getX2(), getY2(), weight);
} }

Wyświetl plik

@ -0,0 +1,11 @@
package shapes;
public interface Shape {
float nextX(double drawingProgress);
float nextY(double drawingProgress);
Shape rotate(double theta);
Shape scale(double factor);
Shape translate(Vector vector);
double getWeight();
double getLength();
}

Wyświetl plik

@ -4,8 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Shapes { public class Shapes {
public static List<Line> generatePolygram(int sides, int angleJump, Vector start, double weight) { public static List<Shape> generatePolygram(int sides, int angleJump, Vector start, double weight) {
List<Line> polygon = new ArrayList<>(); List<Shape> polygon = new ArrayList<>();
double theta = angleJump * 2 * Math.PI / sides; double theta = angleJump * 2 * Math.PI / sides;
@ -22,31 +22,31 @@ public class Shapes {
return polygon; return polygon;
} }
public static List<Line> generatePolygram(int sides, int angleJump, Vector start) { public static List<Shape> generatePolygram(int sides, int angleJump, Vector start) {
return generatePolygram(sides, angleJump, start, Line.DEFAULT_WEIGHT); return generatePolygram(sides, angleJump, start, Line.DEFAULT_WEIGHT);
} }
public static List<Line> generatePolygram(int sides, int angleJump, double scale, double weight) { public static List<Shape> generatePolygram(int sides, int angleJump, double scale, double weight) {
return generatePolygram(sides, angleJump, new Vector(scale, scale), weight); return generatePolygram(sides, angleJump, new Vector(scale, scale), weight);
} }
public static List<Line> generatePolygram(int sides, int angleJump, double scale) { public static List<Shape> generatePolygram(int sides, int angleJump, double scale) {
return generatePolygram(sides, angleJump, new Vector(scale, scale)); return generatePolygram(sides, angleJump, new Vector(scale, scale));
} }
public static List<Line> generatePolygon(int sides, Vector start, double weight) { public static List<Shape> generatePolygon(int sides, Vector start, double weight) {
return generatePolygram(sides, 1, start, weight); return generatePolygram(sides, 1, start, weight);
} }
public static List<Line> generatePolygon(int sides, Vector start) { public static List<Shape> generatePolygon(int sides, Vector start) {
return generatePolygram(sides, 1, start); return generatePolygram(sides, 1, start);
} }
public static List<Line> generatePolygon(int sides, double scale, double weight) { public static List<Shape> generatePolygon(int sides, double scale, double weight) {
return generatePolygon(sides, new Vector(scale, scale), weight); return generatePolygon(sides, new Vector(scale, scale), weight);
} }
public static List<Line> generatePolygon(int sides, double scale) { public static List<Shape> generatePolygon(int sides, double scale) {
return generatePolygon(sides, new Vector(scale, scale)); return generatePolygon(sides, new Vector(scale, scale));
} }