Add more comments and massively clean-up sortLines

pull/35/head
James Ball 2020-10-18 22:45:34 +01:00
rodzic 96d4b6f662
commit d467aab422
2 zmienionych plików z 26 dodań i 24 usunięć

Wyświetl plik

@ -23,14 +23,14 @@ public class AudioClient {
// args:
// args[0] - path of .obj file
// args[1] - focal length of camera
// args[2] - x position of camera
// args[3] - y position of camera
// args[4] - z position of camera
// args[5] - rotation speed of object
// args[1] - rotation speed of object
// args[2] - focal length of camera
// args[3] - x position of camera
// args[4] - y position of camera
// args[5] - z position of camera
//
// example:
// osci-render models/cube.obj 1 0 0 -3 10
// osci-render models/cube.obj 3
public static void main(String[] programArgs) {
// TODO: Calculate weight of lines using depth.
// Reduce weight of lines drawn multiple times.
@ -44,6 +44,8 @@ public class AudioClient {
Vector3 cameraPos = new Vector3(args.cameraX(), args.cameraY(), args.cameraZ());
WorldObject object = new WorldObject(args.objFilePath());
// If camera position arguments haven't been specified, automatically work out the position of
// the camera based on the size of the object in the camera's view.
Camera camera = args.isDefaultPosition() ? new Camera(args.focalLength(), object)
: new Camera(args.focalLength(), cameraPos);
@ -62,6 +64,7 @@ public class AudioClient {
private static List<List<? extends Shape>> preRender(WorldObject object, Vector3 rotation,
Camera camera) {
List<List<? extends Shape>> preRenderedFrames = new ArrayList<>();
// Number of frames it will take to render a full rotation of the object.
int numFrames = (int) (2 * Math.PI / OBJ_ROTATE_SPEED);
for (int i = 0; i < numFrames; i++) {
@ -74,6 +77,8 @@ public class AudioClient {
IntStream.range(0, numFrames).parallel().forEach((frameNum) -> {
WorldObject clone = object.clone();
clone.rotate(rotation.scale(frameNum));
// Finds all lines to draw the object from the camera's view and then 'sorts' them by finding
// a hamiltonian path, which dramatically helps with rendering a clean image.
preRenderedFrames.set(frameNum, Shapes.sortLines(camera.draw(clone)));
int numRendered = renderedFrames.getAndIncrement();

Wyświetl plik

@ -1,11 +1,11 @@
package shapes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.connectivity.ConnectivityInspector;
import org.jgrapht.alg.cycle.ChinesePostman;
import org.jgrapht.graph.AsSubgraph;
@ -68,12 +68,15 @@ public class Shapes {
.orElse(0d);
}
// performs chinese postman on the input lines to get a path that will render cleanly on the oscilloscope.
// Performs chinese postman on the input lines to get a path that will render cleanly on the
// oscilloscope.
// TODO: Speed up.
public static List<Shape> sortLines(List<Line> lines) {
Graph<Vector2, DefaultWeightedEdge> graph = new DefaultUndirectedWeightedGraph<>(
DefaultWeightedEdge.class);
// Add all lines in frame to graph as vertices and edges. Edge weight is determined by the
// length of the line as this is directly proportional to draw time.
for (Line line : lines) {
graph.addVertex(line.getA());
graph.addVertex(line.getB());
@ -88,28 +91,22 @@ public class Shapes {
List<Shape> sortedLines = new ArrayList<>();
// Chinese Postman can only be performed on connected graphs, so iterate over all connected
// sub-graphs.
for (Set<Vector2> vertices : inspector.connectedSets()) {
AsSubgraph<Vector2, DefaultWeightedEdge> subgraph = new AsSubgraph<>(graph, vertices);
ChinesePostman<Vector2, DefaultWeightedEdge> cp = new ChinesePostman<>();
Collection<DefaultWeightedEdge> path;
try {
GraphPath<Vector2, DefaultWeightedEdge> edges = cp.getCPPSolution(subgraph);
Vector2 prevPoint = edges.getStartVertex();
Vector2 firstPoint = edges.getStartVertex();
List<Vector2> path = edges.getVertexList();
for (int i = 1; i < edges.getLength(); i++) {
sortedLines.add(new Line(prevPoint, path.get(i)));
prevPoint = path.get(i);
}
sortedLines.add(new Line(prevPoint, firstPoint));
path = cp.getCPPSolution(subgraph).getEdgeList();
} catch (Exception e) {
for (DefaultWeightedEdge edge : subgraph.edgeSet()) {
sortedLines.add(new Line(subgraph.getEdgeSource(edge), subgraph.getEdgeTarget(edge)));
}
// Safety in case getCPPSolution fails.
path = subgraph.edgeSet();
}
for (DefaultWeightedEdge edge : path) {
sortedLines.add(new Line(subgraph.getEdgeSource(edge), subgraph.getEdgeTarget(edge)));
}
}