diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java
index 103369a8b..765ac73ea 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java
@@ -57,8 +57,13 @@ public class GraphicMinMax implements Graphic {
@Override
public void drawPolygon(Polygon p, Style style) {
- for (VectorInterface v : p)
- check(v);
+ for (Polygon.PathElement v : p) {
+ if (v==null)
+ System.out.println(v);
+ final VectorInterface point = v.getPoint();
+ if (point != null)
+ check(point);
+ }
}
@Override
diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java
index 95202874b..e32011a46 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java
@@ -113,22 +113,11 @@ public class GraphicSVG implements Graphic {
@Override
public void drawPolygon(Polygon p, Style style) {
try {
- //modification of loop variable i is intended!
- //CHECKSTYLE.OFF: ModifiedControlVariable
- w.write("\n");
else
diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java
index b051fbb57..638b970b1 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java
@@ -64,25 +64,7 @@ public class GraphicSwing implements Graphic {
public void drawPolygon(Polygon p, Style style) {
applyStyle(style);
Path2D path = new GeneralPath();
- //modification of loop variable i is intended!
- //CHECKSTYLE.OFF: ModifiedControlVariable
- for (int i = 0; i < p.size(); i++) {
- if (i == 0) {
- path.moveTo(p.get(i).getXFloat(), p.get(i).getYFloat());
- } else {
- if (p.isBezierStart(i)) {
- path.curveTo(p.get(i).getXFloat(), p.get(i).getYFloat(),
- p.get(i + 1).getXFloat(), p.get(i + 1).getYFloat(),
- p.get(i + 2).getXFloat(), p.get(i + 2).getYFloat());
- i += 2;
- } else
- path.lineTo(p.get(i).getXFloat(), p.get(i).getYFloat());
- }
- }
- //CHECKSTYLE.ON: ModifiedControlVariable
-
- if (p.isClosed())
- path.closePath();
+ p.drawTo(path);
if (style.isFilled() && p.isClosed())
gr.fill(path);
diff --git a/src/main/java/de/neemann/digital/draw/graphics/Polygon.java b/src/main/java/de/neemann/digital/draw/graphics/Polygon.java
index ac8465daf..5e4253475 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/Polygon.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/Polygon.java
@@ -5,18 +5,19 @@
*/
package de.neemann.digital.draw.graphics;
+import java.awt.geom.Path2D;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.Iterator;
/**
* A polygon representation used by the {@link Graphic} interface.
*/
-public class Polygon implements Iterable {
+public class Polygon implements Iterable {
- private final ArrayList points;
- private final HashSet isBezierStart;
+ private final ArrayList path;
private boolean closed;
+ private boolean hasSpecialElements = false;
+ private boolean evenOdd;
/**
* Creates e new closed polygon
@@ -41,9 +42,10 @@ public class Polygon implements Iterable {
* @param closed true if polygon is closed
*/
public Polygon(ArrayList points, boolean closed) {
- this.points = points;
this.closed = closed;
- isBezierStart = new HashSet<>();
+ this.path = new ArrayList<>();
+ for (VectorInterface p : points)
+ add(p);
}
/**
@@ -71,10 +73,17 @@ public class Polygon implements Iterable {
* @return this for chained calls
*/
public Polygon add(VectorInterface p) {
- points.add(p);
+ if (path.isEmpty())
+ path.add(new MoveTo(p));
+ else
+ path.add(new LineTo(p));
return this;
}
+ private void add(PathElement pe) {
+ path.add(pe);
+ }
+
/**
* Adds a new cubic bezier curve to the polygon.
*
@@ -84,45 +93,29 @@ public class Polygon implements Iterable {
* @return this for chained calls
*/
public Polygon add(VectorInterface c1, VectorInterface c2, VectorInterface p) {
- if (points.size() == 0)
+ if (path.size() == 0)
throw new RuntimeException("cubic bezier curve is not allowed to be the first path element");
- isBezierStart.add(points.size());
- points.add(c1);
- points.add(c2);
- points.add(p);
+ path.add(new CurveTo(c1, c2, p));
+ hasSpecialElements = true;
return this;
}
/**
- * Returns true if the point with the given index is a bezier start point
- *
- * @param n the index
- * @return true if point is bezier start
+ * @return true if filled in even odd mode
*/
- public boolean isBezierStart(int n) {
- return isBezierStart.contains(n);
+ public boolean getEvenOdd() {
+ return evenOdd;
}
/**
- * @return the number of points
- */
- public int size() {
- return points.size();
- }
-
- /**
- * Returns one of the points
+ * Sets the even odd mode used to fill the polygon
*
- * @param i the index
- * @return the i'th point
+ * @param evenOdd true is even odd mode is needed
+ * @return this for chained calls
*/
- public VectorInterface get(int i) {
- return points.get(i);
- }
-
- @Override
- public Iterator iterator() {
- return points.iterator();
+ public Polygon setEvenOdd(boolean evenOdd) {
+ this.evenOdd = evenOdd;
+ return this;
}
/**
@@ -140,28 +133,43 @@ public class Polygon implements Iterable {
}
private boolean check(VectorInterface p1, VectorInterface p2) {
+ if (closed)
+ return false;
+
if (p1.equals(getFirst())) {
- points.add(0, p2);
+ if (p2.equals(getLast()))
+ closed = true;
+ else {
+ removeInitialMoveTo();
+ path.add(0, new MoveTo(p2));
+ }
return true;
} else if (p1.equals(getLast())) {
- points.add(p2);
+ if (p2.equals(getFirst()))
+ closed = true;
+ else
+ path.add(new LineTo(p2));
return true;
} else
return false;
}
+ private void removeInitialMoveTo() {
+ path.set(0, new LineTo(path.get(0)));
+ }
+
/**
* @return the first point of the polygon
*/
public VectorInterface getFirst() {
- return points.get(0);
+ return path.get(0).getPoint();
}
/**
* @return the last point of the polygon
*/
public VectorInterface getLast() {
- return points.get(points.size() - 1);
+ return path.get(path.size() - 1).getPoint();
}
/**
@@ -171,10 +179,17 @@ public class Polygon implements Iterable {
* @return this for chained calls
*/
public Polygon append(Polygon p2) {
- if (!p2.isBezierStart.isEmpty())
+ if (hasSpecialElements || p2.hasSpecialElements)
throw new RuntimeException("append of bezier not supported");
- for (int i = 1; i < p2.points.size(); i++)
- points.add(p2.points.get(i));
+
+ if (p2.getLast().equals(getFirst())) {
+ for (int i = 1; i < p2.path.size() - 1; i++)
+ add(p2.path.get(i).getPoint());
+ closed = true;
+ } else {
+ for (int i = 1; i < p2.path.size(); i++)
+ add(p2.path.get(i).getPoint());
+ }
return this;
}
@@ -184,11 +199,11 @@ public class Polygon implements Iterable {
* @return returns this polygon with reverse order of points
*/
public Polygon reverse() {
- if (!isBezierStart.isEmpty())
- throw new RuntimeException("reverse of bezier not supported");
+ if (hasSpecialElements)
+ throw new RuntimeException("append of bezier not supported");
Polygon p = new Polygon(closed);
- for (int i = points.size() - 1; i >= 0; i--)
- p.add(points.get(i));
+ for (int i = path.size() - 1; i >= 0; i--)
+ p.add(path.get(i).getPoint());
return p;
}
@@ -202,43 +217,24 @@ public class Polygon implements Iterable {
if (transform == Transform.IDENTITY)
return this;
- Polygon p = new Polygon(closed);
- for (VectorInterface v : points)
- p.add(v.transform(transform));
- p.isBezierStart.addAll(isBezierStart);
+ Polygon p = new Polygon(closed).setEvenOdd(evenOdd);
+ for (PathElement pe : path)
+ p.add(pe.transform(transform));
return p;
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("M ");
- VectorInterface v = points.get(0);
- sb.append(str(v.getXFloat())).append(",").append(str(v.getYFloat())).append(" ");
- //modification of loop variable i is intended!
- //CHECKSTYLE.OFF: ModifiedControlVariable
- for (int i = 1; i < points.size(); i++) {
- v = points.get(i);
- if (isBezierStart.contains(i)) {
- sb.append("C ").append(str(v.getXFloat())).append(",").append(str(v.getYFloat())).append(" ");
- v = points.get(i + 1);
- sb.append(str(v.getXFloat())).append(",").append(str(v.getYFloat())).append(" ");
- v = points.get(i + 2);
- sb.append(str(v.getXFloat())).append(",").append(str(v.getYFloat())).append(" ");
- i += 2;
- } else
- sb.append("L ").append(str(v.getXFloat())).append(",").append(str(v.getYFloat())).append(" ");
+ StringBuilder sb = new StringBuilder();
+ for (PathElement pe : path) {
+ if (sb.length() > 0)
+ sb.append(' ');
+ sb.append(pe.toString());
}
- //CHECKSTYLE.ON: ModifiedControlVariable
- if (closed)
- sb.append("z");
- return sb.toString();
- }
- private static String str(float f) {
- if (f == Math.round(f))
- return Integer.toString(Math.round(f));
- else
- return Float.toString(f);
+ if (closed)
+ sb.append(" Z");
+ return sb.toString();
}
/**
@@ -258,4 +254,191 @@ public class Polygon implements Iterable {
void setClosed(boolean closed) {
this.closed = closed;
}
+
+ @Override
+ public Iterator iterator() {
+ return path.iterator();
+ }
+
+ /**
+ * Closes the actual path
+ */
+ public void addClosePath() {
+ add(new ClosePath());
+ }
+
+ /**
+ * Adds a moveto to the path
+ *
+ * @param p the point to move to
+ */
+ public void addMoveTo(VectorFloat p) {
+ add(new MoveTo(p));
+ }
+
+ /**
+ * Draw this polygon to a {@link Path2D} instance.
+ *
+ * @param path2d the Path2d instance.
+ */
+ public void drawTo(Path2D path2d) {
+ for (PathElement pe : path)
+ pe.drawTo(path2d);
+ if (closed)
+ path2d.closePath();
+ if (evenOdd)
+ path2d.setWindingRule(Path2D.WIND_EVEN_ODD);
+ }
+
+ /**
+ * A element of the path
+ */
+ public interface PathElement {
+ /**
+ * @return the coordinate of this path element
+ */
+ VectorInterface getPoint();
+
+ /**
+ * Returns the transormated path element
+ *
+ * @param transform the transformation
+ * @return the transormated path element
+ */
+ PathElement transform(Transform transform);
+
+ /**
+ * Draws this path element to a Path2D instance.
+ *
+ * @param path2d the a Path2D instance
+ */
+ void drawTo(Path2D path2d);
+ }
+
+ private static String str(float f) {
+ if (f == Math.round(f))
+ return Integer.toString(Math.round(f));
+ else
+ return Float.toString(f);
+ }
+
+ private static String str(VectorInterface p) {
+ return str(p.getXFloat()) + "," + str(p.getYFloat());
+ }
+
+ //LineTo can not be final because its overridden. Maybe checkstyle has a bug?
+ //CHECKSTYLE.OFF: FinalClass
+ private static class LineTo implements PathElement {
+ protected final VectorInterface p;
+
+ private LineTo(VectorInterface p) {
+ this.p = p;
+ }
+
+ private LineTo(PathElement pathElement) {
+ this(pathElement.getPoint());
+ }
+
+ @Override
+ public VectorInterface getPoint() {
+ return p;
+ }
+
+ @Override
+ public PathElement transform(Transform transform) {
+ return new LineTo(p.transform(transform));
+ }
+
+ @Override
+ public void drawTo(Path2D path2d) {
+ path2d.lineTo(p.getXFloat(), p.getYFloat());
+ }
+
+ @Override
+ public String toString() {
+ return "L " + str(p);
+ }
+ }
+ //CHECKSTYLE.ON: FinalClass
+
+ private static final class MoveTo extends LineTo {
+ private MoveTo(VectorInterface p) {
+ super(p);
+ }
+
+ @Override
+ public String toString() {
+ return "M " + str(p);
+ }
+
+ @Override
+ public void drawTo(Path2D path2d) {
+ path2d.moveTo(p.getXFloat(), p.getYFloat());
+ }
+
+ @Override
+ public PathElement transform(Transform transform) {
+ return new MoveTo(p.transform(transform));
+ }
+ }
+
+ private static final class CurveTo implements PathElement {
+ private final VectorInterface c1;
+ private final VectorInterface c2;
+ private final VectorInterface p;
+
+ private CurveTo(VectorInterface c1, VectorInterface c2, VectorInterface p) {
+ this.c1 = c1;
+ this.c2 = c2;
+ this.p = p;
+ }
+
+ @Override
+ public VectorInterface getPoint() {
+ return p;
+ }
+
+ @Override
+ public PathElement transform(Transform transform) {
+ return new CurveTo(
+ c1.transform(transform),
+ c2.transform(transform),
+ p.transform(transform)
+ );
+ }
+
+ @Override
+ public String toString() {
+ return "C " + str(c1) + " " + str(c2) + " " + str(p);
+ }
+
+ @Override
+ public void drawTo(Path2D path2d) {
+ path2d.curveTo(c1.getXFloat(), c1.getYFloat(),
+ c2.getXFloat(), c2.getYFloat(),
+ p.getXFloat(), p.getYFloat());
+ }
+ }
+
+ private class ClosePath implements PathElement {
+ @Override
+ public VectorInterface getPoint() {
+ return null;
+ }
+
+ @Override
+ public PathElement transform(Transform transform) {
+ return this;
+ }
+
+ @Override
+ public void drawTo(Path2D path2d) {
+ path2d.closePath();
+ }
+
+ @Override
+ public String toString() {
+ return "Z";
+ }
+ }
}
diff --git a/src/main/java/de/neemann/digital/draw/graphics/PolygonConverter.java b/src/main/java/de/neemann/digital/draw/graphics/PolygonConverter.java
index 35a15b72f..772705f8c 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/PolygonConverter.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/PolygonConverter.java
@@ -25,12 +25,17 @@ public class PolygonConverter implements Converter {
public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) {
Polygon p = (Polygon) o;
writer.addAttribute("path", p.toString());
+ writer.addAttribute("evenOdd", Boolean.toString(p.getEvenOdd()));
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext unmarshallingContext) {
String path = reader.getAttribute("path");
- return Polygon.createFromPath(path);
+ boolean evenOdd = Boolean.parseBoolean(reader.getAttribute("evenOdd"));
+ final Polygon polygon = Polygon.createFromPath(path);
+ if (polygon != null)
+ polygon.setEvenOdd(evenOdd);
+ return polygon;
}
}
diff --git a/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java b/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
index da4a49117..3c45be139 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
@@ -117,6 +117,7 @@ public class PolygonParser {
public Polygon create() throws ParserException {
Polygon p = new Polygon(false);
Token tok;
+ boolean closedPending = false;
while ((tok = next()) != Token.EOF) {
if (tok == Token.NUMBER) {
unreadToken();
@@ -127,11 +128,19 @@ public class PolygonParser {
}
switch (command) {
case 'M':
- p.add(nextVector());
+ if (closedPending) {
+ closedPending = false;
+ p.addClosePath();
+ }
+ p.addMoveTo(nextVector());
clearControl();
break;
case 'm':
- p.add(nextVectorInc());
+ if (closedPending) {
+ closedPending = false;
+ p.addClosePath();
+ }
+ p.addMoveTo(nextVectorInc());
clearControl();
break;
case 'V':
@@ -196,13 +205,15 @@ public class PolygonParser {
break;
case 'Z':
case 'z':
- p.setClosed(true);
+ closedPending = true;
clearControl();
break;
default:
throw new ParserException("unsupported path command " + command);
}
}
+ if (closedPending)
+ p.setClosed(true);
return p;
}
diff --git a/src/main/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollector.java b/src/main/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollector.java
index 28a79c770..470305095 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollector.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollector.java
@@ -75,7 +75,7 @@ public class GraphicLineCollector implements Graphic {
private void tryMerge(Polygon p1) {
for (Polygon p2 : polyList)
- if (p1 != p2) {
+ if (p1 != p2 && !p1.isClosed() && !p2.isClosed()) {
if (p1.getLast().equals(p2.getFirst())) {
p1.append(p2);
polyList.remove(p2);
diff --git a/src/test/java/de/neemann/digital/draw/graphics/PolygonTest.java b/src/test/java/de/neemann/digital/draw/graphics/PolygonTest.java
index 03c52bba9..bfc64feb2 100644
--- a/src/test/java/de/neemann/digital/draw/graphics/PolygonTest.java
+++ b/src/test/java/de/neemann/digital/draw/graphics/PolygonTest.java
@@ -10,42 +10,46 @@ import junit.framework.TestCase;
public class PolygonTest extends TestCase {
public void testPath() {
- checkLine(Polygon.createFromPath("m 10,10 L 20,10 20,20 10,20 z"));
- checkLine(Polygon.createFromPath("m 10,10 l 10,0 0,10 -10,0 z"));
- checkLine(Polygon.createFromPath("m 10,10 h 10 v 10 h -10 z"));
- checkLine(Polygon.createFromPath("m 10,10 H 20 V 20 H 10 z"));
+ checkLine(Polygon.createFromPath("m 10,10 L 20,10 20,20 10,20 Z"));
+ checkLine(Polygon.createFromPath("m 10,10 l 10,0 0,10 -10,0 Z"));
+ checkLine(Polygon.createFromPath("m 10,10 h 10 v 10 h -10 Z"));
+ checkLine(Polygon.createFromPath("m 10,10 H 20 V 20 H 10 Z"));
}
private void checkLine(Polygon p) {
- checkCoor(p);
- assertEquals("M 10,10 L 20,10 L 20,20 L 10,20 z", p.toString());
- }
-
- private void checkCoor(Polygon p) {
- assertEquals(4, p.size());
- assertEquals(new VectorFloat(10, 10), p.get(0));
- assertEquals(new VectorFloat(20, 10), p.get(1));
- assertEquals(new VectorFloat(20, 20), p.get(2));
- assertEquals(new VectorFloat(10, 20), p.get(3));
+ assertNotNull(p);
+ assertEquals("M 10,10 L 20,10 L 20,20 L 10,20 Z", p.toString());
}
private void checkBezier(Polygon p) {
- checkCoor(p);
- assertEquals("M 10,10 C 20,10 20,20 10,20 z", p.toString());
+ assertEquals("M 10,10 C 20,10 20,20 10,20 Z", p.toString());
}
public void testBezierPath() {
- checkBezier(Polygon.createFromPath("m 10,10 C 20 10 20 20 10 20 z"));
- checkBezier(Polygon.createFromPath("m 10,10 c 10 0 10 10 0 10 z"));
+ checkBezier(Polygon.createFromPath("m 10,10 C 20 10 20 20 10 20 Z"));
+ checkBezier(Polygon.createFromPath("m 10,10 c 10 0 10 10 0 10 Z"));
}
public void testCubicReflect() {
- assertEquals("M 0,0 C 0,10 10,10 10,0 C 10,-10 20,-10 20,0 C 20,10 30,10 30,0 z",
- Polygon.createFromPath("m 0,0 c 0,10 10,10 10,0 s 10,-10 10,0 s 10,10 10,0 z").toString());
+ assertEquals("M 0,0 C 0,10 10,10 10,0 C 10,-10 20,-10 20,0 C 20,10 30,10 30,0 Z",
+ Polygon.createFromPath("m 0,0 c 0,10 10,10 10,0 s 10,-10 10,0 s 10,10 10,0 Z").toString());
}
public void testQuadraticReflect() {
- assertEquals("M 0,0 C 20,20 40,20 60,0 C 80,-20 100,-20 120,0 C 140,20 160,20 180,0 C 200,-20 220,-20 240,0 ",
+ assertEquals("M 0,0 C 20,20 40,20 60,0 C 80,-20 100,-20 120,0 C 140,20 160,20 180,0 C 200,-20 220,-20 240,0",
Polygon.createFromPath("m 0,0 Q 30,30 60,0 t 60,0 t 60,0 t 60,0").toString());
}
+
+ public void testMultiPath() {
+ assertEquals("M 0,0 C 0,40 20,60 60,60 C 100,60 120,40 120,0 C 120,-40 100,-60 60,-60 C 20,-60 0,-40 0,0 Z M 30,0 C 30,20 40,30 60,30 C 80,30 90,20 90,0 C 90,-20 80,-30 60,-30 C 40,-30 30,-20 30,0 Z",
+ Polygon.createFromPath("M 0,0 Q 0,60 60,60 T 120,0 T 60,-60 T 0,0 z M 30,0 Q 30,30 60,30 T 90,0 T 60,-30 T 30,0 Z").toString());
+ }
+
+ public void testAppend() {
+ Polygon p1 = new Polygon(false).add(0, 0).add(0, 10).add(10, 10);
+ Polygon p2 = new Polygon(false).add(10, 10).add(10, 0).add(0, 0);
+
+ assertEquals("M 0,0 L 0,10 L 10,10 L 10,0 Z", p1.append(p2).toString());
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollectorTest.java b/src/test/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollectorTest.java
new file mode 100644
index 000000000..4c174b3fd
--- /dev/null
+++ b/src/test/java/de/neemann/digital/draw/graphics/linemerger/GraphicLineCollectorTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Helmut Neemann
+ * Use of this source code is governed by the GPL v3 license
+ * that can be found in the LICENSE file.
+ */
+package de.neemann.digital.draw.graphics.linemerger;
+
+import de.neemann.digital.draw.graphics.*;
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+
+public class GraphicLineCollectorTest extends TestCase {
+
+ public void testOpenSquare() {
+ GraphicLineCollector col = new GraphicLineCollector();
+ col.drawLine(new Vector(0, 0), new Vector(10, 0), Style.NORMAL);
+ col.drawLine(new Vector(0, 10), new Vector(10, 10), Style.NORMAL);
+
+ col.drawLine(new Vector(0, 0), new Vector(0, 10), Style.NORMAL);
+
+ ArrayList poly = new ArrayList<>();
+ col.drawTo(new MyGraphic(poly));
+
+ assertEquals(1, poly.size());
+ assertEquals("M 10,0 L 0,0 L 0,10 L 10,10", poly.get(0).toString());
+ }
+
+ public void testClosedSquare() {
+ GraphicLineCollector col = new GraphicLineCollector();
+ col.drawLine(new Vector(0, 0), new Vector(10, 0), Style.NORMAL);
+ col.drawLine(new Vector(0, 10), new Vector(10, 10), Style.NORMAL);
+
+ col.drawLine(new Vector(0, 0), new Vector(0, 10), Style.NORMAL);
+ col.drawLine(new Vector(10, 0), new Vector(10, 10), Style.NORMAL);
+
+ ArrayList poly = new ArrayList<>();
+ col.drawTo(new MyGraphic(poly));
+
+ assertEquals(1, poly.size());
+ assertEquals("M 10,0 L 0,0 L 0,10 L 10,10 Z", poly.get(0).toString());
+ }
+
+ public void testClosedSquare2() {
+ GraphicLineCollector col = new GraphicLineCollector();
+ col.drawLine(new Vector(0, 0), new Vector(10, 0), Style.NORMAL);
+ col.drawLine(new Vector(0, 10), new Vector(10, 10), Style.NORMAL);
+
+ col.drawLine(new Vector(0, 0), new Vector(0, 10), Style.NORMAL);
+ col.drawLine(new Vector(10, 0), new Vector(10, 10), Style.NORMAL);
+
+ ArrayList poly = new ArrayList<>();
+ col.drawTo(new MyGraphic(poly));
+
+ assertEquals(1, poly.size());
+ assertEquals("M 10,0 L 0,0 L 0,10 L 10,10 Z", poly.get(0).toString());
+ }
+
+ private static class MyGraphic implements Graphic {
+ private final ArrayList poly;
+
+ private MyGraphic(ArrayList poly) {
+ this.poly = poly;
+ }
+
+ @Override
+ public void drawLine(VectorInterface p1, VectorInterface p2, Style style) {
+ }
+
+ @Override
+ public void drawPolygon(Polygon p, Style style) {
+ poly.add(p);
+ }
+
+ @Override
+ public void drawCircle(VectorInterface p1, VectorInterface p2, Style style) {
+ }
+
+ @Override
+ public void drawText(VectorInterface p1, VectorInterface p2, String text, Orientation orientation, Style style) {
+ }
+ }
+}
\ No newline at end of file