diff --git a/input/Night.png b/input/Night.png new file mode 100644 index 0000000..d987358 Binary files /dev/null and b/input/Night.png differ diff --git a/src/apps/MapApplication.java b/src/apps/MapApplication.java index 0b2238f..673c565 100644 --- a/src/apps/MapApplication.java +++ b/src/apps/MapApplication.java @@ -543,14 +543,18 @@ public abstract class MapApplication extends Application { protected void disable(ButtonType... buttons) { - for (ButtonType bt: buttons) - this.buttons.get(bt).setDisable(true); + Platform.runLater(() -> { + for (ButtonType bt: buttons) + this.buttons.get(bt).setDisable(true); + }); } protected void enable(ButtonType... buttons) { - for (ButtonType bt: buttons) - this.buttons.get(bt).setDisable(false); + Platform.runLater(() -> { + for (ButtonType bt: buttons) + this.buttons.get(bt).setDisable(false); + }); } diff --git a/src/apps/MapDesignerVector.java b/src/apps/MapDesignerVector.java index 85f1f07..b82ee1e 100644 --- a/src/apps/MapDesignerVector.java +++ b/src/apps/MapDesignerVector.java @@ -33,6 +33,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import dialogs.ProgressBarDialog; +import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.canvas.Canvas; @@ -160,14 +161,18 @@ public class MapDesignerVector extends MapApplication { final Iterable transformed = map(input, input.length()/maxVtx+1, aspect.clone(), null); if (this.getProjection().getWidth() > this.getProjection().getHeight()) { - viewer.setWidth(IMG_WIDTH); - viewer.setHeight(IMG_WIDTH/this.getProjection().getAspectRatio()); + Platform.runLater(() -> { + viewer.setWidth(IMG_WIDTH); + viewer.setHeight(IMG_WIDTH/this.getProjection().getAspectRatio()); + }); } else { - viewer.setWidth(IMG_WIDTH*this.getProjection().getAspectRatio()); - viewer.setHeight(IMG_WIDTH); + Platform.runLater(() -> { + viewer.setWidth(IMG_WIDTH*this.getProjection().getAspectRatio()); + viewer.setHeight(IMG_WIDTH); + }); } - drawImage(transformed, viewer); + Platform.runLater(() -> drawImage(transformed, viewer)); enable(ButtonType.SAVE_MAP); } @@ -228,7 +233,7 @@ public class MapDesignerVector extends MapApplication { private void drawImage( - Iterable paths, Canvas c) { //parse the SVG path, with a few modifications + Iterable paths, Canvas c) { //parse the SVG path, with a few modifications (run this from the GUI thread!) final double mX = this.getProjection().getWidth()/2; final double mY = this.getProjection().getHeight()/2; GraphicsContext g = c.getGraphicsContext2D(); diff --git a/src/maps/Octohedral.java b/src/maps/Octohedral.java index d96f243..15fbd21 100644 --- a/src/maps/Octohedral.java +++ b/src/maps/Octohedral.java @@ -307,17 +307,19 @@ public class Octohedral { } public double[] inverse(double x, double y) { - if (Math.hypot(x-southPoleX, y-southPoleY) < 0.325) { //do the special Antarctica thing + if (Math.hypot(x-southPoleX, y-southPoleY) < 0.324) { //do the special Antarctica thing double tht = Math.atan2(southPoleX-x, y-southPoleY); double centralAngle = Math.floor((tht+Math.PI/12)/(Math.PI/2))*Math.PI/2 + Math.PI/6; + if (centralAngle == 7*Math.PI/6) + centralAngle = -5*Math.PI/6; double maxLat = (centralAngle != Math.PI/6) ? -Math.PI/3 : Math.PI/2; return new double[] { southPoleX - (2-cutRatio)*Math.sin(centralAngle), southPoleY + (2-cutRatio)*Math.cos(centralAngle), centralAngle, -Math.PI/12 - centralAngle, -Math.PI/2, maxLat}; } - else { + else { //everything besides Antarctica is pretty straightforward double tht = Math.atan2(Math.abs(x)-1, -y); if (tht < -Math.PI/3) return null; double centralAngle = Math.floor(tht/(Math.PI/3))*Math.PI/3 + Math.PI/6; diff --git a/src/utils/SVGMap.java b/src/utils/SVGMap.java index 72b927b..e114bf1 100644 --- a/src/utils/SVGMap.java +++ b/src/utils/SVGMap.java @@ -31,6 +31,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -279,7 +280,7 @@ public class SVGMap implements Iterable { out.write(replacePlaceholders(formatIterator.next(), inWidth/inHeight)); while (curveIterator.hasNext()) { - out.write(curveIterator.next().toString(inMinX, inMaxY, vbMinX, vbMinY, + out.write(breakWraps(curveIterator.next()).toString(inMinX, inMaxY, vbMinX, vbMinY, Math.max(vbWidth, vbHeight)/Math.max(inWidth, inHeight))); out.write(formatIterator.next()); tracker.accept((double)i/paths.size()); @@ -312,6 +313,32 @@ public class SVGMap implements Iterable { } + private Path breakWraps(Path continuous) { //break excessively long commands, as they are likely wrapping over a discontinuity + if (continuous.size() <= 2) return continuous; + Path broken = new Path(); + double[] lens = {Double.NaN, Double.NaN, Double.NaN}; //the revolving array of command lengths + for (int i = 0; i < continuous.size(); i ++) { + if (i < continuous.size()-1 && continuous.get(i+1).type != 'M') + lens[2] = Math.hypot( //compute this next length + continuous.get(i+1).args[0] - continuous.get(i).args[0], + continuous.get(i+1).args[1] - continuous.get(i).args[1]); + else + lens[2] = Double.NaN; + + char type = continuous.get(i).type; + if ((Double.isNaN(lens[0]) || lens[1] > 20*lens[0]) //and compare it to the last two lengths + && (Double.isNaN(lens[2]) || lens[1] > 20*lens[2])) + type = 'M'; + + broken.add(new Command(type, continuous.get(i).args.clone())); + lens[0] = lens[1]; + lens[1] = lens[2]; + } + + return broken; + } + + private static boolean isNonELetter(char c) { return (c >= 'A' && c <= 'Z' && c != 'E') || (c >= 'a' && c <= 'z' && c != 'e'); } @@ -337,6 +364,11 @@ public class SVGMap implements Iterable { super(); } + public Path(Command... commands) { + this(); + this.addAll(Arrays.asList(commands)); + } + public Path(String d, double vbWidth, double vbHeight) throws Exception { this(d, new double[] {1,1,0,0}, 0, 0, vbWidth, vbHeight); } @@ -346,7 +378,8 @@ public class SVGMap implements Iterable { super(); int i = 0; - double[] last = new double[] {0,0}; //for relative coordinates + double[] lastMove = {0, 0}; //for closepaths + double[] last = {0, 0}; //for relative coordinates while (i < d.length()) { char type = d.charAt(i); String argString = ""; @@ -374,6 +407,10 @@ public class SVGMap implements Iterable { last[direcIdx] = args[direcIdx]; type = 'L'; } + else if (type == 'z' || type == 'Z') { //change this to 'L', too + args = new double[] {lastMove[0], lastMove[1]}; + type = 'L'; + } else { args = new double[argStrings.length]; for (int j = 0; j < args.length; j ++) { @@ -386,6 +423,10 @@ public class SVGMap implements Iterable { if (type >= 'a') //make all letters uppercase type -= 32; } + if (type == 'M') { //make note, so we can interpret closepaths properly + lastMove[0] = args[args.length-2]; + lastMove[1] = args[args.length-1]; + } for (int j = 0; j < args.length; j ++) { if (!Double.isFinite(args[j])) @@ -406,10 +447,8 @@ public class SVGMap implements Iterable { } } - public boolean addAll(Path p) { - for (Command c: p) - add(c); - return true; + public Path(Command command) { + // TODO: Implement this } public String toString( @@ -435,6 +474,10 @@ public class SVGMap implements Iterable { this.args = args; } + public Command(Command command) { + this(command.type, command.args.clone()); + } + public String toString() { return this.toString(-1, -1, 0, 0, 1); }