Complete bulk of FrameProducer refactor

pull/35/head
James Ball 2021-04-17 00:03:43 +01:00
rodzic cee2b19165
commit 67fb81dea8
12 zmienionych plików z 199 dodań i 136 usunięć

Wyświetl plik

@ -24,6 +24,7 @@
<configuration> <configuration>
<source>15</source> <source>15</source>
<target>15</target> <target>15</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

Wyświetl plik

@ -0,0 +1,5 @@
package sh.ball;
public interface FrameSet<T> {
T next();
}

Wyświetl plik

@ -1,59 +1,35 @@
package sh.ball.audio; package sh.ball.audio;
import sh.ball.Renderer;
import sh.ball.engine.Vector3;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet;
import sh.ball.Renderer;
import java.io.IOException;
import sh.ball.parser.FileParser; import sh.ball.parser.FileParser;
import sh.ball.parser.ObjParser;
import sh.ball.parser.TextParser;
import sh.ball.parser.svg.SvgParser;
import sh.ball.shapes.Shape;
public class FrameProducer implements Runnable { import javax.xml.parsers.ParserConfigurationException;
private final Renderer<List<Shape>> renderer; public class FrameProducer<T> implements Runnable {
private ObjParser objParser; private final Renderer<T> renderer;
private SvgParser svgParser; private final FrameSet<T> frames;
private TextParser textParser;
private FileParser parser;
public FrameProducer(Renderer<List<Shape>> renderer) { private boolean running;
public FrameProducer(Renderer<T> renderer, FileParser<FrameSet<T>> parser) throws IOException, SAXException, ParserConfigurationException {
this.renderer = renderer; this.renderer = renderer;
this.frames = parser.parse();
} }
@Override @Override
public void run() { public void run() {
while (true) { running = true;
renderer.addFrame(parser.nextFrame()); while (running) {
renderer.addFrame(frames.next());
} }
} }
public void setParser(String filePath) public void stop() {
throws IOException, ParserConfigurationException, SAXException { running = false;
if (ObjParser.isObjFile(filePath)) {
objParser = new ObjParser(filePath, 1);
parser = objParser;
} else if (SvgParser.isSvgFile(filePath)) {
svgParser = new SvgParser(filePath);
parser = svgParser;
} else if (TextParser.isTxtFile(filePath)) {
textParser = new TextParser(filePath);
parser = textParser;
} else {
throw new IllegalArgumentException(
"Provided file extension in file " + filePath + " not supported.");
}
}
public void setFocalLength(Double focalLength) {
objParser.setFocalLength(focalLength);
}
public void setCameraPos(Vector3 vector) {
objParser.setCameraPos(vector);
} }
} }

Wyświetl plik

@ -3,13 +3,17 @@ package sh.ball.gui;
import sh.ball.MovableRenderer; import sh.ball.MovableRenderer;
import sh.ball.audio.AudioPlayer; import sh.ball.audio.AudioPlayer;
import sh.ball.audio.FrameProducer; import sh.ball.audio.FrameProducer;
import sh.ball.engine.Vector3;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@ -20,20 +24,28 @@ import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane; import javafx.scene.control.TitledPane;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Stage; import javafx.stage.Stage;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.parser.ObjParser; import sh.ball.parser.obj.ObjParser;
import sh.ball.parser.ParserFactory;
import sh.ball.parser.txt.TextParser;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;
import sh.ball.shapes.Vector2; import sh.ball.shapes.Vector2;
public class Controller implements Initializable { public class Controller implements Initializable {
private static final String DEFAULT_FILE = "src/main/resources/models/cube.obj"; private static final String DEFAULT_FILE = TextParser.class.getResource("/models/cube.obj").getPath();
private final FileChooser fileChooser = new FileChooser(); private final FileChooser fileChooser = new FileChooser();
private final MovableRenderer<List<Shape>, Vector2> renderer = new AudioPlayer(); private final MovableRenderer<List<Shape>, Vector2> renderer = new AudioPlayer();
private final FrameProducer producer = new FrameProducer(renderer); private final ExecutorService executor = Executors.newSingleThreadExecutor();
private FrameProducer<List<Shape>> producer = new FrameProducer<>(
renderer,
ParserFactory.getParser(DEFAULT_FILE).orElseThrow(FileNotFoundException::new)
);
private Stage stage; private Stage stage;
@ -74,52 +86,53 @@ public class Controller implements Initializable {
@FXML @FXML
private TextField cameraZTextField; private TextField cameraZTextField;
public Controller() throws ParserConfigurationException, SAXException, IOException {
}
private Map<Slider, SliderUpdater<Double>> initializeSliderMap() { private Map<Slider, SliderUpdater<Double>> initializeSliderMap() {
return Map.of( return Map.of(
weightSlider, weightSlider,
new SliderUpdater<>(weightLabel::setText, renderer::setQuality), new SliderUpdater<>(weightLabel::setText, renderer::setQuality),
rotateSpeedSlider, rotateSpeedSlider,
new SliderUpdater<>(rotateSpeedLabel::setText, renderer::setRotationSpeed), new SliderUpdater<>(rotateSpeedLabel::setText, renderer::setRotationSpeed),
translationSpeedSlider, translationSpeedSlider,
new SliderUpdater<>(translationSpeedLabel::setText, renderer::setTranslationSpeed), new SliderUpdater<>(translationSpeedLabel::setText, renderer::setTranslationSpeed),
scaleSlider, scaleSlider,
new SliderUpdater<>(scaleLabel::setText, renderer::setScale), new SliderUpdater<>(scaleLabel::setText, renderer::setScale)
focalLengthSlider, // focalLengthSlider,
new SliderUpdater<>(focalLengthLabel::setText, producer::setFocalLength) // new SliderUpdater<>(focalLengthLabel::setText, producer::setFocalLength)
); );
} }
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
chooseFile(new File(DEFAULT_FILE));
Map<Slider, SliderUpdater<Double>> sliders = initializeSliderMap(); Map<Slider, SliderUpdater<Double>> sliders = initializeSliderMap();
for (Slider slider : sliders.keySet()) { for (Slider slider : sliders.keySet()) {
slider.valueProperty().addListener((source, oldValue, newValue) -> slider.valueProperty().addListener((source, oldValue, newValue) ->
sliders.get(slider).update(slider.getValue()) sliders.get(slider).update(slider.getValue())
); );
} }
InvalidationListener translationUpdate = observable -> InvalidationListener translationUpdate = observable ->
renderer.setTranslation(new Vector2( renderer.setTranslation(new Vector2(
tryParse(translationXTextField.getText()), tryParse(translationXTextField.getText()),
tryParse(translationYTextField.getText()) tryParse(translationYTextField.getText())
)); ));
translationXTextField.textProperty().addListener(translationUpdate); translationXTextField.textProperty().addListener(translationUpdate);
translationYTextField.textProperty().addListener(translationUpdate); translationYTextField.textProperty().addListener(translationUpdate);
InvalidationListener cameraPosUpdate = observable -> // InvalidationListener cameraPosUpdate = observable ->
producer.setCameraPos(new Vector3( // producer.setCameraPos(new Vector3(
tryParse(cameraXTextField.getText()), // tryParse(cameraXTextField.getText()),
tryParse(cameraYTextField.getText()), // tryParse(cameraYTextField.getText()),
tryParse(cameraZTextField.getText()) // tryParse(cameraZTextField.getText())
)); // ));
//
cameraXTextField.textProperty().addListener(cameraPosUpdate); // cameraXTextField.textProperty().addListener(cameraPosUpdate);
cameraYTextField.textProperty().addListener(cameraPosUpdate); // cameraYTextField.textProperty().addListener(cameraPosUpdate);
cameraZTextField.textProperty().addListener(cameraPosUpdate); // cameraZTextField.textProperty().addListener(cameraPosUpdate);
chooseFileButton.setOnAction(e -> { chooseFileButton.setOnAction(e -> {
File file = null; File file = null;
@ -129,7 +142,7 @@ public class Controller implements Initializable {
chooseFile(file); chooseFile(file);
}); });
new Thread(producer).start(); executor.submit(producer);
new Thread(renderer).start(); new Thread(renderer).start();
} }
@ -143,8 +156,15 @@ public class Controller implements Initializable {
private void chooseFile(File file) { private void chooseFile(File file) {
try { try {
producer.stop();
String path = file.getAbsolutePath(); String path = file.getAbsolutePath();
producer.setParser(path); producer = new FrameProducer<>(
renderer,
ParserFactory.getParser(path)
.orElseThrow(FileNotFoundException::new)
);
executor.submit(producer);
if (file.exists() && !file.isDirectory()) { if (file.exists() && !file.isDirectory()) {
fileLabel.setText(path); fileLabel.setText(path);
objTitledPane.setDisable(!ObjParser.isObjFile(path)); objTitledPane.setDisable(!ObjParser.isObjFile(path));

Wyświetl plik

@ -6,7 +6,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;
public abstract class FileParser { public abstract class FileParser<T> {
public abstract String getFileExtension(); public abstract String getFileExtension();
@ -21,9 +21,8 @@ public abstract class FileParser {
return path.matches(".*\\." + getFileExtension()); return path.matches(".*\\." + getFileExtension());
} }
protected abstract void parseFile(String path) public abstract T parse()
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException; throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException;
public abstract List<Shape> nextFrame();
public abstract String getFilePath(); public abstract String getFilePath();
} }

Wyświetl plik

@ -0,0 +1,28 @@
package sh.ball.parser;
import org.xml.sax.SAXException;
import sh.ball.FrameSet;
import sh.ball.parser.obj.ObjParser;
import sh.ball.parser.svg.SvgParser;
import sh.ball.parser.txt.TextParser;
import sh.ball.shapes.Shape;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
public class ParserFactory {
public static Optional<FileParser<FrameSet<List<Shape>>>> getParser(String filePath) throws IOException, ParserConfigurationException, SAXException {
if (ObjParser.isObjFile(filePath)) {
return Optional.of(new ObjParser(filePath, 1));
} else if (SvgParser.isSvgFile(filePath)) {
return Optional.of(new SvgParser(filePath));
} else if (TextParser.isTxtFile(filePath)) {
return Optional.of(new TextParser(filePath));
}
return Optional.empty();
}
}

Wyświetl plik

@ -0,0 +1,20 @@
package sh.ball.parser;
import sh.ball.FrameSet;
import sh.ball.shapes.Shape;
import java.util.List;
public class ShapeFrameSet implements FrameSet<List<Shape>> {
private final List<Shape> shapes;
public ShapeFrameSet(List<Shape> shapes) {
this.shapes = shapes;
}
@Override
public List<Shape> next() {
return shapes;
}
}

Wyświetl plik

@ -0,0 +1,28 @@
package sh.ball.parser.obj;
import sh.ball.FrameSet;
import sh.ball.engine.Camera;
import sh.ball.engine.Vector3;
import sh.ball.engine.WorldObject;
import sh.ball.shapes.Shape;
import java.util.List;
public class ObjFrameSet implements FrameSet<List<Shape>> {
private final WorldObject object;
private final Camera camera;
private final Vector3 rotation;
public ObjFrameSet(WorldObject object, Camera camera, Vector3 rotation) {
this.object = object;
this.camera = camera;
this.rotation = rotation;
}
@Override
public List<Shape> next() {
object.rotate(rotation);
return camera.draw(object);
}
}

Wyświetl plik

@ -1,35 +1,35 @@
package sh.ball.parser; package sh.ball.parser.obj;
import sh.ball.FrameSet;
import sh.ball.engine.Camera; import sh.ball.engine.Camera;
import sh.ball.engine.Vector3; import sh.ball.engine.Vector3;
import sh.ball.engine.WorldObject; import sh.ball.engine.WorldObject;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import sh.ball.parser.FileParser;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;
public class ObjParser extends FileParser { public class ObjParser extends FileParser<FrameSet<List<Shape>>> {
private static final float DEFAULT_ROTATE_SPEED = 3; private static final float DEFAULT_ROTATE_SPEED = 3;
private final Vector3 cameraPos;
private final Vector3 rotation; private final Vector3 rotation;
private final boolean isDefaultPosition; private final boolean isDefaultPosition;
private final String filePath; private final String filePath;
private final Camera camera;
private WorldObject object; private WorldObject object;
private Camera camera;
private double focalLength;
public ObjParser(String path, float rotateSpeed, float cameraX, float cameraY, float cameraZ, public ObjParser(String path, float rotateSpeed, float cameraX, float cameraY, float cameraZ,
float focalLength, boolean isDefaultPosition) throws IOException { float focalLength, boolean isDefaultPosition) {
rotateSpeed *= Math.PI / 1000; rotateSpeed *= Math.PI / 1000;
checkFileExtension(path); checkFileExtension(path);
this.filePath = path; this.filePath = path;
this.cameraPos = new Vector3(cameraX, cameraY, cameraZ);
this.isDefaultPosition = isDefaultPosition; this.isDefaultPosition = isDefaultPosition;
this.focalLength = focalLength; Vector3 cameraPos = new Vector3(cameraX, cameraY, cameraZ);
this.camera = new Camera(focalLength, cameraPos);
this.rotation = new Vector3(0, rotateSpeed, rotateSpeed); this.rotation = new Vector3(0, rotateSpeed, rotateSpeed);
parseFile(path);
} }
public ObjParser(String path, float focalLength) throws IOException { public ObjParser(String path, float focalLength) throws IOException {
@ -42,19 +42,14 @@ public class ObjParser extends FileParser {
} }
@Override @Override
protected void parseFile(String path) throws IllegalArgumentException, IOException { public FrameSet<List<Shape>> parse() throws IllegalArgumentException, IOException {
object = new WorldObject(path); object = new WorldObject(filePath);
camera = new Camera(focalLength, cameraPos);
if (isDefaultPosition) { if (isDefaultPosition) {
camera.findZPos(object); camera.findZPos(object);
} }
}
@Override return new ObjFrameSet(object, camera, rotation);
public List<Shape> nextFrame() {
object.rotate(rotation);
return camera.draw(object);
} }
@Override @Override

Wyświetl plik

@ -19,27 +19,26 @@ import org.jsoup.Jsoup;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet;
import sh.ball.parser.FileParser; import sh.ball.parser.FileParser;
import sh.ball.parser.ShapeFrameSet;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;
import sh.ball.shapes.Vector2; import sh.ball.shapes.Vector2;
public class SvgParser extends FileParser { public class SvgParser extends FileParser<FrameSet<List<Shape>>> {
private final Map<Character, Function<List<Float>, List<Shape>>> commandMap; private final Map<Character, Function<List<Float>, List<Shape>>> commandMap;
private final SvgState state; private final SvgState state;
private final String filePath; private final String filePath;
private List<Shape> shapes;
private Document svg; private Document svg;
public SvgParser(String path) throws IOException, SAXException, ParserConfigurationException { public SvgParser(String path) {
checkFileExtension(path); checkFileExtension(path);
this.filePath = path; this.filePath = path;
this.shapes = new ArrayList<>();
this.state = new SvgState(); this.state = new SvgState();
this.commandMap = new HashMap<>(); this.commandMap = new HashMap<>();
initialiseCommandMap(); initialiseCommandMap();
parseFile(path);
} }
// Map command chars to function calls. // Map command chars to function calls.
@ -118,10 +117,11 @@ public class SvgParser extends FileParser {
} }
@Override @Override
protected void parseFile(String filePath) public FrameSet<List<Shape>> parse()
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException { throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException {
this.svg = getXMLDocument(filePath); this.svg = getXMLDocument(filePath);
List<Node> svgElem = asList(svg.getElementsByTagName("svg")); List<Node> svgElem = asList(svg.getElementsByTagName("svg"));
List<Shape> shapes = new ArrayList<>();
if (svgElem.size() != 1) { if (svgElem.size() != 1) {
throw new IllegalArgumentException("SVG has either zero or more than one svg element."); throw new IllegalArgumentException("SVG has either zero or more than one svg element.");
@ -132,7 +132,7 @@ public class SvgParser extends FileParser {
shapes.addAll(parsePath(node.getNodeValue())); shapes.addAll(parsePath(node.getNodeValue()));
} }
shapes = Shape.normalize(shapes); return new ShapeFrameSet(Shape.normalize(shapes));
} }
/* Given a character, will return the glyph associated with it. /* Given a character, will return the glyph associated with it.
@ -196,11 +196,6 @@ public class SvgParser extends FileParser {
return svgShapes; return svgShapes;
} }
@Override
public List<Shape> nextFrame() {
return shapes;
}
@Override @Override
public String getFilePath() { public String getFilePath() {
return filePath; return filePath;

Wyświetl plik

@ -1,4 +1,4 @@
package sh.ball.parser; package sh.ball.parser.txt;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -11,34 +11,31 @@ import java.util.Map;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet;
import sh.ball.parser.FileParser;
import sh.ball.parser.ShapeFrameSet;
import sh.ball.parser.svg.SvgParser; import sh.ball.parser.svg.SvgParser;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;
import sh.ball.shapes.Vector2; import sh.ball.shapes.Vector2;
public class TextParser extends FileParser { public class TextParser extends FileParser<FrameSet<List<Shape>>> {
private static final char WIDE_CHAR = 'W'; private static final char WIDE_CHAR = 'W';
private static final double HEIGHT_SCALAR = 1.6; private static final double HEIGHT_SCALAR = 1.6;
private static final String DEFAULT_FONT = TextParser.class.getResource("/fonts/SourceCodePro-ExtraLight.svg").getPath(); private static final String DEFAULT_FONT = TextParser.class.getResource("/fonts/SourceCodePro-ExtraLight.svg").getPath();
private final Map<Character, List<Shape>> charToShape; private final Map<Character, List<Shape>> charToShape;
private final List<String> text;
private final String filePath; private final String filePath;
private final String fontPath;
private List<Shape> shapes; public TextParser(String path, String font) {
public TextParser(String path, String font)
throws IOException, SAXException, ParserConfigurationException {
checkFileExtension(path); checkFileExtension(path);
this.filePath = path; this.filePath = path;
this.fontPath = font;
this.charToShape = new HashMap<>(); this.charToShape = new HashMap<>();
this.shapes = new ArrayList<>();
this.text = Files.readAllLines(Paths.get(path), Charset.defaultCharset());
parseFile(font);
} }
public TextParser(String path) public TextParser(String path) {
throws IOException, SAXException, ParserConfigurationException {
this(path, DEFAULT_FONT); this(path, DEFAULT_FONT);
} }
@ -48,9 +45,11 @@ public class TextParser extends FileParser {
} }
@Override @Override
protected void parseFile(String path) public FrameSet<List<Shape>> parse() throws IllegalArgumentException, IOException, ParserConfigurationException, SAXException {
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException { List<String> text = Files.readAllLines(Paths.get(filePath), Charset.defaultCharset());
SvgParser parser = new SvgParser(path); SvgParser parser = new SvgParser(fontPath);
parser.parse();
List<Shape> shapes = new ArrayList<>();
/* WIDE_CHAR used as an example character that will be wide in most languages. /* WIDE_CHAR used as an example character that will be wide in most languages.
* This helps determine the correct character width for the font chosen. */ * This helps determine the correct character width for the font chosen. */
@ -78,12 +77,7 @@ public class TextParser extends FileParser {
} }
} }
shapes = Shape.flip(Shape.normalize(shapes)); return new ShapeFrameSet(Shape.flip(Shape.normalize(shapes)));
}
@Override
public List<Shape> nextFrame() {
return shapes;
} }
@Override @Override

Wyświetl plik

@ -4,11 +4,13 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test; import org.junit.Test;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.parser.svg.SvgParser; import sh.ball.parser.svg.SvgParser;
import sh.ball.shapes.Line; import sh.ball.shapes.Line;
import sh.ball.shapes.Shape;
import sh.ball.util.ClassLoaderUtil; import sh.ball.util.ClassLoaderUtil;
public class SvgParserTest { public class SvgParserTest {
@ -20,28 +22,28 @@ public class SvgParserTest {
@Test @Test
public void lineToGeneratesALineShape() public void lineToGeneratesALineShape()
throws ParserConfigurationException, SAXException, IOException, URISyntaxException { throws ParserConfigurationException, SAXException, IOException, URISyntaxException {
SvgParser svgParser = new SvgParser(getResource("images/line-to.svg")); FrameSet<List<Shape>> frames = new SvgParser(getResource("images/line-to.svg")).parse();
assertEquals(svgParser.nextFrame(), Line.pathToLines(0.5, 0.5, 0.75, 1, 0, 0, 0.5, 0.5)); assertEquals(frames.next(), Line.pathToLines(0.5, 0.5, 0.75, 1, 0, 0, 0.5, 0.5));
} }
@Test @Test
public void horizontalLineToGeneratesAHorizontalLineShape() public void horizontalLineToGeneratesAHorizontalLineShape()
throws ParserConfigurationException, SAXException, IOException, URISyntaxException { throws ParserConfigurationException, SAXException, IOException, URISyntaxException {
SvgParser svgParser = new SvgParser(getResource("images/horizontal-line-to.svg")); FrameSet<List<Shape>> frames = new SvgParser(getResource("images/horizontal-line-to.svg")).parse();
assertEquals(svgParser.nextFrame(), Line.pathToLines(0.5, 0.5, 0.75, 0.5, 0, 0.5, 0.5, 0.5)); assertEquals(frames.next(), Line.pathToLines(0.5, 0.5, 0.75, 0.5, 0, 0.5, 0.5, 0.5));
} }
@Test @Test
public void verticalLineToGeneratesAVerticalLineShape() public void verticalLineToGeneratesAVerticalLineShape()
throws ParserConfigurationException, SAXException, IOException, URISyntaxException { throws ParserConfigurationException, SAXException, IOException, URISyntaxException {
SvgParser svgParser = new SvgParser(getResource("images/vertical-line-to.svg")); FrameSet<List<Shape>> frames = new SvgParser(getResource("images/vertical-line-to.svg")).parse();
assertEquals(svgParser.nextFrame(), Line.pathToLines(0.5, 0.5, 0.5, 0.75, 0.5, 0, 0.5, 0.5)); assertEquals(frames.next(), Line.pathToLines(0.5, 0.5, 0.5, 0.75, 0.5, 0, 0.5, 0.5));
} }
@Test @Test
public void closingASubPathDrawsLineToInitialPoint() public void closingASubPathDrawsLineToInitialPoint()
throws ParserConfigurationException, SAXException, IOException, URISyntaxException { throws ParserConfigurationException, SAXException, IOException, URISyntaxException {
SvgParser svgParser = new SvgParser(getResource("images/closing-subpath.svg")); FrameSet<List<Shape>> frames = new SvgParser(getResource("images/closing-subpath.svg")).parse();
assertEquals(svgParser.nextFrame(), Line.pathToLines(0.5, 0.5, 0.75, 0.5, 0.75, 0.75, 0.5, 0.75, 0.5, 0.5)); assertEquals(frames.next(), Line.pathToLines(0.5, 0.5, 0.75, 0.5, 0.75, 0.75, 0.5, 0.75, 0.5, 0.5));
} }
} }