Changeset 32542 in osm for applications/editors/josm/plugins/pdfimport
- Timestamp:
- 2016-07-03T12:20:52+02:00 (9 years ago)
- Location:
- applications/editors/josm/plugins/pdfimport
- Files:
-
- 2 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/pdfimport/.project
r32286 r32542 16 16 </arguments> 17 17 </buildCommand> 18 <buildCommand> 19 <name>net.sf.eclipsecs.core.CheckstyleBuilder</name> 20 <arguments> 21 </arguments> 22 </buildCommand> 18 23 </buildSpec> 19 24 <natures> 20 25 <nature>org.eclipse.jdt.core.javanature</nature> 26 <nature>net.sf.eclipsecs.core.CheckstyleNature</nature> 21 27 </natures> 22 28 </projectDescription> -
applications/editors/josm/plugins/pdfimport/src/pdfimport/DuplicateNodesFinder.java
r30737 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 11 12 import java.util.TreeMap; 12 13 13 public class DuplicateNodesFinder { 14 public final class DuplicateNodesFinder { 14 15 15 /*** 16 * This method finds very close nodes and constructs a mapping from node to suggested representative node. 17 * Works by performing a sweep and noting down similar nodes. 18 * @param nodes the nodes to process 19 * @return map from nodes that need replacement to a representative node. 20 */ 21 public static Map<Point2D, Point2D> findDuplicateNodes(Collection<Point2D> nodes, final double tolerance){ 22 List<Point2D> points = new ArrayList<>(nodes); 23 Collections.sort(points, new Comparator<Point2D>(){ 24 public int compare(Point2D o1, Point2D o2) { 25 double diff = o1.getY() - o2.getY(); 26 return diff > 0 ? 1 : (diff < 0 ? -1 : 0); 27 } 28 }); 16 private DuplicateNodesFinder() { 17 // Hide default constructor for utilities classes 18 } 29 19 30 Map<Point2D, Point2D> result = new HashMap<>(); 31 TreeMap<Point2D, Point2D> sweepLine = new TreeMap<>(new Comparator<Point2D>(){ 32 public int compare(Point2D o1, Point2D o2) { 33 double diff = o1.getX() - o2.getX(); 20 /*** 21 * This method finds very close nodes and constructs a mapping from node to suggested representative node. 22 * Works by performing a sweep and noting down similar nodes. 23 * @param nodes the nodes to process 24 * @return map from nodes that need replacement to a representative node. 25 */ 26 public static Map<Point2D, Point2D> findDuplicateNodes(Collection<Point2D> nodes, final double tolerance) { 27 List<Point2D> points = new ArrayList<>(nodes); 28 Collections.sort(points, new Comparator<Point2D>() { 29 @Override 30 public int compare(Point2D o1, Point2D o2) { 31 double diff = o1.getY() - o2.getY(); 32 return diff > 0 ? 1 : (diff < 0 ? -1 : 0); 33 } 34 }); 34 35 35 if (Math.abs(diff) <= tolerance){ 36 return 0; 37 } 36 Map<Point2D, Point2D> result = new HashMap<>(); 37 TreeMap<Point2D, Point2D> sweepLine = new TreeMap<>(new Comparator<Point2D>() { 38 @Override 39 public int compare(Point2D o1, Point2D o2) { 40 double diff = o1.getX() - o2.getX(); 38 41 39 return diff > 0 ? 1 : (diff < 0 ? -1 : 0); 40 } 41 }); 42 if (Math.abs(diff) <= tolerance) { 43 return 0; 44 } 42 45 43 //sweep from top to bottom. 44 double prevY = Double.NEGATIVE_INFINITY; 46 return diff > 0 ? 1 : (diff < 0 ? -1 : 0); 47 } 48 }); 45 49 46 for(Point2D point: points) { 47 boolean mappedToOtherPoint = false;50 //sweep from top to bottom. 51 double prevY = Double.NEGATIVE_INFINITY; 48 52 49 if (point.getY() - prevY > tolerance){ 50 sweepLine.clear(); 51 //big offset, clear old points 52 } else { 53 //small offset, test against existing points (there may be more than one) 53 for (Point2D point: points) { 54 boolean mappedToOtherPoint = false; 54 55 55 while (!mappedToOtherPoint && sweepLine.containsKey(point)) { 56 //a close point found 57 Point2D closePoint = sweepLine.get(point); 58 double dy = point.getY() - closePoint.getY(); 59 if (dy <= tolerance) { 60 //mark them as close 61 result.put(point, closePoint); 62 mappedToOtherPoint = true; 63 } 64 else 65 { 66 sweepLine.remove(point); 56 if (point.getY() - prevY > tolerance) { 57 sweepLine.clear(); 58 //big offset, clear old points 59 } else { 60 //small offset, test against existing points (there may be more than one) 67 61 68 } 69 } 70 } 62 while (!mappedToOtherPoint && sweepLine.containsKey(point)) { 63 //a close point found 64 Point2D closePoint = sweepLine.get(point); 65 double dy = point.getY() - closePoint.getY(); 66 if (dy <= tolerance) { 67 //mark them as close 68 result.put(point, closePoint); 69 mappedToOtherPoint = true; 70 } else { 71 sweepLine.remove(point); 71 72 72 if (!mappedToOtherPoint) { 73 sweepLine.put(point, point); 74 73 } 74 } 75 } 75 76 76 prevY = point.getY(); 77 } 77 if (!mappedToOtherPoint) { 78 sweepLine.put(point, point); 79 } 78 80 79 return result; 80 } 81 prevY = point.getY(); 82 } 83 84 return result; 85 } 81 86 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/FilePlacement.java
r29854 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 13 14 14 15 public class FilePlacement { 15 public Projection projection = null; 16 public double minX = 0; 17 public double maxX = 1; 18 public double minY = 0; 19 public double maxY = 1; 20 21 public double minEast = 0; 22 public double maxEast = 10000; 23 public double minNorth = 0; 24 public double maxNorth = 10000; 25 26 private AffineTransform transform; 27 28 29 public void setPdfBounds(double minX, double minY, double maxX, double maxY){ 30 this.minX = minX; 31 this.minY = minY; 32 this.maxX = maxX; 33 this.maxY = maxY; 34 } 35 36 public void setEastNorthBounds(double minEast, double minNorth, double maxEast, double maxNorth) { 37 this.minEast = minEast; 38 this.maxEast = maxEast; 39 this.minNorth = minNorth; 40 this.maxNorth = maxNorth; 41 } 42 43 public Properties toProperties() { 44 Properties p = new Properties(); 45 if (projection != null) { 46 p.setProperty("Projection", projection.toCode()); 47 } 48 49 p.setProperty("minX", Double.toString(minX)); 50 p.setProperty("maxX", Double.toString(maxX)); 51 p.setProperty("minY", Double.toString(minY)); 52 p.setProperty("maxY", Double.toString(maxY)); 53 p.setProperty("minEast", Double.toString(minEast)); 54 p.setProperty("maxEast", Double.toString(maxEast)); 55 p.setProperty("minNorth", Double.toString(minNorth)); 56 p.setProperty("maxNorth", Double.toString(maxNorth)); 57 58 return p; 59 } 60 61 public void fromProperties(Properties p){ 62 String projectionCode = p.getProperty("Projection", null); 63 if (projectionCode != null) { 64 projection = ProjectionInfo.getProjectionByCode(projectionCode); 65 } else { 66 projection = null; 67 } 68 69 minX = parseProperty(p, "minX", minX); 70 maxX = parseProperty(p, "maxX", maxX); 71 minY = parseProperty(p, "minY", minY); 72 maxY = parseProperty(p, "maxY", maxY); 73 74 minEast = parseProperty(p, "minEast", minEast); 75 maxEast = parseProperty(p, "maxEast", maxEast); 76 minNorth = parseProperty(p, "minNorth", minNorth); 77 maxNorth = parseProperty(p, "maxNorth", maxNorth); 78 } 79 80 private double parseProperty(Properties p, String name, double defaultValue){ 81 if (!p.containsKey(name)) { 82 return defaultValue; 83 } 84 85 String value = p.getProperty(name); 86 87 try { 88 return Double.parseDouble(value); 89 } catch (Exception e) { 90 return defaultValue; 91 } 92 93 } 94 95 96 public String prepareTransform() 97 { 98 if (this.minX > this.maxX){ 99 return tr("Transform error: Min X must be smaller than max"); 100 } 101 102 if (this.minY > this.maxY){ 103 return tr("Transform error: Min Y must be smaller than max"); 104 } 105 106 if (Math.abs(this.minY - this.maxY) < 1 && 107 Math.abs(this.minX - this.maxX) < 1) 108 { 109 return tr("Transform error: Points too close"); 110 } 111 else if (Math.abs(this.minX - this.maxX) < 1){ 112 //x axis equal, assume same scale in both dimensions 113 if (this.minEast == this.maxEast){ 114 //no rotation 115 this.maxX = this.minX + this.maxY - this.minY; 116 this.maxEast = this.minEast + this.maxNorth - this.minNorth; 117 } else if (this.minNorth == this.maxNorth) { 118 //needs rotated 90 degrees clockwise, or counter 119 this.maxX = this.minX + this.maxY - this.minY; 120 this.maxNorth = this.minNorth - (this.maxEast - this.minEast); 121 } else { 122 return tr("Transform error: Unsupported variant."); 123 } 124 } else if (Math.abs(this.minY - this.maxY) < 1) { 125 //Y axis equal, assume same scale in both dimensions 126 if (this.minNorth == this.maxNorth){ 127 //no rotation 128 this.maxY = this.minY + this.maxX - this.minX; 129 this.maxNorth = this.minNorth + this.maxEast - this.minEast; 130 } else if (this.minEast == this.maxEast){ 131 //needs rotated 90 degrees clockwise, or counter 132 this.maxY = this.minY + this.maxX - this.minX; 133 this.maxEast = this.minEast - (this.maxNorth - this.minNorth); 134 } else { 135 return tr("Transform error: Unsupported variant."); 136 } 137 } else { 138 //all fine 139 } 140 141 142 if (this.minEast < this.maxEast && this.minNorth < this.maxNorth) { 143 //no rotation 144 this.transform = new AffineTransform(); 145 this.transform.translate(this.minEast, this.minNorth); 146 this.transform.scale( 147 (this.maxEast - this.minEast) / (this.maxX - this.minX), 148 (this.maxNorth - this.minNorth) / (this.maxY - this.minY)); 149 this.transform.translate(-this.minX, -this.minY); 150 } else if (this.minEast > this.maxEast && this.minNorth < this.maxNorth) { 151 //need to rotate 90 degrees counterclockwise 152 this.transform = new AffineTransform(); 153 //transform to 0..1, 0..1 range 154 this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY)); 155 this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY))); 156 157 //rotate -90 degs around min 158 this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(1, 0, 0)); 159 160 //transform back to target range 161 this.transform.preConcatenate(AffineTransform.getScaleInstance( 162 (this.minEast - this.maxEast), 163 (this.maxNorth - this.minNorth))); 164 this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth)); 165 } else if (this.minEast < this.maxEast && this.minNorth > this.maxNorth) { 166 //need to rotate 90 degrees clockwise 167 this.transform = new AffineTransform(); 168 //transform to 0..1, 0..1 range 169 this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY)); 170 this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY))); 171 172 //rotate 90 degs around min 173 this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(-1, 0, 0)); 174 175 //transform back to target range 176 this.transform.preConcatenate(AffineTransform.getScaleInstance( 177 (this.maxEast - this.minEast), 178 (this.minNorth - this.maxNorth))); 179 this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth)); 180 } 181 else 182 { 183 return tr("Transform error: Unsupported orientation"); 184 } 185 186 return null; 187 188 } 189 190 EastNorth en = new EastNorth(0, 0); 191 Point2D src = new Point2D.Double(); 192 193 194 public Bounds getWorldBounds(PathOptimizer data) { 195 LatLon min = this.tranformCoords(new Point2D.Double(data.bounds.getMinX(), data.bounds.getMinY())); 196 LatLon max = this.tranformCoords(new Point2D.Double(data.bounds.getMaxX(), data.bounds.getMaxY())); 197 return new Bounds(min, max); 198 } 199 200 public LatLon tranformCoords(Point2D pt) { 201 202 if (this.projection == null) { 203 return new LatLon(pt.getY() / 1000, pt.getX() / 1000); 204 } else { 205 Point2D dest = new Point2D.Double(); 206 this.transform.transform(pt, dest); 207 en = new EastNorth(dest.getX(), dest.getY()); 208 return this.projection.eastNorth2latlon(en); 209 } 210 } 211 212 public EastNorth reverseTransform(LatLon coor) { 213 if (this.projection == null) { 214 return new EastNorth(coor.lon() * 1000, coor.lat() * 1000); 215 } else { 216 return null; 217 } 218 } 16 public Projection projection = null; 17 public double minX = 0; 18 public double maxX = 1; 19 public double minY = 0; 20 public double maxY = 1; 21 22 public double minEast = 0; 23 public double maxEast = 10000; 24 public double minNorth = 0; 25 public double maxNorth = 10000; 26 27 private AffineTransform transform; 28 29 public void setPdfBounds(double minX, double minY, double maxX, double maxY) { 30 this.minX = minX; 31 this.minY = minY; 32 this.maxX = maxX; 33 this.maxY = maxY; 34 } 35 36 public void setEastNorthBounds(double minEast, double minNorth, double maxEast, double maxNorth) { 37 this.minEast = minEast; 38 this.maxEast = maxEast; 39 this.minNorth = minNorth; 40 this.maxNorth = maxNorth; 41 } 42 43 public Properties toProperties() { 44 Properties p = new Properties(); 45 if (projection != null) { 46 p.setProperty("Projection", projection.toCode()); 47 } 48 49 p.setProperty("minX", Double.toString(minX)); 50 p.setProperty("maxX", Double.toString(maxX)); 51 p.setProperty("minY", Double.toString(minY)); 52 p.setProperty("maxY", Double.toString(maxY)); 53 p.setProperty("minEast", Double.toString(minEast)); 54 p.setProperty("maxEast", Double.toString(maxEast)); 55 p.setProperty("minNorth", Double.toString(minNorth)); 56 p.setProperty("maxNorth", Double.toString(maxNorth)); 57 58 return p; 59 } 60 61 public void fromProperties(Properties p) { 62 String projectionCode = p.getProperty("Projection", null); 63 if (projectionCode != null) { 64 projection = ProjectionInfo.getProjectionByCode(projectionCode); 65 } else { 66 projection = null; 67 } 68 69 minX = parseProperty(p, "minX", minX); 70 maxX = parseProperty(p, "maxX", maxX); 71 minY = parseProperty(p, "minY", minY); 72 maxY = parseProperty(p, "maxY", maxY); 73 74 minEast = parseProperty(p, "minEast", minEast); 75 maxEast = parseProperty(p, "maxEast", maxEast); 76 minNorth = parseProperty(p, "minNorth", minNorth); 77 maxNorth = parseProperty(p, "maxNorth", maxNorth); 78 } 79 80 private double parseProperty(Properties p, String name, double defaultValue) { 81 if (!p.containsKey(name)) { 82 return defaultValue; 83 } 84 85 String value = p.getProperty(name); 86 87 try { 88 return Double.parseDouble(value); 89 } catch (Exception e) { 90 return defaultValue; 91 } 92 } 93 94 public String prepareTransform() { 95 if (this.minX > this.maxX) { 96 return tr("Transform error: Min X must be smaller than max"); 97 } 98 99 if (this.minY > this.maxY) { 100 return tr("Transform error: Min Y must be smaller than max"); 101 } 102 103 if (Math.abs(this.minY - this.maxY) < 1 && 104 Math.abs(this.minX - this.maxX) < 1) { 105 return tr("Transform error: Points too close"); 106 } else if (Math.abs(this.minX - this.maxX) < 1) { 107 //x axis equal, assume same scale in both dimensions 108 if (this.minEast == this.maxEast) { 109 //no rotation 110 this.maxX = this.minX + this.maxY - this.minY; 111 this.maxEast = this.minEast + this.maxNorth - this.minNorth; 112 } else if (this.minNorth == this.maxNorth) { 113 //needs rotated 90 degrees clockwise, or counter 114 this.maxX = this.minX + this.maxY - this.minY; 115 this.maxNorth = this.minNorth - (this.maxEast - this.minEast); 116 } else { 117 return tr("Transform error: Unsupported variant."); 118 } 119 } else if (Math.abs(this.minY - this.maxY) < 1) { 120 //Y axis equal, assume same scale in both dimensions 121 if (this.minNorth == this.maxNorth) { 122 //no rotation 123 this.maxY = this.minY + this.maxX - this.minX; 124 this.maxNorth = this.minNorth + this.maxEast - this.minEast; 125 } else if (this.minEast == this.maxEast) { 126 //needs rotated 90 degrees clockwise, or counter 127 this.maxY = this.minY + this.maxX - this.minX; 128 this.maxEast = this.minEast - (this.maxNorth - this.minNorth); 129 } else { 130 return tr("Transform error: Unsupported variant."); 131 } 132 } 133 134 if (this.minEast < this.maxEast && this.minNorth < this.maxNorth) { 135 //no rotation 136 this.transform = new AffineTransform(); 137 this.transform.translate(this.minEast, this.minNorth); 138 this.transform.scale( 139 (this.maxEast - this.minEast) / (this.maxX - this.minX), 140 (this.maxNorth - this.minNorth) / (this.maxY - this.minY)); 141 this.transform.translate(-this.minX, -this.minY); 142 } else if (this.minEast > this.maxEast && this.minNorth < this.maxNorth) { 143 //need to rotate 90 degrees counterclockwise 144 this.transform = new AffineTransform(); 145 //transform to 0..1, 0..1 range 146 this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY)); 147 this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY))); 148 149 //rotate -90 degs around min 150 this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(1, 0, 0)); 151 152 //transform back to target range 153 this.transform.preConcatenate(AffineTransform.getScaleInstance( 154 (this.minEast - this.maxEast), 155 (this.maxNorth - this.minNorth))); 156 this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth)); 157 } else if (this.minEast < this.maxEast && this.minNorth > this.maxNorth) { 158 //need to rotate 90 degrees clockwise 159 this.transform = new AffineTransform(); 160 //transform to 0..1, 0..1 range 161 this.transform.preConcatenate(AffineTransform.getTranslateInstance(-this.minX, -this.minY)); 162 this.transform.preConcatenate(AffineTransform.getScaleInstance(1/(this.maxX - this.minX), 1/(this.maxY - this.minY))); 163 164 //rotate 90 degs around min 165 this.transform.preConcatenate(AffineTransform.getQuadrantRotateInstance(-1, 0, 0)); 166 167 //transform back to target range 168 this.transform.preConcatenate(AffineTransform.getScaleInstance( 169 (this.maxEast - this.minEast), 170 (this.minNorth - this.maxNorth))); 171 this.transform.preConcatenate(AffineTransform.getTranslateInstance(this.minEast, this.minNorth)); 172 } else { 173 return tr("Transform error: Unsupported orientation"); 174 } 175 176 return null; 177 178 } 179 180 EastNorth en = new EastNorth(0, 0); 181 Point2D src = new Point2D.Double(); 182 183 public Bounds getWorldBounds(PathOptimizer data) { 184 LatLon min = this.tranformCoords(new Point2D.Double(data.bounds.getMinX(), data.bounds.getMinY())); 185 LatLon max = this.tranformCoords(new Point2D.Double(data.bounds.getMaxX(), data.bounds.getMaxY())); 186 return new Bounds(min, max); 187 } 188 189 public LatLon tranformCoords(Point2D pt) { 190 191 if (this.projection == null) { 192 return new LatLon(pt.getY() / 1000, pt.getX() / 1000); 193 } else { 194 Point2D dest = new Point2D.Double(); 195 this.transform.transform(pt, dest); 196 en = new EastNorth(dest.getX(), dest.getY()); 197 return this.projection.eastNorth2latlon(en); 198 } 199 } 200 201 public EastNorth reverseTransform(LatLon coor) { 202 if (this.projection == null) { 203 return new EastNorth(coor.lon() * 1000, coor.lat() * 1000); 204 } else { 205 return null; 206 } 207 } 219 208 220 209 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/LayerContents.java
r30737 r32542 1 /** 2 * 3 */ 1 // License: GPL. For details, see LICENSE file. 4 2 package pdfimport; 5 3 … … 8 6 import java.util.List; 9 7 10 public class LayerContents{ 8 public class LayerContents { 11 9 12 13 14 15 10 List<Point2D> points = new ArrayList<>(); 11 List<PdfPath> paths = new ArrayList<>(); 12 List<PdfMultiPath> multiPaths = new ArrayList<>(); 13 LayerInfo info; 16 14 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/LayerInfo.java
r25349 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 3 4 import java.awt.Color; 4 5 5 public class LayerInfo{ 6 7 8 9 10 11 6 public class LayerInfo { 7 public Color fill; 8 public Color stroke; 9 public int dash; 10 public double width; 11 public int divider; 12 public boolean isGroup; 12 13 13 14 public int nr; 14 15 15 @Override 16 public int hashCode() 17 { 18 int code = Double.toString(width).hashCode() ^ this.divider ^ this.dash; 16 @Override 17 public int hashCode() { 18 int code = Double.toString(width).hashCode() ^ this.divider ^ this.dash; 19 19 20 21 22 20 if (this.fill != null) { 21 code ^= this.fill.hashCode(); 22 } 23 23 24 25 26 24 if (this.stroke != null) { 25 code ^= this.stroke.hashCode(); 26 } 27 27 28 29 28 return code; 29 } 30 30 31 @Override 32 public boolean equals(Object o) 33 { 34 LayerInfo l = (LayerInfo) o; 35 boolean eq = this.width == l.width && 36 this.divider == l.divider && 37 this.dash == l.dash; 31 @Override 32 public boolean equals(Object o) { 33 LayerInfo l = (LayerInfo) o; 34 boolean eq = this.width == l.width && 35 this.divider == l.divider && 36 this.dash == l.dash; 38 37 39 38 40 41 42 39 if (this.fill != null) { 40 eq &= this.fill.equals(l.fill); 41 } 43 42 44 45 46 43 if (this.stroke != null) { 44 eq &= this.stroke.equals(l.stroke); 45 } 47 46 48 49 47 return eq; 48 } 50 49 51 52 53 54 55 56 57 58 59 50 public LayerInfo copy() { 51 LayerInfo result = new LayerInfo(); 52 result.fill = this.fill; 53 result.stroke = this.stroke; 54 result.dash = this.dash; 55 result.width = this.width; 56 result.divider = this.divider; 57 return result; 58 } 60 59 61 60 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/LoadPdfDialog.java
r32515 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 63 64 import pdfimport.pdfbox.PdfBoxParser; 64 65 65 public class LoadPdfDialog extends JFrame{ 66 67 class LoadProgressRenderer implements ProgressRenderer{ 68 private final JProgressBar pBar; 69 private String title = ""; 70 71 public LoadProgressRenderer(JProgressBar pb) 72 { 73 this.pBar =pb; 74 this.pBar.setMinimum(0); 75 this.pBar.setValue(0); 76 this.pBar.setMaximum(1); 77 this.pBar.setString(""); 78 this.pBar.setStringPainted(true); 79 80 } 81 82 @Override 83 public void setCustomText(String message) { 84 this.pBar.setString(this.title + message); 85 } 86 87 @Override 88 public void setIndeterminate(boolean indeterminate) { 89 this.pBar.setIndeterminate(indeterminate); 90 } 91 92 @Override 93 public void setMaximum(int maximum) { 94 this.pBar.setMaximum(maximum); 95 } 96 97 @Override 98 public void setTaskTitle(String taskTitle) { 99 this.title = taskTitle; 100 this.pBar.setString(this.title); 101 } 102 103 @Override 104 public void setValue(int value) { 105 this.pBar.setValue(value); 106 } 107 108 public void finish() { 109 this.pBar.setString(tr("Finished")); 110 this.pBar.setValue(this.pBar.getMaximum()); 111 } 112 113 } 114 115 private File fileName; 116 private PathOptimizer data; 117 private OsmDataLayer layer; 118 119 /** 120 * Combobox with all projections available 121 */ 122 private JComboBox<ProjectionChoice> projectionCombo; 123 private JButton projectionPreferencesButton; 124 private JTextField minXField; 125 private JTextField minYField; 126 private JTextField minEastField; 127 private JTextField minNorthField; 128 private JButton getMinButton; 129 private JButton okButton; 130 private JButton cancelButton; 131 private JButton getMaxButton; 132 private JTextField maxNorthField; 133 private JTextField maxEastField; 134 private JTextField maxYField; 135 private JTextField maxXField; 136 private JButton loadFileButton; 137 private JButton showButton; 138 private JButton saveButton; 139 private JCheckBox debugModeCheck; 140 private JCheckBox mergeCloseNodesCheck; 141 private JTextField mergeCloseNodesTolerance; 142 private JCheckBox removeSmallObjectsCheck; 143 private JTextField removeSmallObjectsSize; 144 private JTextField colorFilterColor; 145 private JCheckBox colorFilterCheck; 146 private JCheckBox removeParallelSegmentsCheck; 147 private JTextField removeParallelSegmentsTolerance; 148 private JCheckBox removeLargeObjectsCheck; 149 private JTextField removeLargeObjectsSize; 150 private JProgressBar loadProgress; 151 protected OsmDataLayer newLayer; 152 153 private LoadProgressRenderer progressRenderer; 154 private JCheckBox limitPathCountCheck; 155 private JTextField limitPathCount; 156 private JCheckBox splitOnColorChangeCheck; 157 private JCheckBox splitOnShapeClosedCheck; 158 private JCheckBox splitOnSingleSegmentCheck; 159 private JCheckBox splitOnOrthogonalCheck; 160 161 162 public LoadPdfDialog() { 163 this.buildGUI(); 164 FilePlacement pl = new FilePlacement(); 165 this.setPlacement(pl); 166 this.addListeners(); 167 this.removeLayer(); 168 } 169 170 private void addListeners() { 171 172 this.projectionCombo.addActionListener(new ActionListener() { 173 @Override 174 public void actionPerformed(ActionEvent e) { 175 updateProjectionPrefButton(); 176 } 177 178 }); 179 this.projectionPreferencesButton.addActionListener(new ActionListener() { 180 @Override 181 public void actionPerformed(ActionEvent e) { 182 showProjectionPreferences(); 183 } 184 }); 185 186 this.loadFileButton.addActionListener(new ActionListener() { 187 @Override 188 public void actionPerformed(ActionEvent e) { 189 loadFilePressed(); 190 } 191 }); 192 193 this.okButton.addActionListener(new ActionListener() { 194 @Override 195 public void actionPerformed(ActionEvent e) { 196 okPressed(); 197 } 198 }); 199 200 this.saveButton.addActionListener(new ActionListener() { 201 @Override 202 public void actionPerformed(ActionEvent e) { 203 savePressed(); 204 } 205 }); 206 207 this.showButton.addActionListener(new ActionListener() { 208 @Override 209 public void actionPerformed(ActionEvent e) { 210 showPressed(); 211 } 212 }); 213 214 this.cancelButton.addActionListener(new ActionListener() { 215 @Override 216 public void actionPerformed(ActionEvent e) { 217 cancelPressed(); 218 } 219 }); 220 221 this.addWindowListener(new WindowAdapter() 222 { 223 @Override 224 public void windowClosing(WindowEvent e) { 225 cancelPressed(); 226 } 227 }); 228 229 this.getMinButton.addActionListener(new ActionListener() { 230 @Override 231 public void actionPerformed(ActionEvent e) { 232 getMinPressed(); 233 } 234 }); 235 236 this.getMaxButton.addActionListener(new ActionListener() { 237 @Override 238 public void actionPerformed(ActionEvent e) { 239 getMaxPressed(); 240 } 241 }); 242 243 } 244 245 private void buildGUI() { 246 GridBagConstraints c = new GridBagConstraints(); 247 c.gridheight = 1;c.gridwidth = 1;c.weightx =1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; 248 249 this.projectionCombo = new JComboBox<>(); 250 for (ProjectionChoice p: ProjectionPreference.getProjectionChoices()) { 251 this.projectionCombo.addItem(p); 252 } 253 254 this.projectionPreferencesButton = new JButton(tr("Prefs")); 255 updateProjectionPrefButton(); 256 257 this.loadFileButton = new JButton(tr("Load file...")); 258 this.okButton = new JButton(tr("Place")); 259 this.saveButton = new JButton(tr("Save")); 260 this.showButton = new JButton(tr("Show target")); 261 this.cancelButton = new JButton(tr("Discard")); 262 this.loadProgress = new JProgressBar(); 263 this.progressRenderer = new LoadProgressRenderer(this.loadProgress); 264 265 this.minXField = new JTextField(""); 266 this.minYField = new JTextField(""); 267 this.minEastField = new JTextField(""); 268 this.minNorthField = new JTextField(""); 269 this.getMinButton = new JButton(tr("Take X and Y from selected node")); 270 271 this.maxXField = new JTextField(""); 272 this.maxYField = new JTextField(""); 273 this.maxEastField = new JTextField(""); 274 this.maxNorthField = new JTextField(""); 275 this.getMaxButton = new JButton(tr("Take X and Y from selected node")); 276 277 this.debugModeCheck = new JCheckBox(tr("Debug info")); 278 this.mergeCloseNodesCheck = new JCheckBox(tr("Merge close nodes")); 279 this.mergeCloseNodesTolerance = new JTextField("1e-3"); 280 281 this.removeSmallObjectsCheck = new JCheckBox(tr("Remove objects smaller than")); 282 this.removeSmallObjectsSize = new JTextField("1"); 283 284 this.removeLargeObjectsCheck = new JCheckBox(tr("Remove objects larger than")); 285 this.removeLargeObjectsSize = new JTextField("10"); 286 287 288 this.colorFilterCheck = new JCheckBox(tr("Only this color")); 289 this.colorFilterColor = new JTextField("#000000"); 290 291 this.removeParallelSegmentsCheck = new JCheckBox(tr("Remove parallel lines")); 292 this.removeParallelSegmentsTolerance = new JTextField("3"); 293 294 this.limitPathCountCheck = new JCheckBox(tr("Take only first X paths")); 295 this.limitPathCount = new JTextField("10000"); 296 297 this.splitOnColorChangeCheck = new JCheckBox(tr("Color/width change")); 298 this.splitOnShapeClosedCheck = new JCheckBox(tr("Shape closed")); 299 this.splitOnSingleSegmentCheck = new JCheckBox(tr("Single segments")); 300 this.splitOnOrthogonalCheck = new JCheckBox(tr("Orthogonal shapes")); 301 302 JPanel configPanel = new JPanel(new GridBagLayout()); 303 configPanel.setBorder(BorderFactory.createTitledBorder(tr("Import settings"))); 304 c.gridx = 0; c.gridy = 0; c.gridwidth = 1; 305 configPanel.add(this.mergeCloseNodesCheck, c); 306 c.gridx = 1; c.gridy = 0; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 307 configPanel.add(new JLabel("Tolerance :"), c); 308 c.gridx = 2; c.gridy = 0; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 309 configPanel.add(this.mergeCloseNodesTolerance, c); 310 311 c.gridx = 0; c.gridy = 1; c.gridwidth = 1; 312 configPanel.add(this.removeSmallObjectsCheck, c); 313 c.gridx = 1; c.gridy = 1; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 314 configPanel.add(new JLabel("Tolerance :"), c); 315 c.gridx = 2; c.gridy = 1; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 316 configPanel.add(this.removeSmallObjectsSize, c); 317 318 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 319 configPanel.add(this.removeLargeObjectsCheck, c); 320 c.gridx = 1; c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 321 configPanel.add(new JLabel("Tolerance :"), c); 322 c.gridx = 2; c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 323 configPanel.add(this.removeLargeObjectsSize, c); 324 325 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 326 configPanel.add(this.removeParallelSegmentsCheck, c); 327 c.gridx = 1; c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 328 configPanel.add(new JLabel("Max distance :"), c); 329 c.gridx = 2; c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 330 configPanel.add(this.removeParallelSegmentsTolerance, c); 331 332 333 c.gridx = 0; c.gridy = 4; c.gridwidth = 2; 334 configPanel.add(this.limitPathCountCheck, c); 335 c.gridx = 2; c.gridy = 4; c.gridwidth = 1; 336 configPanel.add(this.limitPathCount, c); 337 338 c.gridx = 0; c.gridy = 5; c.gridwidth = 1; 339 configPanel.add(this.colorFilterCheck, c); 340 c.gridx = 2; c.gridy = 5; c.gridwidth = 1; 341 configPanel.add(this.colorFilterColor, c); 342 343 c.gridx = 0; c.gridy = 6; c.gridwidth = 2; 344 configPanel.add(this.debugModeCheck, c); 345 346 347 c.gridx = 0; c.gridy = 7; c.gridwidth = 1; 348 configPanel.add(new JLabel(tr("Introduce separate layers for:")), c); 349 c.gridx = 1; c.gridy = 7; c.gridwidth = 1; 350 configPanel.add(this.splitOnShapeClosedCheck, c); 351 c.gridx = 2; c.gridy = 7; c.gridwidth = 1; 352 configPanel.add(this.splitOnSingleSegmentCheck, c); 353 c.gridx = 1; c.gridy = 8; c.gridwidth = 1; 354 configPanel.add(this.splitOnColorChangeCheck, c); 355 c.gridx = 2; c.gridy = 8; c.gridwidth = 1; 356 configPanel.add(this.splitOnOrthogonalCheck, c); 357 358 359 JPanel projectionPanel = new JPanel(new GridBagLayout()); 360 projectionPanel.setBorder(BorderFactory.createTitledBorder(tr("Bind to coordinates"))); 361 362 JPanel projectionSubPanel = new JPanel(); 363 projectionSubPanel.setLayout(new BoxLayout(projectionSubPanel, BoxLayout.X_AXIS)); 364 365 projectionSubPanel.add(new JLabel(tr("Projection:"))); 366 projectionSubPanel.add(this.projectionCombo); 367 projectionSubPanel.add(this.projectionPreferencesButton); 368 c.gridx = 0; c.gridy = 0; c.gridwidth = 3; 369 projectionPanel.add(projectionSubPanel, c); 370 371 c.gridx = 0; c.gridy = 1; c.gridwidth = 2; 372 projectionPanel.add(new JLabel(tr("Bottom left (min) corner:")), c); 373 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 374 projectionPanel.add(new JLabel(tr("PDF X and Y")), c); 375 c.gridx = 1; c.gridy = 2; c.gridwidth = 1; 376 projectionPanel.add(new JLabel(tr("East and North")), c); 377 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 378 projectionPanel.add(this.minXField, c); 379 c.gridx = 0; c.gridy = 4; c.gridwidth = 1; 380 projectionPanel.add(this.minYField, c); 381 c.gridx = 1; c.gridy = 3; c.gridwidth = 1; 382 projectionPanel.add(this.minEastField, c); 383 c.gridx = 1; c.gridy = 4; c.gridwidth = 1; 384 projectionPanel.add(this.minNorthField, c); 385 c.gridx = 0; c.gridy = 5; c.gridwidth = 1; 386 projectionPanel.add(this.getMinButton, c); 387 388 389 c.gridx = 0; c.gridy = 6; c.gridwidth = 2; 390 projectionPanel.add(new JLabel(tr("Top right (max) corner:")), c); 391 c.gridx = 0; c.gridy = 7; c.gridwidth = 1; 392 projectionPanel.add(new JLabel(tr("PDF X and Y")), c); 393 c.gridx = 1; c.gridy = 7; c.gridwidth = 1; 394 projectionPanel.add(new JLabel(tr("East and North")), c); 395 c.gridx = 0; c.gridy = 8; c.gridwidth = 1; 396 projectionPanel.add(this.maxXField, c); 397 c.gridx = 0; c.gridy = 9; c.gridwidth = 1; 398 projectionPanel.add(this.maxYField, c); 399 c.gridx = 1; c.gridy = 8; c.gridwidth = 1; 400 projectionPanel.add(this.maxEastField, c); 401 c.gridx = 1; c.gridy = 9; c.gridwidth = 1; 402 projectionPanel.add(this.maxNorthField, c); 403 c.gridx = 0; c.gridy = 10; c.gridwidth = 1; 404 projectionPanel.add(this.getMaxButton, c); 405 406 407 JPanel okCancelPanel = new JPanel(new GridLayout(1,3)); 408 okCancelPanel.add(this.cancelButton); 409 okCancelPanel.add(this.showButton); 410 okCancelPanel.add(this.okButton); 411 okCancelPanel.add(this.saveButton); 412 413 414 JPanel panel = new JPanel(new GridBagLayout()); 415 c.gridx = 0; c.gridy = 0; c.gridwidth = 1; 416 panel.add(configPanel, c); 417 c.gridx = 0; c.gridy = 1; c.gridwidth = 1; 418 panel.add(loadFileButton, c); 419 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 420 panel.add(projectionPanel, c); 421 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 422 panel.add(okCancelPanel, c); 423 c.gridx = 0; c.gridy = 4; c.gridwidth = 1; 424 panel.add(this.loadProgress, c); 425 426 427 this.setSize(450, 550); 428 this.setContentPane(panel); 429 } 430 431 private class ProjectionSubPrefsDialog extends JDialog { 432 private final ProjectionChoice projPref; 433 private OKAction actOK; 434 private CancelAction actCancel; 435 private JPanel projPrefPanel; 436 437 public ProjectionSubPrefsDialog(Component parent, ProjectionChoice pr) { 438 super(JOptionPane.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL); 439 440 projPref = pr; 441 442 setTitle(tr("Projection Preferences")); 443 setDefaultCloseOperation(DISPOSE_ON_CLOSE); 444 445 build(); 446 } 447 448 protected void makeButtonRespondToEnter(SideButton btn) { 449 btn.setFocusable(true); 450 btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter"); 451 btn.getActionMap().put("enter", btn.getAction()); 452 } 453 454 protected JPanel buildInputForm() { 455 return projPref.getPreferencePanel(null); 456 } 457 458 protected JPanel buildButtonRow() { 459 JPanel pnl = new JPanel(new FlowLayout()); 460 461 actOK = new OKAction(); 462 actCancel = new CancelAction(); 463 464 SideButton btn; 465 pnl.add(btn = new SideButton(actOK)); 466 makeButtonRespondToEnter(btn); 467 pnl.add(btn = new SideButton(actCancel)); 468 makeButtonRespondToEnter(btn); 469 return pnl; 470 } 471 472 protected void build() { 473 projPrefPanel = buildInputForm(); 474 getContentPane().setLayout(new BorderLayout()); 475 getContentPane().add(projPrefPanel, BorderLayout.CENTER); 476 getContentPane().add(buildButtonRow(), BorderLayout.SOUTH); 477 pack(); 478 479 // make dialog respond to ESCAPE 480 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape"); 481 getRootPane().getActionMap().put("escape", actCancel); 482 } 483 484 class OKAction extends AbstractAction { 485 public OKAction() { 486 putValue(NAME, tr("OK")); 487 putValue(SHORT_DESCRIPTION, tr("Close the dialog and apply projection preferences")); 488 putValue(SMALL_ICON, ImageProvider.get("ok")); 489 } 490 491 @Override 492 public void actionPerformed(ActionEvent e) { 493 projPref.setPreferences(projPref.getPreferences(projPrefPanel)); 494 setVisible(false); 495 } 496 } 497 498 class CancelAction extends AbstractAction { 499 public CancelAction() { 500 putValue(NAME, tr("Cancel")); 501 putValue(SHORT_DESCRIPTION, tr("Close the dialog, discard projection preference changes")); 502 putValue(SMALL_ICON, ImageProvider.get("cancel")); 503 } 504 505 @Override 506 public void actionPerformed(ActionEvent e) { 507 setVisible(false); 508 } 509 } 510 511 @Override 512 public void setVisible(boolean visible) { 513 if (visible) { 514 new WindowGeometry( 515 getClass().getName() + ".geometry", 516 WindowGeometry.centerOnScreen(new Dimension(400, 300))).applySafe(this); 517 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 518 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 519 } 520 super.setVisible(visible); 521 } 522 } 523 524 private void updateProjectionPrefButton() { 525 // ProjectionChoice proj = (ProjectionChoice) projectionCombo.getSelectedItem(); 526 527 //TODO 528 // Enable/disable pref button 529 // if(!(proj instanceof ProjectionSubPrefs)) { 530 // projectionPreferencesButton.setEnabled(false); 531 // } else { 532 projectionPreferencesButton.setEnabled(true); 533 // } 534 } 535 536 private void showProjectionPreferences() { 537 ProjectionChoice proj = (ProjectionChoice) projectionCombo.getSelectedItem(); 538 539 ProjectionSubPrefsDialog dlg = new ProjectionSubPrefsDialog(this, proj); 540 dlg.setVisible(true); 541 542 } 543 544 private void loadFilePressed() { 545 final File newFileName = this.chooseFile(); 546 547 if (newFileName == null) { 548 return; 549 } 550 551 this.removeLayer(); 552 553 this.loadFileButton.setEnabled(false); 554 this.loadFileButton.setText(tr("Loading...")); 555 556 this.runAsBackgroundTask( 557 new Runnable() { 558 @Override 559 public void run() { 560 //async part 561 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 562 monitor.beginTask("Loading file", 1000); 563 data = loadPDF(newFileName, monitor.createSubTaskMonitor(500, false)); 564 OsmBuilder.Mode mode = LoadPdfDialog.this.debugModeCheck.isSelected() ? OsmBuilder.Mode.Debug: OsmBuilder.Mode.Draft; 565 566 if (data!= null) { 567 LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer(tr("PDF file preview"), new FilePlacement(), mode, monitor.createSubTaskMonitor(500, false)); 568 } 569 570 monitor.finishTask(); 571 progressRenderer.finish(); 572 } 573 }, 574 new ActionListener() { 575 576 @Override 577 public void actionPerformed(ActionEvent e) { 578 //sync part 579 if (data!= null) { 580 LoadPdfDialog.this.placeLayer(newLayer, new FilePlacement()); 581 fileName = newFileName; 582 newLayer = null; 583 LoadPdfDialog.this.loadFileButton.setText(tr("Loaded")); 584 LoadPdfDialog.this.loadFileButton.setEnabled(true); 585 FilePlacement placement = LoadPdfDialog.this.loadPlacement(); 586 LoadPdfDialog.this.setPlacement(placement); 587 } 588 } 589 }); 590 } 591 592 593 private FilePlacement preparePlacement() 594 { 595 FilePlacement placement = this.parsePlacement(); 596 if (placement == null){ 597 return null; 598 } 599 600 String transformError = placement.prepareTransform(); 601 if (transformError != null){ 602 JOptionPane.showMessageDialog(Main.parent, transformError); 603 return null; 604 } 605 606 this.savePlacement(placement); 607 608 return placement; 609 } 610 611 private void okPressed() { 612 613 final FilePlacement placement = preparePlacement(); 614 if (placement == null) { 615 return; 616 } 617 618 this.removeLayer(); 619 620 this.runAsBackgroundTask( 621 new Runnable() { 622 @Override 623 public void run() { 624 //async part 625 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 626 LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer(tr("Imported PDF: ") + fileName, placement, OsmBuilder.Mode.Final, monitor); 627 progressRenderer.finish(); 628 } 629 }, 630 new ActionListener() { 631 632 @Override 633 public void actionPerformed(ActionEvent e) { 634 //sync part 635 //rebuild layer with latest projection 636 LoadPdfDialog.this.placeLayer(newLayer, placement); 637 LoadPdfDialog.this.setVisible(false); 638 } 639 }); 640 } 641 642 private void savePressed() { 643 644 final FilePlacement placement = preparePlacement(); 645 if (placement == null) { 646 return; 647 } 648 649 final java.io.File file = this.chooseSaveFile(); 650 651 if (file == null){ 652 return; 653 } 654 655 this.removeLayer(); 656 657 this.runAsBackgroundTask( 658 new Runnable() { 659 @Override 660 public void run() { 661 //async part 662 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 663 LoadPdfDialog.this.saveLayer(file, placement, monitor); 664 progressRenderer.finish(); 665 } 666 }, 667 new ActionListener() { 668 669 @Override 670 public void actionPerformed(ActionEvent e) { 671 //sync part 672 LoadPdfDialog.this.setVisible(false); 673 } 674 }); 675 } 676 677 678 private void showPressed() { 679 680 FilePlacement placement = preparePlacement(); 681 if (placement == null) { 682 return; 683 } 684 685 //zoom to new location 686 Main.map.mapView.zoomTo(placement.getWorldBounds(this.data)); 687 Main.map.repaint(); 688 } 689 690 private void cancelPressed() { 691 this.removeLayer(); 692 this.setVisible(false); 693 } 694 695 696 private void getMinPressed() { 697 EastNorth en = this.getSelectedCoor(); 698 699 if (en != null) { 700 this.minXField.setText(Double.toString(en.east())); 701 this.minYField.setText(Double.toString(en.north())); 702 } 703 } 704 705 private void getMaxPressed() { 706 EastNorth en = this.getSelectedCoor(); 707 708 if (en != null) { 709 this.maxXField.setText(Double.toString(en.east())); 710 this.maxYField.setText(Double.toString(en.north())); 711 } 712 } 713 714 // Implementation methods 715 716 private EastNorth getSelectedCoor() { 717 Collection<OsmPrimitive> selected = Main.getLayerManager().getEditDataSet().getSelected(); 718 719 if (selected.size() != 1 || !(selected.iterator().next() instanceof Node)){ 720 JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly one node.")); 721 return null; 722 } 723 724 LatLon ll = ((Node)selected.iterator().next()).getCoor(); 725 FilePlacement pl = new FilePlacement(); 726 return pl.reverseTransform(ll); 727 } 728 729 730 private java.io.File chooseFile() { 731 //get file name 732 JFileChooser fc = new JFileChooser(); 733 fc.setAcceptAllFileFilterUsed(false); 734 fc.setMultiSelectionEnabled(false); 735 fc.setSelectedFile(this.fileName); 736 fc.setFileFilter(new FileFilter(){ 737 @Override 738 public boolean accept(java.io.File pathname) { 739 return pathname.isDirectory() || pathname.getName().endsWith(".pdf"); 740 } 741 @Override 742 public String getDescription() { 743 return tr("PDF files"); 744 } 745 }); 746 int result = fc.showOpenDialog(Main.parent); 747 748 if (result != JFileChooser.APPROVE_OPTION) { 749 return null; 750 } 751 else 752 { 753 return fc.getSelectedFile(); 754 } 755 } 756 757 private java.io.File chooseSaveFile() { 758 //get file name 759 JFileChooser fc = new JFileChooser(); 760 fc.setAcceptAllFileFilterUsed(true); 761 fc.setMultiSelectionEnabled(false); 762 fc.setFileFilter(new FileFilter(){ 763 @Override 764 public boolean accept(java.io.File pathname) { 765 return pathname.isDirectory() || pathname.getName().endsWith(".osm"); 766 } 767 @Override 768 public String getDescription() { 769 return tr("OSM files"); 770 } 771 }); 772 int result = fc.showOpenDialog(Main.parent); 773 774 if (result != JFileChooser.APPROVE_OPTION) { 775 return null; 776 } 777 else 778 { 779 return fc.getSelectedFile(); 780 } 781 } 782 783 private void runAsBackgroundTask(final Runnable task, final ActionListener after) { 784 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 785 Thread t = new Thread(new Runnable() 786 { 787 @Override 788 public void run() { 789 task.run(); 790 791 SwingUtilities.invokeLater(new Runnable(){ 792 @Override 793 public void run() { 794 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 795 after.actionPerformed(null); 796 } 797 }); 798 } 799 }); 800 t.start(); 801 } 802 803 private PathOptimizer loadPDF(File fileName, ProgressMonitor monitor) { 804 805 monitor.beginTask("", 100); 806 monitor.setTicks(0); 807 monitor.setCustomText(tr("Preparing")); 808 809 double nodesTolerance = 0.0; 810 Color color = null; 811 int maxPaths = Integer.MAX_VALUE; 812 813 if (this.mergeCloseNodesCheck.isSelected()) { 814 try { 815 nodesTolerance = Double.parseDouble(this.mergeCloseNodesTolerance.getText()); 816 } 817 catch (Exception e) { 818 JOptionPane 819 .showMessageDialog( 820 Main.parent, 821 tr("Tolerance is not a number")); 822 return null; 823 } 824 } 825 826 if (this.colorFilterCheck.isSelected()) { 827 try { 828 String colString = this.colorFilterColor.getText().replace("#", ""); 829 color = new Color(Integer.parseInt(colString, 16)); 830 } 831 catch (Exception e) { 832 JOptionPane 833 .showMessageDialog( 834 Main.parent, 835 tr("Could not parse color")); 836 return null; 837 } 838 } 839 840 if (this.limitPathCountCheck.isSelected()) { 841 try { 842 maxPaths = Integer.parseInt(this.limitPathCount.getText()); 843 } 844 catch (Exception e) { 845 JOptionPane 846 .showMessageDialog( 847 Main.parent, 848 tr("Could not parse max path count")); 849 return null; 850 } 851 } 852 853 854 monitor.setTicks(10); 855 monitor.setCustomText(tr("Parsing file")); 856 857 PathOptimizer data = new PathOptimizer(nodesTolerance, color, this.splitOnColorChangeCheck.isSelected()); 858 859 try { 860 PdfBoxParser parser = new PdfBoxParser(data); 861 parser.parse(fileName, maxPaths, monitor.createSubTaskMonitor(80, false)); 862 863 } catch (FileNotFoundException e1) { 864 JOptionPane 865 .showMessageDialog( 866 Main.parent, 867 tr("File not found.")); 868 return null; 869 } catch (Exception e) { 870 e.printStackTrace(); 871 JOptionPane 872 .showMessageDialog( 873 Main.parent, 874 tr("Error while parsing: {0}", e.getMessage())); 875 return null; 876 } 877 878 monitor.setTicks(80); 879 880 if (this.removeParallelSegmentsCheck.isSelected()) { 881 try { 882 double tolerance = Double.parseDouble(this.removeParallelSegmentsTolerance.getText()); 883 monitor.setCustomText(tr("Removing parallel segments")); 884 data.removeParallelLines(tolerance); 885 } 886 catch (Exception e) { 887 JOptionPane 888 .showMessageDialog( 889 Main.parent, 890 tr("Max distance is not a number")); 891 return null; 892 } 893 } 894 895 if (nodesTolerance > 0.0) { 896 monitor.setTicks(83); 897 monitor.setCustomText(tr("Joining nodes")); 898 data.mergeNodes(); 899 } 900 901 monitor.setTicks(85); 902 monitor.setCustomText(tr("Joining adjacent segments")); 903 data.mergeSegments(); 904 905 if (this.removeSmallObjectsCheck.isSelected()) { 906 try { 907 double tolerance = Double.parseDouble(this.removeSmallObjectsSize.getText()); 908 monitor.setTicks(90); 909 monitor.setCustomText(tr("Removing small objects")); 910 911 data.removeSmallObjects(tolerance); 912 } 913 catch (Exception e) { 914 JOptionPane 915 .showMessageDialog( 916 Main.parent, 917 tr("Tolerance is not a number")); 918 return null; 919 } 920 } 921 922 if (this.removeLargeObjectsCheck.isSelected()) { 923 try { 924 double tolerance = Double.parseDouble(this.removeLargeObjectsSize.getText()); 925 monitor.setTicks(90); 926 monitor.setCustomText(tr("Removing large objects")); 927 data.removeLargeObjects(tolerance); 928 } 929 catch (Exception e) { 930 JOptionPane 931 .showMessageDialog( 932 Main.parent, 933 tr("Tolerance is not a number")); 934 return null; 935 } 936 } 937 938 monitor.setTicks(95); 939 monitor.setCustomText(tr("Finalizing layers")); 940 data.splitLayersByPathKind(this.splitOnShapeClosedCheck.isSelected(), this.splitOnSingleSegmentCheck.isSelected(), this.splitOnOrthogonalCheck.isSelected()); 941 data.finish(); 942 943 monitor.finishTask(); 944 return data; 945 } 946 947 948 949 private FilePlacement parsePlacement() { 950 ProjectionChoice selectedProjection = (ProjectionChoice) this.projectionCombo.getSelectedItem(); 951 952 if (selectedProjection == null) 953 { 954 JOptionPane.showMessageDialog(Main.parent, tr("Please set a projection.")); 955 return null; 956 } 957 958 FilePlacement placement = new FilePlacement(); 959 960 placement.projection = selectedProjection.getProjection(); 961 962 try 963 { 964 placement.setPdfBounds( 965 Double.parseDouble(this.minXField.getText()), 966 Double.parseDouble(this.minYField.getText()), 967 Double.parseDouble(this.maxXField.getText()), 968 Double.parseDouble(this.maxYField.getText())); 969 placement.setEastNorthBounds( 970 Double.parseDouble(this.minEastField.getText()), 971 Double.parseDouble(this.minNorthField.getText()), 972 Double.parseDouble(this.maxEastField.getText()), 973 Double.parseDouble(this.maxNorthField.getText())); 974 } 975 catch (Exception e) { 976 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse numbers. Please check.")); 977 return null; 978 } 979 980 return placement; 981 } 982 983 private void setPlacement(FilePlacement placement) { 984 985 if (placement == null) { 986 //use default values. 987 placement = new FilePlacement(); 988 } 989 990 if (placement.projection != null) { 991 String projectionCode = placement.projection.toCode(); 992 BIG_LOOP: 993 for (ProjectionChoice projectionChoice: ProjectionPreference.getProjectionChoices()) { 994 for (String code: projectionChoice.allCodes()) { 995 if (code.equals(projectionCode)) { 996 projectionChoice.getPreferencesFromCode(projectionCode); 997 this.projectionCombo.setSelectedItem(projectionChoice); 998 break BIG_LOOP; 999 } 1000 } 1001 } 1002 } 1003 1004 this.minXField.setText(Double.toString(placement.minX)); 1005 this.maxXField.setText(Double.toString(placement.maxX)); 1006 this.minYField.setText(Double.toString(placement.minY)); 1007 this.maxYField.setText(Double.toString(placement.maxY)); 1008 this.minEastField.setText(Double.toString(placement.minEast)); 1009 this.maxEastField.setText(Double.toString(placement.maxEast)); 1010 this.minNorthField.setText(Double.toString(placement.minNorth)); 1011 this.maxNorthField.setText(Double.toString(placement.maxNorth)); 1012 } 1013 1014 1015 private FilePlacement loadPlacement() { 1016 FilePlacement pl = null; 1017 //load saved transformation 1018 File propertiesFile = new File(fileName.getAbsoluteFile()+ ".placement"); 1019 try { 1020 1021 if (propertiesFile.exists()){ 1022 pl = new FilePlacement(); 1023 Properties p = new Properties(); 1024 p.load(new FileInputStream(propertiesFile)); 1025 pl.fromProperties(p); 1026 } 1027 }catch (Exception e){ 1028 pl = null; 1029 e.printStackTrace(); 1030 } 1031 1032 return pl; 1033 } 1034 1035 private void savePlacement(FilePlacement pl){ 1036 //load saved transformation 1037 File propertiesFile = new File(fileName.getAbsoluteFile()+ ".placement"); 1038 try { 1039 Properties p = pl.toProperties(); 1040 p.store(new FileOutputStream(propertiesFile), "PDF file placement on OSM"); 1041 } catch (Exception e){ 1042 e.printStackTrace(); 1043 } 1044 } 1045 1046 1047 private OsmDataLayer makeLayer(String name, FilePlacement placement, OsmBuilder.Mode mode, ProgressMonitor monitor) { 1048 monitor.beginTask(tr("Building JOSM layer"), 100); 1049 OsmBuilder builder = new OsmBuilder(placement); 1050 DataSet data = builder.build(this.data.getLayers(), mode, monitor.createSubTaskMonitor(50, false)); 1051 monitor.setTicks(50); 1052 monitor.setCustomText(tr("Postprocessing layer")); 1053 OsmDataLayer result = new OsmDataLayer(data, name, null); 1054 result.onPostLoadFromFile(); 1055 1056 monitor.finishTask(); 1057 return result; 1058 } 1059 1060 private void placeLayer(OsmDataLayer _layer, FilePlacement placement) { 1061 this.removeLayer(); 1062 this.layer = _layer; 1063 Main.getLayerManager().addLayer(this.layer); 1064 Main.map.mapView.zoomTo(placement.getWorldBounds(this.data)); 1065 } 1066 1067 private void removeLayer() { 1068 if (this.layer != null) { 1069 Main.getLayerManager().removeLayer(this.layer); 1070 this.layer.data.clear(); //saves memory 1071 this.layer = null; 1072 } 1073 } 1074 1075 private void saveLayer(java.io.File file, FilePlacement placement, ProgressMonitor monitor) { 1076 monitor.beginTask(tr("Saving to file."), 1000); 1077 1078 OsmBuilder builder = new OsmBuilder(placement); 1079 DataSet data = builder.build(this.data.getLayers(), OsmBuilder.Mode.Final, monitor.createSubTaskMonitor(500, false)); 1080 OsmDataLayer layer = new OsmDataLayer(data, file.getName(), file); 1081 1082 monitor.setCustomText(tr(" Writing to file")); 1083 monitor.setTicks(500); 1084 1085 OsmExporter exporter = new OsmExporter(); 1086 1087 try { 1088 exporter.exportData(file, layer); 1089 } 1090 catch(IOException e){ 1091 //TODO: 1092 } 1093 1094 monitor.finishTask(); 1095 } 66 public class LoadPdfDialog extends JFrame { 67 68 class LoadProgressRenderer implements ProgressRenderer { 69 private final JProgressBar pBar; 70 private String title = ""; 71 72 LoadProgressRenderer(JProgressBar pb) { 73 this.pBar = pb; 74 this.pBar.setMinimum(0); 75 this.pBar.setValue(0); 76 this.pBar.setMaximum(1); 77 this.pBar.setString(""); 78 this.pBar.setStringPainted(true); 79 80 } 81 82 @Override 83 public void setCustomText(String message) { 84 this.pBar.setString(this.title + message); 85 } 86 87 @Override 88 public void setIndeterminate(boolean indeterminate) { 89 this.pBar.setIndeterminate(indeterminate); 90 } 91 92 @Override 93 public void setMaximum(int maximum) { 94 this.pBar.setMaximum(maximum); 95 } 96 97 @Override 98 public void setTaskTitle(String taskTitle) { 99 this.title = taskTitle; 100 this.pBar.setString(this.title); 101 } 102 103 @Override 104 public void setValue(int value) { 105 this.pBar.setValue(value); 106 } 107 108 public void finish() { 109 this.pBar.setString(tr("Finished")); 110 this.pBar.setValue(this.pBar.getMaximum()); 111 } 112 113 } 114 115 private File fileName; 116 private PathOptimizer data; 117 private OsmDataLayer layer; 118 119 /** 120 * Combobox with all projections available 121 */ 122 private JComboBox<ProjectionChoice> projectionCombo; 123 private JButton projectionPreferencesButton; 124 private JTextField minXField; 125 private JTextField minYField; 126 private JTextField minEastField; 127 private JTextField minNorthField; 128 private JButton getMinButton; 129 private JButton okButton; 130 private JButton cancelButton; 131 private JButton getMaxButton; 132 private JTextField maxNorthField; 133 private JTextField maxEastField; 134 private JTextField maxYField; 135 private JTextField maxXField; 136 private JButton loadFileButton; 137 private JButton showButton; 138 private JButton saveButton; 139 private JCheckBox debugModeCheck; 140 private JCheckBox mergeCloseNodesCheck; 141 private JTextField mergeCloseNodesTolerance; 142 private JCheckBox removeSmallObjectsCheck; 143 private JTextField removeSmallObjectsSize; 144 private JTextField colorFilterColor; 145 private JCheckBox colorFilterCheck; 146 private JCheckBox removeParallelSegmentsCheck; 147 private JTextField removeParallelSegmentsTolerance; 148 private JCheckBox removeLargeObjectsCheck; 149 private JTextField removeLargeObjectsSize; 150 private JProgressBar loadProgress; 151 protected OsmDataLayer newLayer; 152 153 private LoadProgressRenderer progressRenderer; 154 private JCheckBox limitPathCountCheck; 155 private JTextField limitPathCount; 156 private JCheckBox splitOnColorChangeCheck; 157 private JCheckBox splitOnShapeClosedCheck; 158 private JCheckBox splitOnSingleSegmentCheck; 159 private JCheckBox splitOnOrthogonalCheck; 160 161 public LoadPdfDialog() { 162 this.buildGUI(); 163 FilePlacement pl = new FilePlacement(); 164 this.setPlacement(pl); 165 this.addListeners(); 166 this.removeLayer(); 167 } 168 169 private void addListeners() { 170 171 this.projectionCombo.addActionListener(new ActionListener() { 172 @Override 173 public void actionPerformed(ActionEvent e) { 174 updateProjectionPrefButton(); 175 } 176 177 }); 178 this.projectionPreferencesButton.addActionListener(new ActionListener() { 179 @Override 180 public void actionPerformed(ActionEvent e) { 181 showProjectionPreferences(); 182 } 183 }); 184 185 this.loadFileButton.addActionListener(new ActionListener() { 186 @Override 187 public void actionPerformed(ActionEvent e) { 188 loadFilePressed(); 189 } 190 }); 191 192 this.okButton.addActionListener(new ActionListener() { 193 @Override 194 public void actionPerformed(ActionEvent e) { 195 okPressed(); 196 } 197 }); 198 199 this.saveButton.addActionListener(new ActionListener() { 200 @Override 201 public void actionPerformed(ActionEvent e) { 202 savePressed(); 203 } 204 }); 205 206 this.showButton.addActionListener(new ActionListener() { 207 @Override 208 public void actionPerformed(ActionEvent e) { 209 showPressed(); 210 } 211 }); 212 213 this.cancelButton.addActionListener(new ActionListener() { 214 @Override 215 public void actionPerformed(ActionEvent e) { 216 cancelPressed(); 217 } 218 }); 219 220 this.addWindowListener(new WindowAdapter() { 221 @Override 222 public void windowClosing(WindowEvent e) { 223 cancelPressed(); 224 } 225 }); 226 227 this.getMinButton.addActionListener(new ActionListener() { 228 @Override 229 public void actionPerformed(ActionEvent e) { 230 getMinPressed(); 231 } 232 }); 233 234 this.getMaxButton.addActionListener(new ActionListener() { 235 @Override 236 public void actionPerformed(ActionEvent e) { 237 getMaxPressed(); 238 } 239 }); 240 } 241 242 private void buildGUI() { 243 GridBagConstraints c = new GridBagConstraints(); 244 c.gridheight = 1; c.gridwidth = 1; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; 245 246 this.projectionCombo = new JComboBox<>(); 247 for (ProjectionChoice p: ProjectionPreference.getProjectionChoices()) { 248 this.projectionCombo.addItem(p); 249 } 250 251 this.projectionPreferencesButton = new JButton(tr("Prefs")); 252 updateProjectionPrefButton(); 253 254 this.loadFileButton = new JButton(tr("Load file...")); 255 this.okButton = new JButton(tr("Place")); 256 this.saveButton = new JButton(tr("Save")); 257 this.showButton = new JButton(tr("Show target")); 258 this.cancelButton = new JButton(tr("Discard")); 259 this.loadProgress = new JProgressBar(); 260 this.progressRenderer = new LoadProgressRenderer(this.loadProgress); 261 262 this.minXField = new JTextField(""); 263 this.minYField = new JTextField(""); 264 this.minEastField = new JTextField(""); 265 this.minNorthField = new JTextField(""); 266 this.getMinButton = new JButton(tr("Take X and Y from selected node")); 267 268 this.maxXField = new JTextField(""); 269 this.maxYField = new JTextField(""); 270 this.maxEastField = new JTextField(""); 271 this.maxNorthField = new JTextField(""); 272 this.getMaxButton = new JButton(tr("Take X and Y from selected node")); 273 274 this.debugModeCheck = new JCheckBox(tr("Debug info")); 275 this.mergeCloseNodesCheck = new JCheckBox(tr("Merge close nodes")); 276 this.mergeCloseNodesTolerance = new JTextField("1e-3"); 277 278 this.removeSmallObjectsCheck = new JCheckBox(tr("Remove objects smaller than")); 279 this.removeSmallObjectsSize = new JTextField("1"); 280 281 this.removeLargeObjectsCheck = new JCheckBox(tr("Remove objects larger than")); 282 this.removeLargeObjectsSize = new JTextField("10"); 283 284 285 this.colorFilterCheck = new JCheckBox(tr("Only this color")); 286 this.colorFilterColor = new JTextField("#000000"); 287 288 this.removeParallelSegmentsCheck = new JCheckBox(tr("Remove parallel lines")); 289 this.removeParallelSegmentsTolerance = new JTextField("3"); 290 291 this.limitPathCountCheck = new JCheckBox(tr("Take only first X paths")); 292 this.limitPathCount = new JTextField("10000"); 293 294 this.splitOnColorChangeCheck = new JCheckBox(tr("Color/width change")); 295 this.splitOnShapeClosedCheck = new JCheckBox(tr("Shape closed")); 296 this.splitOnSingleSegmentCheck = new JCheckBox(tr("Single segments")); 297 this.splitOnOrthogonalCheck = new JCheckBox(tr("Orthogonal shapes")); 298 299 JPanel configPanel = new JPanel(new GridBagLayout()); 300 configPanel.setBorder(BorderFactory.createTitledBorder(tr("Import settings"))); 301 c.gridx = 0; c.gridy = 0; c.gridwidth = 1; 302 configPanel.add(this.mergeCloseNodesCheck, c); 303 c.gridx = 1; c.gridy = 0; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 304 configPanel.add(new JLabel("Tolerance :"), c); 305 c.gridx = 2; c.gridy = 0; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 306 configPanel.add(this.mergeCloseNodesTolerance, c); 307 308 c.gridx = 0; c.gridy = 1; c.gridwidth = 1; 309 configPanel.add(this.removeSmallObjectsCheck, c); 310 c.gridx = 1; c.gridy = 1; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 311 configPanel.add(new JLabel("Tolerance :"), c); 312 c.gridx = 2; c.gridy = 1; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 313 configPanel.add(this.removeSmallObjectsSize, c); 314 315 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 316 configPanel.add(this.removeLargeObjectsCheck, c); 317 c.gridx = 1; c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 318 configPanel.add(new JLabel("Tolerance :"), c); 319 c.gridx = 2; c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 320 configPanel.add(this.removeLargeObjectsSize, c); 321 322 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 323 configPanel.add(this.removeParallelSegmentsCheck, c); 324 c.gridx = 1; c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHEAST; 325 configPanel.add(new JLabel("Max distance :"), c); 326 c.gridx = 2; c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.NORTHWEST; 327 configPanel.add(this.removeParallelSegmentsTolerance, c); 328 329 330 c.gridx = 0; c.gridy = 4; c.gridwidth = 2; 331 configPanel.add(this.limitPathCountCheck, c); 332 c.gridx = 2; c.gridy = 4; c.gridwidth = 1; 333 configPanel.add(this.limitPathCount, c); 334 335 c.gridx = 0; c.gridy = 5; c.gridwidth = 1; 336 configPanel.add(this.colorFilterCheck, c); 337 c.gridx = 2; c.gridy = 5; c.gridwidth = 1; 338 configPanel.add(this.colorFilterColor, c); 339 340 c.gridx = 0; c.gridy = 6; c.gridwidth = 2; 341 configPanel.add(this.debugModeCheck, c); 342 343 344 c.gridx = 0; c.gridy = 7; c.gridwidth = 1; 345 configPanel.add(new JLabel(tr("Introduce separate layers for:")), c); 346 c.gridx = 1; c.gridy = 7; c.gridwidth = 1; 347 configPanel.add(this.splitOnShapeClosedCheck, c); 348 c.gridx = 2; c.gridy = 7; c.gridwidth = 1; 349 configPanel.add(this.splitOnSingleSegmentCheck, c); 350 c.gridx = 1; c.gridy = 8; c.gridwidth = 1; 351 configPanel.add(this.splitOnColorChangeCheck, c); 352 c.gridx = 2; c.gridy = 8; c.gridwidth = 1; 353 configPanel.add(this.splitOnOrthogonalCheck, c); 354 355 356 JPanel projectionPanel = new JPanel(new GridBagLayout()); 357 projectionPanel.setBorder(BorderFactory.createTitledBorder(tr("Bind to coordinates"))); 358 359 JPanel projectionSubPanel = new JPanel(); 360 projectionSubPanel.setLayout(new BoxLayout(projectionSubPanel, BoxLayout.X_AXIS)); 361 362 projectionSubPanel.add(new JLabel(tr("Projection:"))); 363 projectionSubPanel.add(this.projectionCombo); 364 projectionSubPanel.add(this.projectionPreferencesButton); 365 c.gridx = 0; c.gridy = 0; c.gridwidth = 3; 366 projectionPanel.add(projectionSubPanel, c); 367 368 c.gridx = 0; c.gridy = 1; c.gridwidth = 2; 369 projectionPanel.add(new JLabel(tr("Bottom left (min) corner:")), c); 370 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 371 projectionPanel.add(new JLabel(tr("PDF X and Y")), c); 372 c.gridx = 1; c.gridy = 2; c.gridwidth = 1; 373 projectionPanel.add(new JLabel(tr("East and North")), c); 374 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 375 projectionPanel.add(this.minXField, c); 376 c.gridx = 0; c.gridy = 4; c.gridwidth = 1; 377 projectionPanel.add(this.minYField, c); 378 c.gridx = 1; c.gridy = 3; c.gridwidth = 1; 379 projectionPanel.add(this.minEastField, c); 380 c.gridx = 1; c.gridy = 4; c.gridwidth = 1; 381 projectionPanel.add(this.minNorthField, c); 382 c.gridx = 0; c.gridy = 5; c.gridwidth = 1; 383 projectionPanel.add(this.getMinButton, c); 384 385 386 c.gridx = 0; c.gridy = 6; c.gridwidth = 2; 387 projectionPanel.add(new JLabel(tr("Top right (max) corner:")), c); 388 c.gridx = 0; c.gridy = 7; c.gridwidth = 1; 389 projectionPanel.add(new JLabel(tr("PDF X and Y")), c); 390 c.gridx = 1; c.gridy = 7; c.gridwidth = 1; 391 projectionPanel.add(new JLabel(tr("East and North")), c); 392 c.gridx = 0; c.gridy = 8; c.gridwidth = 1; 393 projectionPanel.add(this.maxXField, c); 394 c.gridx = 0; c.gridy = 9; c.gridwidth = 1; 395 projectionPanel.add(this.maxYField, c); 396 c.gridx = 1; c.gridy = 8; c.gridwidth = 1; 397 projectionPanel.add(this.maxEastField, c); 398 c.gridx = 1; c.gridy = 9; c.gridwidth = 1; 399 projectionPanel.add(this.maxNorthField, c); 400 c.gridx = 0; c.gridy = 10; c.gridwidth = 1; 401 projectionPanel.add(this.getMaxButton, c); 402 403 JPanel okCancelPanel = new JPanel(new GridLayout(1, 3)); 404 okCancelPanel.add(this.cancelButton); 405 okCancelPanel.add(this.showButton); 406 okCancelPanel.add(this.okButton); 407 okCancelPanel.add(this.saveButton); 408 409 JPanel panel = new JPanel(new GridBagLayout()); 410 c.gridx = 0; c.gridy = 0; c.gridwidth = 1; 411 panel.add(configPanel, c); 412 c.gridx = 0; c.gridy = 1; c.gridwidth = 1; 413 panel.add(loadFileButton, c); 414 c.gridx = 0; c.gridy = 2; c.gridwidth = 1; 415 panel.add(projectionPanel, c); 416 c.gridx = 0; c.gridy = 3; c.gridwidth = 1; 417 panel.add(okCancelPanel, c); 418 c.gridx = 0; c.gridy = 4; c.gridwidth = 1; 419 panel.add(this.loadProgress, c); 420 421 this.setSize(450, 550); 422 this.setContentPane(panel); 423 } 424 425 private class ProjectionSubPrefsDialog extends JDialog { 426 private final ProjectionChoice projPref; 427 private OKAction actOK; 428 private CancelAction actCancel; 429 private JPanel projPrefPanel; 430 431 ProjectionSubPrefsDialog(Component parent, ProjectionChoice pr) { 432 super(JOptionPane.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL); 433 434 projPref = pr; 435 436 setTitle(tr("Projection Preferences")); 437 setDefaultCloseOperation(DISPOSE_ON_CLOSE); 438 439 build(); 440 } 441 442 protected void makeButtonRespondToEnter(SideButton btn) { 443 btn.setFocusable(true); 444 btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter"); 445 btn.getActionMap().put("enter", btn.getAction()); 446 } 447 448 protected JPanel buildInputForm() { 449 return projPref.getPreferencePanel(null); 450 } 451 452 protected JPanel buildButtonRow() { 453 JPanel pnl = new JPanel(new FlowLayout()); 454 455 actOK = new OKAction(); 456 actCancel = new CancelAction(); 457 458 SideButton btn; 459 pnl.add(btn = new SideButton(actOK)); 460 makeButtonRespondToEnter(btn); 461 pnl.add(btn = new SideButton(actCancel)); 462 makeButtonRespondToEnter(btn); 463 return pnl; 464 } 465 466 protected void build() { 467 projPrefPanel = buildInputForm(); 468 getContentPane().setLayout(new BorderLayout()); 469 getContentPane().add(projPrefPanel, BorderLayout.CENTER); 470 getContentPane().add(buildButtonRow(), BorderLayout.SOUTH); 471 pack(); 472 473 // make dialog respond to ESCAPE 474 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( 475 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape"); 476 getRootPane().getActionMap().put("escape", actCancel); 477 } 478 479 class OKAction extends AbstractAction { 480 OKAction() { 481 putValue(NAME, tr("OK")); 482 putValue(SHORT_DESCRIPTION, tr("Close the dialog and apply projection preferences")); 483 putValue(SMALL_ICON, ImageProvider.get("ok")); 484 } 485 486 @Override 487 public void actionPerformed(ActionEvent e) { 488 projPref.setPreferences(projPref.getPreferences(projPrefPanel)); 489 setVisible(false); 490 } 491 } 492 493 class CancelAction extends AbstractAction { 494 CancelAction() { 495 putValue(NAME, tr("Cancel")); 496 putValue(SHORT_DESCRIPTION, tr("Close the dialog, discard projection preference changes")); 497 putValue(SMALL_ICON, ImageProvider.get("cancel")); 498 } 499 500 @Override 501 public void actionPerformed(ActionEvent e) { 502 setVisible(false); 503 } 504 } 505 506 @Override 507 public void setVisible(boolean visible) { 508 if (visible) { 509 new WindowGeometry( 510 getClass().getName() + ".geometry", 511 WindowGeometry.centerOnScreen(new Dimension(400, 300))).applySafe(this); 512 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 513 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 514 } 515 super.setVisible(visible); 516 } 517 } 518 519 private void updateProjectionPrefButton() { 520 // ProjectionChoice proj = (ProjectionChoice) projectionCombo.getSelectedItem(); 521 522 //TODO 523 // Enable/disable pref button 524 // if(!(proj instanceof ProjectionSubPrefs)) { 525 // projectionPreferencesButton.setEnabled(false); 526 // } else { 527 projectionPreferencesButton.setEnabled(true); 528 // } 529 } 530 531 private void showProjectionPreferences() { 532 ProjectionChoice proj = (ProjectionChoice) projectionCombo.getSelectedItem(); 533 534 ProjectionSubPrefsDialog dlg = new ProjectionSubPrefsDialog(this, proj); 535 dlg.setVisible(true); 536 537 } 538 539 private void loadFilePressed() { 540 final File newFileName = this.chooseFile(); 541 542 if (newFileName == null) { 543 return; 544 } 545 546 this.removeLayer(); 547 548 this.loadFileButton.setEnabled(false); 549 this.loadFileButton.setText(tr("Loading...")); 550 551 this.runAsBackgroundTask( 552 new Runnable() { 553 @Override 554 public void run() { 555 //async part 556 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 557 monitor.beginTask("Loading file", 1000); 558 data = loadPDF(newFileName, monitor.createSubTaskMonitor(500, false)); 559 OsmBuilder.Mode mode = LoadPdfDialog.this.debugModeCheck.isSelected() ? OsmBuilder.Mode.Debug : OsmBuilder.Mode.Draft; 560 561 if (data != null) { 562 LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer( 563 tr("PDF file preview"), new FilePlacement(), mode, monitor.createSubTaskMonitor(500, false)); 564 } 565 566 monitor.finishTask(); 567 progressRenderer.finish(); 568 } 569 }, 570 new ActionListener() { 571 572 @Override 573 public void actionPerformed(ActionEvent e) { 574 //sync part 575 if (data != null) { 576 LoadPdfDialog.this.placeLayer(newLayer, new FilePlacement()); 577 fileName = newFileName; 578 newLayer = null; 579 LoadPdfDialog.this.loadFileButton.setText(tr("Loaded")); 580 LoadPdfDialog.this.loadFileButton.setEnabled(true); 581 FilePlacement placement = LoadPdfDialog.this.loadPlacement(); 582 LoadPdfDialog.this.setPlacement(placement); 583 } 584 } 585 }); 586 } 587 588 private FilePlacement preparePlacement() { 589 FilePlacement placement = this.parsePlacement(); 590 if (placement == null) { 591 return null; 592 } 593 594 String transformError = placement.prepareTransform(); 595 if (transformError != null) { 596 JOptionPane.showMessageDialog(Main.parent, transformError); 597 return null; 598 } 599 600 this.savePlacement(placement); 601 602 return placement; 603 } 604 605 private void okPressed() { 606 607 final FilePlacement placement = preparePlacement(); 608 if (placement == null) { 609 return; 610 } 611 612 this.removeLayer(); 613 614 this.runAsBackgroundTask( 615 new Runnable() { 616 @Override 617 public void run() { 618 //async part 619 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 620 LoadPdfDialog.this.newLayer = LoadPdfDialog.this.makeLayer( 621 tr("Imported PDF: ") + fileName, placement, OsmBuilder.Mode.Final, monitor); 622 progressRenderer.finish(); 623 } 624 }, 625 new ActionListener() { 626 627 @Override 628 public void actionPerformed(ActionEvent e) { 629 //sync part 630 //rebuild layer with latest projection 631 LoadPdfDialog.this.placeLayer(newLayer, placement); 632 LoadPdfDialog.this.setVisible(false); 633 } 634 }); 635 } 636 637 private void savePressed() { 638 639 final FilePlacement placement = preparePlacement(); 640 if (placement == null) { 641 return; 642 } 643 644 final java.io.File file = this.chooseSaveFile(); 645 646 if (file == null) { 647 return; 648 } 649 650 this.removeLayer(); 651 652 this.runAsBackgroundTask( 653 new Runnable() { 654 @Override 655 public void run() { 656 //async part 657 SwingRenderingProgressMonitor monitor = new SwingRenderingProgressMonitor(progressRenderer); 658 LoadPdfDialog.this.saveLayer(file, placement, monitor); 659 progressRenderer.finish(); 660 } 661 }, 662 new ActionListener() { 663 664 @Override 665 public void actionPerformed(ActionEvent e) { 666 //sync part 667 LoadPdfDialog.this.setVisible(false); 668 } 669 }); 670 } 671 672 private void showPressed() { 673 674 FilePlacement placement = preparePlacement(); 675 if (placement == null) { 676 return; 677 } 678 679 //zoom to new location 680 Main.map.mapView.zoomTo(placement.getWorldBounds(this.data)); 681 Main.map.repaint(); 682 } 683 684 private void cancelPressed() { 685 this.removeLayer(); 686 this.setVisible(false); 687 } 688 689 private void getMinPressed() { 690 EastNorth en = this.getSelectedCoor(); 691 692 if (en != null) { 693 this.minXField.setText(Double.toString(en.east())); 694 this.minYField.setText(Double.toString(en.north())); 695 } 696 } 697 698 private void getMaxPressed() { 699 EastNorth en = this.getSelectedCoor(); 700 701 if (en != null) { 702 this.maxXField.setText(Double.toString(en.east())); 703 this.maxYField.setText(Double.toString(en.north())); 704 } 705 } 706 707 // Implementation methods 708 709 private EastNorth getSelectedCoor() { 710 Collection<OsmPrimitive> selected = Main.getLayerManager().getEditDataSet().getSelected(); 711 712 if (selected.size() != 1 || !(selected.iterator().next() instanceof Node)) { 713 JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly one node.")); 714 return null; 715 } 716 717 LatLon ll = ((Node) selected.iterator().next()).getCoor(); 718 FilePlacement pl = new FilePlacement(); 719 return pl.reverseTransform(ll); 720 } 721 722 private java.io.File chooseFile() { 723 //get file name 724 JFileChooser fc = new JFileChooser(); 725 fc.setAcceptAllFileFilterUsed(false); 726 fc.setMultiSelectionEnabled(false); 727 fc.setSelectedFile(this.fileName); 728 fc.setFileFilter(new FileFilter() { 729 @Override 730 public boolean accept(java.io.File pathname) { 731 return pathname.isDirectory() || pathname.getName().endsWith(".pdf"); 732 } 733 734 @Override 735 public String getDescription() { 736 return tr("PDF files"); 737 } 738 }); 739 int result = fc.showOpenDialog(Main.parent); 740 741 if (result != JFileChooser.APPROVE_OPTION) { 742 return null; 743 } else { 744 return fc.getSelectedFile(); 745 } 746 } 747 748 private java.io.File chooseSaveFile() { 749 //get file name 750 JFileChooser fc = new JFileChooser(); 751 fc.setAcceptAllFileFilterUsed(true); 752 fc.setMultiSelectionEnabled(false); 753 fc.setFileFilter(new FileFilter() { 754 @Override 755 public boolean accept(java.io.File pathname) { 756 return pathname.isDirectory() || pathname.getName().endsWith(".osm"); 757 } 758 759 @Override 760 public String getDescription() { 761 return tr("OSM files"); 762 } 763 }); 764 int result = fc.showOpenDialog(Main.parent); 765 766 if (result != JFileChooser.APPROVE_OPTION) { 767 return null; 768 } else { 769 return fc.getSelectedFile(); 770 } 771 } 772 773 private void runAsBackgroundTask(final Runnable task, final ActionListener after) { 774 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 775 Thread t = new Thread(new Runnable() { 776 @Override 777 public void run() { 778 task.run(); 779 780 SwingUtilities.invokeLater(new Runnable() { 781 @Override 782 public void run() { 783 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 784 after.actionPerformed(null); 785 } 786 }); 787 } 788 }); 789 t.start(); 790 } 791 792 private PathOptimizer loadPDF(File fileName, ProgressMonitor monitor) { 793 794 monitor.beginTask("", 100); 795 monitor.setTicks(0); 796 monitor.setCustomText(tr("Preparing")); 797 798 double nodesTolerance = 0.0; 799 Color color = null; 800 int maxPaths = Integer.MAX_VALUE; 801 802 if (this.mergeCloseNodesCheck.isSelected()) { 803 try { 804 nodesTolerance = Double.parseDouble(this.mergeCloseNodesTolerance.getText()); 805 } catch (Exception e) { 806 JOptionPane 807 .showMessageDialog( 808 Main.parent, 809 tr("Tolerance is not a number")); 810 return null; 811 } 812 } 813 814 if (this.colorFilterCheck.isSelected()) { 815 try { 816 String colString = this.colorFilterColor.getText().replace("#", ""); 817 color = new Color(Integer.parseInt(colString, 16)); 818 } catch (Exception e) { 819 JOptionPane 820 .showMessageDialog( 821 Main.parent, 822 tr("Could not parse color")); 823 return null; 824 } 825 } 826 827 if (this.limitPathCountCheck.isSelected()) { 828 try { 829 maxPaths = Integer.parseInt(this.limitPathCount.getText()); 830 } catch (Exception e) { 831 JOptionPane 832 .showMessageDialog( 833 Main.parent, 834 tr("Could not parse max path count")); 835 return null; 836 } 837 } 838 839 840 monitor.setTicks(10); 841 monitor.setCustomText(tr("Parsing file")); 842 843 PathOptimizer data = new PathOptimizer(nodesTolerance, color, this.splitOnColorChangeCheck.isSelected()); 844 845 try { 846 PdfBoxParser parser = new PdfBoxParser(data); 847 parser.parse(fileName, maxPaths, monitor.createSubTaskMonitor(80, false)); 848 849 } catch (FileNotFoundException e1) { 850 JOptionPane 851 .showMessageDialog( 852 Main.parent, 853 tr("File not found.")); 854 return null; 855 } catch (Exception e) { 856 e.printStackTrace(); 857 JOptionPane 858 .showMessageDialog( 859 Main.parent, 860 tr("Error while parsing: {0}", e.getMessage())); 861 return null; 862 } 863 864 monitor.setTicks(80); 865 866 if (this.removeParallelSegmentsCheck.isSelected()) { 867 try { 868 double tolerance = Double.parseDouble(this.removeParallelSegmentsTolerance.getText()); 869 monitor.setCustomText(tr("Removing parallel segments")); 870 data.removeParallelLines(tolerance); 871 } catch (Exception e) { 872 JOptionPane 873 .showMessageDialog( 874 Main.parent, 875 tr("Max distance is not a number")); 876 return null; 877 } 878 } 879 880 if (nodesTolerance > 0.0) { 881 monitor.setTicks(83); 882 monitor.setCustomText(tr("Joining nodes")); 883 data.mergeNodes(); 884 } 885 886 monitor.setTicks(85); 887 monitor.setCustomText(tr("Joining adjacent segments")); 888 data.mergeSegments(); 889 890 if (this.removeSmallObjectsCheck.isSelected()) { 891 try { 892 double tolerance = Double.parseDouble(this.removeSmallObjectsSize.getText()); 893 monitor.setTicks(90); 894 monitor.setCustomText(tr("Removing small objects")); 895 896 data.removeSmallObjects(tolerance); 897 } catch (Exception e) { 898 JOptionPane 899 .showMessageDialog( 900 Main.parent, 901 tr("Tolerance is not a number")); 902 return null; 903 } 904 } 905 906 if (this.removeLargeObjectsCheck.isSelected()) { 907 try { 908 double tolerance = Double.parseDouble(this.removeLargeObjectsSize.getText()); 909 monitor.setTicks(90); 910 monitor.setCustomText(tr("Removing large objects")); 911 data.removeLargeObjects(tolerance); 912 } catch (Exception e) { 913 JOptionPane 914 .showMessageDialog( 915 Main.parent, 916 tr("Tolerance is not a number")); 917 return null; 918 } 919 } 920 921 monitor.setTicks(95); 922 monitor.setCustomText(tr("Finalizing layers")); 923 data.splitLayersByPathKind( 924 this.splitOnShapeClosedCheck.isSelected(), 925 this.splitOnSingleSegmentCheck.isSelected(), 926 this.splitOnOrthogonalCheck.isSelected()); 927 data.finish(); 928 929 monitor.finishTask(); 930 return data; 931 } 932 933 private FilePlacement parsePlacement() { 934 ProjectionChoice selectedProjection = (ProjectionChoice) this.projectionCombo.getSelectedItem(); 935 936 if (selectedProjection == null) { 937 JOptionPane.showMessageDialog(Main.parent, tr("Please set a projection.")); 938 return null; 939 } 940 941 FilePlacement placement = new FilePlacement(); 942 943 placement.projection = selectedProjection.getProjection(); 944 945 try { 946 placement.setPdfBounds( 947 Double.parseDouble(this.minXField.getText()), 948 Double.parseDouble(this.minYField.getText()), 949 Double.parseDouble(this.maxXField.getText()), 950 Double.parseDouble(this.maxYField.getText())); 951 placement.setEastNorthBounds( 952 Double.parseDouble(this.minEastField.getText()), 953 Double.parseDouble(this.minNorthField.getText()), 954 Double.parseDouble(this.maxEastField.getText()), 955 Double.parseDouble(this.maxNorthField.getText())); 956 } catch (Exception e) { 957 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse numbers. Please check.")); 958 return null; 959 } 960 961 return placement; 962 } 963 964 private void setPlacement(FilePlacement placement) { 965 966 if (placement == null) { 967 //use default values. 968 placement = new FilePlacement(); 969 } 970 971 if (placement.projection != null) { 972 String projectionCode = placement.projection.toCode(); 973 BIG_LOOP: 974 for (ProjectionChoice projectionChoice: ProjectionPreference.getProjectionChoices()) { 975 for (String code: projectionChoice.allCodes()) { 976 if (code.equals(projectionCode)) { 977 projectionChoice.getPreferencesFromCode(projectionCode); 978 this.projectionCombo.setSelectedItem(projectionChoice); 979 break BIG_LOOP; 980 } 981 } 982 } 983 } 984 985 this.minXField.setText(Double.toString(placement.minX)); 986 this.maxXField.setText(Double.toString(placement.maxX)); 987 this.minYField.setText(Double.toString(placement.minY)); 988 this.maxYField.setText(Double.toString(placement.maxY)); 989 this.minEastField.setText(Double.toString(placement.minEast)); 990 this.maxEastField.setText(Double.toString(placement.maxEast)); 991 this.minNorthField.setText(Double.toString(placement.minNorth)); 992 this.maxNorthField.setText(Double.toString(placement.maxNorth)); 993 } 994 995 private FilePlacement loadPlacement() { 996 FilePlacement pl = null; 997 //load saved transformation 998 File propertiesFile = new File(fileName.getAbsoluteFile()+ ".placement"); 999 try { 1000 1001 if (propertiesFile.exists()) { 1002 pl = new FilePlacement(); 1003 Properties p = new Properties(); 1004 p.load(new FileInputStream(propertiesFile)); 1005 pl.fromProperties(p); 1006 } 1007 } catch (Exception e) { 1008 pl = null; 1009 e.printStackTrace(); 1010 } 1011 1012 return pl; 1013 } 1014 1015 private void savePlacement(FilePlacement pl) { 1016 //load saved transformation 1017 File propertiesFile = new File(fileName.getAbsoluteFile()+ ".placement"); 1018 try { 1019 Properties p = pl.toProperties(); 1020 p.store(new FileOutputStream(propertiesFile), "PDF file placement on OSM"); 1021 } catch (Exception e) { 1022 e.printStackTrace(); 1023 } 1024 } 1025 1026 private OsmDataLayer makeLayer(String name, FilePlacement placement, OsmBuilder.Mode mode, ProgressMonitor monitor) { 1027 monitor.beginTask(tr("Building JOSM layer"), 100); 1028 OsmBuilder builder = new OsmBuilder(placement); 1029 DataSet data = builder.build(this.data.getLayers(), mode, monitor.createSubTaskMonitor(50, false)); 1030 monitor.setTicks(50); 1031 monitor.setCustomText(tr("Postprocessing layer")); 1032 OsmDataLayer result = new OsmDataLayer(data, name, null); 1033 result.onPostLoadFromFile(); 1034 1035 monitor.finishTask(); 1036 return result; 1037 } 1038 1039 private void placeLayer(OsmDataLayer _layer, FilePlacement placement) { 1040 this.removeLayer(); 1041 this.layer = _layer; 1042 Main.getLayerManager().addLayer(this.layer); 1043 Main.map.mapView.zoomTo(placement.getWorldBounds(this.data)); 1044 } 1045 1046 private void removeLayer() { 1047 if (this.layer != null) { 1048 Main.getLayerManager().removeLayer(this.layer); 1049 this.layer.data.clear(); //saves memory 1050 this.layer = null; 1051 } 1052 } 1053 1054 private void saveLayer(java.io.File file, FilePlacement placement, ProgressMonitor monitor) { 1055 monitor.beginTask(tr("Saving to file."), 1000); 1056 1057 OsmBuilder builder = new OsmBuilder(placement); 1058 DataSet data = builder.build(this.data.getLayers(), OsmBuilder.Mode.Final, monitor.createSubTaskMonitor(500, false)); 1059 OsmDataLayer layer = new OsmDataLayer(data, file.getName(), file); 1060 1061 monitor.setCustomText(tr(" Writing to file")); 1062 monitor.setTicks(500); 1063 1064 OsmExporter exporter = new OsmExporter(); 1065 1066 try { 1067 exporter.exportData(file, layer); 1068 } catch (IOException e) { 1069 Main.error(e); 1070 } 1071 1072 monitor.finishTask(); 1073 } 1096 1074 1097 1075 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/OrthogonalShapesFilter.java
r25349 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 4 5 5 6 public class OrthogonalShapesFilter { 6 7 private double tolerance; 7 8 8 9 10 9 public OrthogonalShapesFilter(double toleranceDegrees) { 10 tolerance = Math.toRadians(toleranceDegrees); 11 } 11 12 12 13 public boolean isOrthogonal(PdfPath path) { 13 14 14 15 15 if (path.points.size() < 3) 16 return false; 16 17 17 18 int targetPos = path.isClosed() ? path.points.size() : path.points.size() - 1; 18 19 19 for(int pos = 1; pos < targetPos; pos++) {20 21 22 20 for (int pos = 1; pos < targetPos; pos++) { 21 Point2D p1 = path.points.get(pos -1); 22 Point2D p2 = path.points.get(pos); 23 Point2D p3 = pos+1 == path.points.size() ? path.points.get(1) : path.points.get(pos+1); 23 24 24 25 25 double angle1 = Math.atan2(p2.getY() - p1.getY(), p2.getX() - p1.getX()); 26 double angle2 = Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX()); 26 27 27 28 28 double angleDifference = angle1 - angle2; 29 while (angleDifference < 0) angleDifference += Math.PI; 29 30 30 31 31 //test straight angles 32 boolean hasGoodVariant = false; 32 33 33 34 35 36 37 34 for (int quadrant = 0; quadrant <= 4; quadrant++) { 35 double difference = angleDifference - Math.PI / 2 * quadrant; 36 if (Math.abs(difference) <= tolerance) 37 hasGoodVariant = true; 38 } 38 39 39 40 41 40 if (!hasGoodVariant) 41 return false; 42 } 42 43 43 44 44 return true; 45 } 45 46 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/OsmBuilder.java
r30737 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 19 20 public class OsmBuilder { 20 21 21 };22 enum Mode { Draft, Final, Debug } 22 23 23 24 private final FilePlacement placement; 24 25 25 26 27 28 26 private String layerName; 27 private String fillName; 28 private String lineName; 29 private Mode mode; 29 30 30 31 32 31 private ProgressMonitor monitor; 32 private int monitorPos; 33 private int monitorTotal; 33 34 34 public OsmBuilder(FilePlacement placement) 35 { 36 this.placement = placement; 37 } 35 public OsmBuilder(FilePlacement placement) { 36 this.placement = placement; 37 } 38 38 39 39 public DataSet build(List<LayerContents> data, Mode mode, ProgressMonitor monitor) { 40 40 41 42 43 44 41 this.monitor = monitor; 42 this.monitorPos = 0; 43 this.mode = mode; 44 DataSet result = new DataSet(); 45 45 46 47 48 49 50 for(PdfMultiPath mp: layer.multiPaths){51 52 53 46 //count total items for progress monitor. 47 this.monitorTotal = 0; 48 for (LayerContents layer: data) { 49 this.monitorTotal += layer.paths.size(); 50 for (PdfMultiPath mp: layer.multiPaths) { 51 this.monitorTotal += mp.paths.size(); 52 } 53 } 54 54 55 55 monitor.beginTask(tr("Building JOSM layer."), this.monitorTotal); 56 56 57 57 58 59 60 58 for (LayerContents layer: data) { 59 this.addLayer(result, layer); 60 } 61 61 62 63 64 62 monitor.finishTask(); 63 return result; 64 } 65 65 66 private void addLayer(DataSet target, LayerContents layer) { 67 Map<Point2D, Node> point2Node = new HashMap<>(); 66 68 67 private void addLayer(DataSet target, LayerContents layer) { 68 Map<Point2D, Node> point2Node = new HashMap<>(); 69 this.fillName = this.printColor(layer.info.fill); 70 this.lineName = this.printColor(layer.info.stroke); 71 this.layerName = "" + layer.info.nr; 69 72 70 this.fillName = this.printColor(layer.info.fill); 71 this.lineName = this.printColor(layer.info.stroke); 72 this.layerName = "" + layer.info.nr; 73 //insert nodes 74 for (Point2D pt: layer.points) { 75 Node node = new Node(); 76 node.setCoor(this.placement.tranformCoords(pt)); 73 77 74 //insert nodes 75 for(Point2D pt: layer.points) { 76 Node node = new Node(); 77 node.setCoor(this.placement.tranformCoords(pt)); 78 target.addPrimitive(node); 79 point2Node.put(pt, node); 80 } 78 81 79 target.addPrimitive(node); 80 point2Node.put(pt, node); 81 } 82 //insert ways 83 Map<PdfPath, Way> path2Way = new HashMap<>(); 82 84 83 //insert ways 84 Map<PdfPath, Way> path2Way = new HashMap<>(); 85 for (PdfPath path: layer.paths) { 86 Way w = this.insertWay(path, point2Node, -1, false); 87 target.addPrimitive(w); 88 path2Way.put(path, w); 89 } 85 90 86 for (PdfPath path: layer.paths){ 87 Way w = this.insertWay(path, point2Node, -1, false); 88 target.addPrimitive(w); 89 path2Way.put(path, w); 90 } 91 int pathId = 0; 92 for (PdfMultiPath mpath: layer.multiPaths) { 93 for (PdfPath path: mpath.paths) { 94 Way w = this.insertWay(path, point2Node, pathId, true); 95 target.addPrimitive(w); 96 path2Way.put(path, w); 97 } 98 pathId++; 99 } 91 100 92 int pathId = 0; 93 for (PdfMultiPath mpath: layer.multiPaths) { 94 for (PdfPath path: mpath.paths){ 95 Way w = this.insertWay(path, point2Node, pathId, true); 96 target.addPrimitive(w); 97 path2Way.put(path, w); 98 } 99 pathId ++; 100 } 101 if (this.mode != Mode.Draft) { 102 //insert relations 103 for (PdfMultiPath mpath: layer.multiPaths) { 104 Relation rel = new Relation(); 101 105 102 if (this.mode != Mode.Draft) { 103 //insert relations 104 for (PdfMultiPath mpath: layer.multiPaths) { 105 Relation rel = new Relation();106 Map<String, String> keys = new HashMap<>(); 107 keys.put("type", "multipolygon"); 108 keys.put("area", "yes"); 109 rel.setKeys(keys); 106 110 107 Map<String, String> keys = new HashMap<>(); 108 keys.put("type", "multipolygon");109 keys.put("area", "yes");110 rel.setKeys(keys); 111 for (PdfPath path: mpath.paths) { 112 Way w = path2Way.get(path); 113 rel.addMember(new RelationMember("", w)); 114 } 111 115 112 for (PdfPath path: mpath.paths){ 113 Way w = path2Way.get(path); 114 rel.addMember(new RelationMember("", w)); 115 116 target.addPrimitive(rel); 117 } 118 } 119 } 116 120 117 target.addPrimitive(rel); 118 } 119 } 120 } 121 private Way insertWay(PdfPath path, Map<Point2D, Node> point2Node, int multipathId, boolean multipolygon) { 121 122 122 private Way insertWay(PdfPath path, Map<Point2D, Node> point2Node, int multipathId, boolean multipolygon) { 123 if (this.monitorPos % 100 == 0) { 124 monitor.setExtraText(tr(" "+this.monitorPos+"/"+this.monitorTotal)); 125 monitor.setTicks(this.monitorPos); 126 } 127 this.monitorPos++; 123 128 124 if (this.monitorPos % 100 == 0) { 125 monitor.setExtraText(tr(" "+this.monitorPos+"/"+this.monitorTotal)); 126 monitor.setTicks(this.monitorPos); 127 } 128 this.monitorPos ++; 129 List<Node> nodes = new ArrayList<>(path.points.size()); 129 130 130 List<Node> nodes = new ArrayList<>(path.points.size()); 131 for (Point2D point: path.points) { 132 Node node = point2Node.get(point); 133 if (node == null) { 134 throw new RuntimeException(); 135 } 131 136 132 for (Point2D point: path.points) { 133 Node node = point2Node.get(point); 134 if (node == null) { 135 throw new RuntimeException(); 136 } 137 nodes.add(node); 138 } 137 139 138 nodes.add(node); 139 } 140 Map<String, String> keys = new HashMap<>(); 140 141 141 Map<String, String> keys = new HashMap<>(); 142 if (this.mode != Mode.Draft) { 143 keys.put("PDF_nr", "" + path.nr); 144 keys.put("PDF_layer", this.layerName); 142 145 143 if (this.mode != Mode.Draft) {144 nr", "" + path.nr);145 keys.put("PDF_layer", this.layerName); 146 if (path.isClosed()) { 147 keys.put("PDF_closed", "yes"); 148 } 146 149 147 if (path.isClosed()){148 closed", "yes");149 150 if (this.fillName != null) { 151 keys.put("PDF_fillColor", this.fillName); 152 } 150 153 151 fillName != null){152 fillColor", this.fillName);153 154 if (this.lineName != null) { 155 keys.put("PDF_lineColor", this.lineName); 156 } 154 157 155 if (this.lineName != null) { 156 keys.put("PDF_lineColor", this.lineName); 157 } 158 if (multipathId != -1) { 159 keys.put("PDF_multipath", ""+ multipathId); 160 } else if (path.layer.info.fill != null && !multipolygon) { 161 keys.put("area", "yes"); 162 } 163 } 158 164 159 if (multipathId != -1){ 160 keys.put("PDF_multipath", ""+ multipathId); 161 } 162 else if (path.layer.info.fill != null && !multipolygon) { 163 keys.put("area", "yes"); 164 } 165 } 165 if (this.mode == Mode.Debug) { 166 166 167 if (this.mode == Mode.Debug) { 167 keys.put("PDF_pathLayer", ""+path.layer.info.nr); 168 keys.put("PDF_lineWidth", ""+path.layer.info.width); 169 keys.put("PDF_lineDash", ""+path.layer.info.dash); 170 keys.put("PDF_layerHash", ""+path.layer.info.hashCode()); 171 keys.put("PDF_layerDivider", ""+path.layer.info.divider); 172 } 168 173 169 keys.put("PDF_pathLayer", ""+path.layer.info.nr); 170 keys.put("PDF_lineWidth", ""+path.layer.info.width); 171 keys.put("PDF_lineDash", ""+path.layer.info.dash); 172 keys.put("PDF_layerHash", ""+path.layer.info.hashCode()); 173 keys.put("PDF_layerDivider", ""+path.layer.info.divider); 174 } 174 Way newWay = new Way(); 175 newWay.setNodes(nodes); 176 newWay.setKeys(keys); 177 return newWay; 178 } 175 179 176 Way newWay = new Way(); 177 newWay.setNodes(nodes); 178 newWay.setKeys(keys); 179 return newWay; 180 } 180 private String printColor(Color col) { 181 if (col == null) { 182 return null; 183 } 181 184 185 String s = Integer.toHexString(col.getRGB() & 0xffffff); 186 while (s.length() < 6) { 187 s = "0" + s; 188 } 182 189 183 184 private String printColor(Color col){ 185 if (col == null){ 186 return null; 187 } 188 189 String s = Integer.toHexString(col.getRGB() & 0xffffff); 190 while (s.length() < 6) { 191 s = "0" + s; 192 } 193 194 return "#" + s; 195 } 190 return "#" + s; 191 } 196 192 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/ParallelSegmentsFinder.java
r30737 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 13 14 14 15 public class ParallelSegmentsFinder { 15 16 17 18 16 public double angle; 17 public double angleSum; 18 public int refCount; 19 public List<PdfPath> paths = new ArrayList<>(); 19 20 20 21 22 23 24 21 public void addPath(PdfPath path, double angle2) { 22 angleSum += angle2; 23 paths.add(path); 24 angle = angleSum /paths.size(); 25 } 25 26 26 public List<ParallelSegmentsFinder> splitByDistance(double maxDistance) 27 { 28 //sort perpendicular to angle 29 AffineTransform tr = new AffineTransform(); 30 tr.rotate(-angle); 27 public List<ParallelSegmentsFinder> splitByDistance(double maxDistance) { 28 //sort perpendicular to angle 29 AffineTransform tr = new AffineTransform(); 30 tr.rotate(-angle); 31 31 32 33 32 final Map<PdfPath, Point2D> positions = new HashMap<>(); 33 Point2D src = new Point2D.Double(); 34 34 35 for(PdfPath path: paths) 36 { 37 src.setLocation((path.firstPoint().getX() + path.lastPoint().getX()) / 2, (path.firstPoint().getY() + path.lastPoint().getY()) / 2); 38 Point2D dest = new Point2D.Double(); 39 Point2D destA = new Point2D.Double(); 40 Point2D destB = new Point2D.Double(); 41 tr.transform(src, dest); 42 tr.transform(path.firstPoint(), destA); 43 tr.transform(path.lastPoint(), destB); 44 positions.put(path, dest); 45 } 46 //point.y = Perpendicular lines, point.x = parallel lines 35 for (PdfPath path: paths) { 36 src.setLocation((path.firstPoint().getX() + path.lastPoint().getX()) / 2, (path.firstPoint().getY() + path.lastPoint().getY()) / 2); 37 Point2D dest = new Point2D.Double(); 38 Point2D destA = new Point2D.Double(); 39 Point2D destB = new Point2D.Double(); 40 tr.transform(src, dest); 41 tr.transform(path.firstPoint(), destA); 42 tr.transform(path.lastPoint(), destB); 43 positions.put(path, dest); 44 } 45 //point.y = Perpendicular lines, point.x = parallel lines 47 46 48 Collections.sort(paths, new Comparator<PdfPath>() { 49 public int compare(PdfPath o1, PdfPath o2) { 50 double y1 = positions.get(o1).getY(); 51 double y2 = positions.get(o2).getY(); 52 return y1 > y2 ? 1: y1 < y2 ? -1 : 0; 53 } 54 }); 47 Collections.sort(paths, new Comparator<PdfPath>() { 48 @Override 49 public int compare(PdfPath o1, PdfPath o2) { 50 double y1 = positions.get(o1).getY(); 51 double y2 = positions.get(o2).getY(); 52 return y1 > y2 ? 1 : y1 < y2 ? -1 : 0; 53 } 54 }); 55 55 56 57 56 //process sweep 57 List<ParallelSegmentsFinder> result = new ArrayList<>(); 58 58 59 59 Map<PdfPath, ParallelSegmentsFinder> sweepLine = new HashMap<>(); 60 60 61 62 63 61 Set<ParallelSegmentsFinder> adjacentClustersSet = new HashSet<>(); 62 List<ParallelSegmentsFinder> adjacentClusters = new ArrayList<>(); 63 List<PdfPath> pathsToRemove = new ArrayList<>(); 64 64 65 66 67 68 65 for (PdfPath path: paths) { 66 adjacentClusters.clear(); 67 adjacentClustersSet.clear(); 68 pathsToRemove.clear(); 69 69 70 71 72 70 for (PdfPath p: sweepLine.keySet()) { 71 Point2D pathPos = positions.get(path); 72 Point2D pPos = positions.get(p); 73 73 74 75 76 77 74 if (pathPos.getY() - pPos.getY() > maxDistance) { 75 //path too far from sweep line 76 pathsToRemove.add(p); 77 } else { 78 78 79 79 double distance = distanceLineLine(path, p); 80 80 81 if (distance <= maxDistance) { 82 if (adjacentClustersSet.add(sweepLine.get(p))) 83 { 84 adjacentClusters.add(sweepLine.get(p)); 85 } 86 } 87 } 88 } 81 if (distance <= maxDistance) { 82 if (adjacentClustersSet.add(sweepLine.get(p))) { 83 adjacentClusters.add(sweepLine.get(p)); 84 } 85 } 86 } 87 } 89 88 90 91 for(PdfPath p: pathsToRemove){92 93 94 95 96 97 89 //remove segments too far apart 90 for (PdfPath p: pathsToRemove) { 91 ParallelSegmentsFinder finder = sweepLine.remove(p); 92 finder.refCount--; 93 if (finder.refCount == 0) { 94 result.add(finder); 95 } 96 } 98 97 99 100 101 102 103 104 98 //join together joinable parts 99 if (adjacentClusters.size() > 0) { 100 ParallelSegmentsFinder finder = adjacentClusters.remove(0); 101 finder.paths.add(path); 102 sweepLine.put(path, finder); 103 finder.refCount++; 105 104 106 for(ParallelSegmentsFinder finder1: adjacentClusters){ 107 for(PdfPath path1: finder1.paths){ 108 finder.paths.add(path1); 109 sweepLine.put(path1, finder); 110 finder.refCount ++; 111 } 112 } 113 } 114 else 115 { 116 ParallelSegmentsFinder finder = new ParallelSegmentsFinder(); 117 finder.addPath(path, angle); 118 sweepLine.put(path, finder); 119 finder.refCount = 1; 120 } 121 } 105 for (ParallelSegmentsFinder finder1: adjacentClusters) { 106 for (PdfPath path1: finder1.paths) { 107 finder.paths.add(path1); 108 sweepLine.put(path1, finder); 109 finder.refCount++; 110 } 111 } 112 } else { 113 ParallelSegmentsFinder finder = new ParallelSegmentsFinder(); 114 finder.addPath(path, angle); 115 sweepLine.put(path, finder); 116 finder.refCount = 1; 117 } 118 } 122 119 123 124 125 126 127 128 129 130 120 //process remaining paths in sweep line 121 for (PdfPath p: sweepLine.keySet()) { 122 ParallelSegmentsFinder finder = sweepLine.get(p); 123 finder.refCount--; 124 if (finder.refCount == 0) { 125 result.add(finder); 126 } 127 } 131 128 132 133 129 return result; 130 } 134 131 135 136 137 132 private double distanceLineLine(PdfPath p1, PdfPath p2) { 133 return distanceLineLine(p1.firstPoint(), p1.lastPoint(), p2.firstPoint(), p2.lastPoint()); 134 } 138 135 139 140 141 142 143 144 145 136 private double distanceLineLine(Point2D p1, Point2D p2, Point2D p3, Point2D p4) { 137 double dist1 = closestPointToSegment(p1, p2, p3).distance(p3); 138 double dist2 = closestPointToSegment(p1, p2, p4).distance(p4); 139 double dist3 = closestPointToSegment(p3, p4, p1).distance(p1); 140 double dist4 = closestPointToSegment(p3, p4, p2).distance(p2); 141 return Math.min(Math.min(dist1, dist2), Math.min(dist3, dist4)); 142 } 146 143 147 /** 148 * Calculates closest point to a line segment. 149 * @param segmentP1 150 * @param segmentP2 151 * @param point 152 * @return segmentP1 if it is the closest point, segmentP2 if it is the closest point, 153 * a new point if closest point is between segmentP1 and segmentP2. 154 */ 155 public static Point2D closestPointToSegment(Point2D segmentP1, Point2D segmentP2, Point2D point) { 144 /** 145 * Calculates closest point to a line segment. 146 * @return segmentP1 if it is the closest point, segmentP2 if it is the closest point, 147 * a new point if closest point is between segmentP1 and segmentP2. 148 */ 149 public static Point2D closestPointToSegment(Point2D segmentP1, Point2D segmentP2, Point2D point) { 156 150 157 158 151 double ldx = segmentP2.getX() - segmentP1.getX(); 152 double ldy = segmentP2.getY() - segmentP1.getY(); 159 153 160 161 154 if (ldx == 0 && ldy == 0) //segment zero length 155 return segmentP1; 162 156 163 164 157 double pdx = point.getX() - segmentP1.getX(); 158 double pdy = point.getY() - segmentP1.getY(); 165 159 166 160 double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy); 167 161 168 if (offset <= 0) 169 return segmentP1; 170 else if (offset >= 1) 171 return segmentP2; 172 else 173 return new Point2D.Double(segmentP1.getX() + ldx * offset, segmentP1.getY() + ldy * offset); 174 175 } 162 if (offset <= 0) 163 return segmentP1; 164 else if (offset >= 1) 165 return segmentP2; 166 else 167 return new Point2D.Double(segmentP1.getX() + ldx * offset, segmentP1.getY() + ldy * offset); 168 } 176 169 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/PathOptimizer.java
r30737 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 14 15 public class PathOptimizer { 15 16 16 public List<Point2D> uniquePoints; 17 public Map<Point2D, Point2D> uniquePointMap; 18 private final Map<LayerInfo, LayerContents> layerMap; 19 private List<LayerContents> layers; 20 public Rectangle2D bounds; 21 private final double pointsTolerance; 22 private final Color color; 23 boolean splitOnColorChange; 24 25 LayerContents prevLayer = null; 26 27 public PathOptimizer(double _pointsTolerance, Color _color, boolean _splitOnColorChange) 28 { 29 uniquePointMap = new HashMap<>(); 30 uniquePoints = new ArrayList<>(); 31 layerMap = new HashMap<>(); 32 layers = new ArrayList<>(); 33 pointsTolerance = _pointsTolerance; 34 color = _color; 35 splitOnColorChange = _splitOnColorChange; 36 } 37 38 public Point2D getUniquePoint(Point2D point) { 39 40 if (uniquePointMap.containsKey(point)){ 41 return uniquePointMap.get(point); 42 } 43 else { 44 uniquePointMap.put(point, point); 45 uniquePoints.add(point); 46 return point; 47 } 48 } 49 50 public void addPath(LayerInfo info, PdfPath path) 51 { 52 if (!isColorOK(info)){ 53 return; 54 } 55 56 LayerContents layer = this.getLayer(info); 57 layer.paths.add(path); 58 } 59 60 public void addMultiPath(LayerInfo info, List<PdfPath> paths) { 61 62 if (!isColorOK(info)){ 63 return; 64 } 65 66 LayerContents layer = this.getLayer(info); 67 68 //optimize the paths 69 Set<Point2D> points = new HashSet<>(); 70 for(PdfPath path: paths) { 71 points.addAll(path.points); 72 } 73 LayerContents multipathLayer = new LayerContents(); 74 multipathLayer.paths = paths; 75 Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(points, pointsTolerance); 76 this.fixPoints(multipathLayer,pointMap); 77 this.concatenatePaths(multipathLayer); 78 79 paths = multipathLayer.paths; 80 81 boolean goodMultiPath = true; 82 for(PdfPath path: paths) { 83 goodMultiPath &= path.isClosed(); 84 } 85 86 if (goodMultiPath) { 87 PdfMultiPath p = new PdfMultiPath(paths); 88 layer.multiPaths.add(p); 89 } else { 90 layer.paths.addAll(paths); 91 } 92 } 93 94 private boolean isColorOK(LayerInfo info) { 95 96 if (color == null) { 97 return true; 98 } 99 100 int rgb = color.getRGB() & 0xffffff; 101 boolean good = false; 102 103 if (info.fill != null && (info.fill.getRGB() & 0xffffff) == rgb) { 104 good = true; 105 } 106 107 if (info.stroke != null && (info.stroke.getRGB() & 0xffffff) == rgb) { 108 good = true; 109 } 110 111 return good; 112 } 113 114 115 public void removeParallelLines(double maxDistance){ 116 for(LayerContents layer: this.layers) { 117 this.removeParallelLines(layer, maxDistance); 118 } 119 } 120 121 public void mergeNodes() { 122 Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(uniquePoints, pointsTolerance); 123 124 for(LayerContents layer: this.layers) { 125 this.fixPoints(layer, pointMap); 126 } 127 } 128 129 public void mergeSegments() { 130 for(LayerContents layer: this.layers) { 131 this.concatenatePaths(layer); 132 } 133 } 134 135 136 public void removeSmallObjects(double tolerance) { 137 for(LayerContents layer: this.layers) { 138 this.removeSmallObjects(layer, tolerance, Double.POSITIVE_INFINITY); 139 } 140 } 141 142 143 public void removeLargeObjects(double tolerance) { 144 for(LayerContents layer: this.layers) { 145 this.removeSmallObjects(layer, 0.0, tolerance); 146 } 147 } 148 149 public void splitLayersBySimilarShapes(double tolerance) { 150 List<LayerContents> newLayers = new ArrayList<>(); 151 for(LayerContents l: this.layers) { 152 List<LayerContents> splitResult = splitBySimilarGroups(l); 153 154 for(LayerContents ll: splitResult) { 155 newLayers.add(ll); 156 } 157 } 158 this.layers = newLayers; 159 } 160 161 public void splitLayersByPathKind(boolean closed, boolean single, boolean orthogonal) { 162 List<LayerContents> newLayers = new ArrayList<>(); 163 for(LayerContents l: this.layers) { 164 List<LayerContents> splitResult = splitBySegmentKind(l, closed, single, orthogonal); 165 166 for(LayerContents ll: splitResult) { 167 newLayers.add(ll); 168 } 169 } 170 171 this.layers = newLayers; 172 } 173 174 175 public void finish() { 176 int nr = 0; 177 for(LayerContents layer: this.layers) { 178 layer.info.nr = nr; 179 nr++; 180 finalizeLayer(layer); 181 } 182 } 183 184 185 private LayerContents getLayer(LayerInfo info) { 186 187 LayerContents layer = null; 188 189 if (this.layerMap.containsKey(info)) 190 { 191 layer = this.layerMap.get(info); 192 193 if (layer != this.prevLayer && this.splitOnColorChange) { 194 layer = null; 195 } 196 } 197 198 if (layer == null) 199 { 200 layer = new LayerContents(); 201 layer.info = info.copy(); 202 layer.info.nr = this.layers.size(); 203 this.layerMap.put(layer.info, layer); 204 this.layers.add(layer); 205 } 206 207 this.prevLayer = layer; 208 return layer; 209 } 210 211 212 private void finalizeLayer(LayerContents layer){ 213 Set<Point2D> points = new HashSet<>(); 214 layer.points = new ArrayList<>(); 215 216 for(PdfPath pp: layer.paths){ 217 pp.layer = layer; 218 219 for(Point2D point: pp.points){ 220 if (!points.contains(point)) { 221 layer.points.add(point); 222 points.add(point); 223 } 224 } 225 } 226 227 for (PdfMultiPath multipath: layer.multiPaths) { 228 multipath.layer = layer; 229 for(PdfPath pp: multipath.paths){ 230 pp.layer = layer; 231 232 for(Point2D point: pp.points){ 233 if (!points.contains(point)) { 234 layer.points.add(point); 235 points.add(point); 236 } 237 } 238 } 239 } 240 } 241 242 private void fixPoints(LayerContents layer, Map<Point2D, Point2D> pointMap) { 243 244 List<PdfPath> newPaths = new ArrayList<>(layer.paths.size()); 245 246 for(PdfPath path: layer.paths) { 247 List<Point2D> points = fixPoints(path.points, pointMap); 248 path.points = points; 249 if (points.size() > 2 || (!path.isClosed() && points.size() > 1)){ 250 251 newPaths.add(path); 252 } 253 } 254 255 layer.paths = newPaths; 256 257 for (PdfMultiPath mp: layer.multiPaths){ 258 for(PdfPath path: mp.paths) { 259 path.points = fixPoints(path.points, pointMap); 260 } 261 } 262 } 263 264 265 private List<Point2D> fixPoints(List<Point2D> points, Map<Point2D, Point2D> pointMap) { 266 267 List<Point2D> newPoints = new ArrayList<>(points.size()); 268 Point2D prevPoint = null; 269 270 for(Point2D p: points){ 271 Point2D pp = p; 272 273 if (pointMap.containsKey(p)){ 274 pp = pointMap.get(p); 275 } 276 277 if (prevPoint != pp){ 278 newPoints.add(pp); 279 } 280 281 prevPoint = pp; 282 } 283 284 return newPoints; 285 } 286 287 288 private void removeSmallObjects(LayerContents layer, double min, double max) { 289 List<PdfPath> newPaths = new ArrayList<>(layer.paths.size()); 290 291 for(PdfPath path: layer.paths) { 292 double size = getShapeSize(path); 293 boolean good = size >= min && size <= max; 294 295 if (good) { 296 newPaths.add(path); 297 } 298 } 299 300 layer.paths = newPaths; 301 302 List<PdfMultiPath> newMPaths = new ArrayList<>(layer.multiPaths.size()); 303 304 for (PdfMultiPath mp: layer.multiPaths){ 305 boolean good = true; 306 for(PdfPath path: mp.paths) { 307 double size = getShapeSize(path); 308 good &= size >= min && size <= max; 309 } 310 311 if (good) { 312 newMPaths.add(mp); 313 } 314 } 315 316 layer.multiPaths = newMPaths; 317 } 318 319 320 private double getShapeSize(PdfPath path) { 321 322 Rectangle2D bounds = new Rectangle2D.Double(); 323 bounds.setRect(path.points.get(0).getX(), path.points.get(0).getY(), 0,0); 324 325 for(Point2D n: path.points) { 326 bounds.add(n); 327 } 328 329 return Math.max(bounds.getWidth(), bounds.getHeight()); 330 } 331 332 333 334 /*** 335 * This method finds parralel lines with similar distance and removes them. 336 * @param layer 337 */ 338 private void removeParallelLines(LayerContents layer, double maxDistance) { 339 double angleTolerance = 1.0 / 180.0 * Math.PI; // 1 degree 340 int minSegments = 10; 341 342 //filter paths by direction 343 List<ParallelSegmentsFinder> angles = new ArrayList<>(); 344 345 for(PdfPath path: layer.paths) { 346 if (path.points.size() != 2){ 347 continue; 348 } 349 350 Point2D p1 = path.firstPoint(); 351 Point2D p2 = path.lastPoint(); 352 double angle = Math.atan2(p2.getX() - p1.getX(), p2.getY() - p1.getY()); 353 //normalize between 0 and 180 degrees 354 while (angle < 0) angle += Math.PI; 355 while (angle > Math.PI) angle -= Math.PI; 356 boolean added = false; 357 358 for(ParallelSegmentsFinder pa: angles) { 359 if (Math.abs(pa.angle - angle) < angleTolerance){ 360 pa.addPath(path, angle); 361 added = true; 362 break; 363 } 364 } 365 366 if (!added) { 367 ParallelSegmentsFinder pa = new ParallelSegmentsFinder(); 368 pa.addPath(path, angle); 369 angles.add(pa); 370 } 371 } 372 373 Set<PdfPath> pathsToRemove = new HashSet<>(); 374 375 //process each direction 376 for (ParallelSegmentsFinder pa: angles){ 377 if (pa.paths.size() < minSegments){ 378 continue; 379 } 380 381 List<ParallelSegmentsFinder> parts = pa.splitByDistance(maxDistance); 382 383 for(ParallelSegmentsFinder part: parts) { 384 if (part.paths.size() >= minSegments){ 385 pathsToRemove.addAll(part.paths); 386 } 387 } 388 } 389 390 //generate new path list 391 List<PdfPath> result = new ArrayList<>(layer.paths.size() - pathsToRemove.size()); 392 393 for(PdfPath path: layer.paths) { 394 if (!pathsToRemove.contains(path)) { 395 result.add(path); 396 } 397 } 398 399 layer.paths = result; 400 } 401 402 403 /** 404 * This method merges together paths with common end nodes. 405 * @param layer the layer to process. 406 */ 407 private void concatenatePaths(LayerContents layer) { 408 Map<Point2D, List<PdfPath>> pathEndpoints = new HashMap<>(); 409 Set<PdfPath> mergedPaths = new HashSet<>(); 410 List<PdfPath> newPaths = new ArrayList<>(); 411 412 //fill pathEndpoints map 413 for(PdfPath pp: layer.paths){ 414 if (pp.isClosed()) { 415 newPaths.add(pp); 416 continue; 417 } 418 419 List<PdfPath> paths = pathEndpoints.get(pp.firstPoint()); 420 if (paths == null){ 421 paths = new ArrayList<>(2); 422 pathEndpoints.put(pp.firstPoint(), paths); 423 } 424 paths.add(pp); 425 426 paths = pathEndpoints.get(pp.lastPoint()); 427 if (paths == null){ 428 paths = new ArrayList<>(2); 429 pathEndpoints.put(pp.lastPoint(), paths); 430 } 431 paths.add(pp); 432 } 433 434 List<PdfPath> pathChain = new ArrayList<>(2); 435 Set<Point2D> pointsInPath = new HashSet<>(); 436 437 //join the paths 438 for(PdfPath pp: layer.paths) { 439 440 if (pp.isClosed() || mergedPaths.contains(pp)) { 441 continue; 442 } 443 444 boolean changed = true; 445 446 PdfPath firstPath = pp; 447 PdfPath lastPath = pp; 448 Point2D firstPoint = pp.firstPoint(); 449 Point2D lastPoint = pp.lastPoint(); 450 451 452 pathChain.clear(); 453 pathChain.add(pp); 454 pointsInPath.clear(); 455 pointsInPath.add(firstPoint); 456 pointsInPath.add(lastPoint); 457 458 //process last point 459 while (changed && firstPoint != lastPoint) { 460 changed = false; 461 462 List<PdfPath> adjacentPaths = pathEndpoints.get(lastPoint); 463 PdfPath nextPath = findNextPath(adjacentPaths, lastPath); 464 465 if (nextPath != null) { 466 Point2D nextPoint = nextPath.getOtherEnd(lastPoint); 467 468 lastPoint = nextPoint; 469 lastPath = nextPath; 470 pathChain.add(lastPath); 471 472 if (!pointsInPath.contains(lastPoint)) { 473 pointsInPath.add(lastPoint); 474 changed = true; 475 } 476 else 477 { 478 //closed path found 479 //remove excess segments from start of chain 480 while (lastPoint != firstPoint) { 481 PdfPath pathToRemove = pathChain.remove(0); 482 firstPoint = pathToRemove.getOtherEnd(firstPoint); 483 } 484 485 changed = false; 486 } 487 } 488 } 489 490 491 //process first point 492 changed = true; 493 while (changed && firstPoint != lastPoint) { 494 changed = false; 495 496 List<PdfPath> adjacentPaths = pathEndpoints.get(firstPoint); 497 PdfPath nextPath = findNextPath(adjacentPaths, firstPath); 498 499 if (nextPath != null) { 500 Point2D nextPoint = nextPath.getOtherEnd(firstPoint); 501 502 firstPoint = nextPoint; 503 firstPath = nextPath; 504 pathChain.add(0, firstPath); 505 506 if (!pointsInPath.contains(firstPoint)) { 507 pointsInPath.add(firstPoint); 508 changed = true; 509 } 510 else 511 { 512 //closed path found 513 //remove excess segments from end of chain 514 while (lastPoint != firstPoint) { 515 PdfPath pathToRemove = pathChain.remove(pathChain.size() - 1); 516 lastPoint = pathToRemove.getOtherEnd(lastPoint); 517 } 518 519 changed = false; 520 } 521 } 522 } 523 524 //remove from map 525 for (PdfPath path: pathChain) { 526 pathEndpoints.get(path.firstPoint()).remove(path); 527 pathEndpoints.get(path.lastPoint()).remove(path); 528 mergedPaths.add(path); 529 } 530 531 532 //construct path 533 PdfPath path = pathChain.get(0); 534 535 for (int pos = 1; pos < pathChain.size(); pos ++) { 536 path.points = tryMergeNodeLists(path.points, pathChain.get(pos).points); 537 538 if (path.points == null) { 539 throw new RuntimeException(); 540 } 541 } 542 543 newPaths.add(path); 544 } 545 546 layer.paths = newPaths; 547 } 548 549 private PdfPath findNextPath(List<PdfPath> adjacentPaths, PdfPath firstPath) { 550 for (int pos = 0; pos < adjacentPaths.size(); pos ++) { 551 PdfPath p = adjacentPaths.get(pos); 552 if (p != firstPath && !isSubpathOf(firstPath, p)){ 553 return p; 554 } 555 } 556 557 return null; 558 } 559 560 561 /** 562 * Tests if sub is subpath of main. 563 * @param main 564 * @param sub 565 * @return 566 */ 567 private boolean isSubpathOf(PdfPath main, PdfPath sub) { 568 569 Set<Point2D> points = new HashSet<>(main.points); 570 571 for(Point2D point: sub.points) { 572 if (!points.contains(point)){ 573 return false; 574 } 575 } 576 577 return true; 578 } 579 580 private List<LayerContents> splitBySegmentKind(LayerContents layer, boolean closed, boolean single, boolean orthogonal) 581 { 582 if (!closed && !single) { 583 return Collections.singletonList(layer); 584 } 585 586 OrthogonalShapesFilter of = new OrthogonalShapesFilter(10); 587 588 List<PdfPath> singleSegmentPaths = new ArrayList<>(); 589 List<PdfPath> multiSegmentPaths = new ArrayList<>(); 590 List<PdfPath> closedPaths = new ArrayList<>(); 591 List<PdfPath> orthogonalPaths = new ArrayList<>(); 592 List<PdfPath> orthogonalClosedPaths = new ArrayList<>(); 593 594 for(PdfPath path: layer.paths) { 595 boolean pathOrthgonal = orthogonal && of.isOrthogonal(path); 596 boolean pathUnclosed = !path.isClosed() && closed; 597 boolean pathSingleSegment = path.points.size() <= 3 && single; 598 599 if (pathSingleSegment) { 600 singleSegmentPaths.add(path); 601 } 602 else if (pathUnclosed) { 603 604 if (pathOrthgonal) { 605 orthogonalPaths.add(path); 606 } 607 else { 608 multiSegmentPaths.add(path); 609 } 610 } 611 else { 612 if (pathOrthgonal) { 613 orthogonalClosedPaths.add(path); 614 } 615 else 616 { 617 closedPaths.add(path); 618 } 619 620 } 621 } 622 623 List<LayerContents> layers = new ArrayList<>(); 624 625 if (multiSegmentPaths.size() > 0) { 626 LayerContents l = new LayerContents(); 627 l.paths = multiSegmentPaths; 628 l.info = layer.info.copy(); 629 630 layers.add(l); 631 } 632 633 if (singleSegmentPaths.size() > 0) { 634 LayerContents l = new LayerContents(); 635 l.paths = singleSegmentPaths; 636 l.info = layer.info.copy(); 637 layers.add(l); 638 } 639 640 641 if (orthogonalPaths.size() > 0) { 642 LayerContents l = new LayerContents(); 643 l.paths = orthogonalPaths; 644 l.info = layer.info.copy(); 645 layers.add(l); 646 } 647 648 if (orthogonalClosedPaths.size() > 0) { 649 LayerContents l = new LayerContents(); 650 l.paths = orthogonalClosedPaths; 651 l.info = layer.info.copy(); 652 layers.add(l); 653 } 654 655 if (closedPaths.size() > 0 || layer.multiPaths.size() > 0) { 656 LayerContents l = new LayerContents(); 657 l.paths = closedPaths; 658 l.info = layer.info.copy(); 659 l.multiPaths = layer.multiPaths; 660 layers.add(l); 661 } 662 663 return layers; 664 } 665 666 private List<LayerContents> splitBySimilarGroups(LayerContents layer) { 667 List<List<PdfPath>> subparts = new ArrayList<>(); 668 669 //split into similar parts 670 for (PdfPath path: layer.paths) { 671 List<PdfPath> sublayer = null; 672 673 for(List<PdfPath> ll: subparts){ 674 if (this.pathsSimilar(ll.get(0).points, path.points)) 675 { 676 sublayer = ll; 677 break; 678 } 679 } 680 681 if (sublayer == null) { 682 sublayer = new ArrayList<>(); 683 subparts.add(sublayer); 684 } 685 686 sublayer.add(path); 687 } 688 689 //get groups 690 int minGroupTreshold = 10; 691 692 List<PdfPath> independantPaths = new ArrayList<>(); 693 List<LayerContents> result = new ArrayList<>(); 694 695 for(List<PdfPath> list: subparts){ 696 if (list.size() >= minGroupTreshold) { 697 LayerContents l = new LayerContents(); 698 l.paths = list; 699 l.info = layer.info.copy(); 700 l.info.isGroup = true; 701 l.multiPaths = Collections.emptyList(); 702 result.add(l); 703 } 704 else 705 { 706 independantPaths.addAll(list); 707 } 708 } 709 710 if (independantPaths.size() > 0 || layer.multiPaths.size() > 0) { 711 LayerContents l = new LayerContents(); 712 l.paths = independantPaths; 713 l.info = layer.info.copy(); 714 l.info.isGroup = false; 715 l.multiPaths = layer.multiPaths; 716 result.add(l); 717 } 718 719 720 return result; 721 } 722 723 724 725 private List<Point2D> tryMergeNodeLists(List<Point2D> nodes1, List<Point2D> nodes2) { 726 727 boolean nodes1Closed = (nodes1.get(0) == nodes1.get(nodes1.size() - 1)); 728 boolean nodes2Closed = (nodes2.get(0) == nodes2.get(nodes2.size() - 1)); 729 730 if (nodes1Closed || nodes2Closed) { 731 return null; 732 } 733 734 if (nodes1.get(nodes1.size() - 1) == nodes2.get(0)) { 735 nodes1.remove(nodes1.size() -1); 736 nodes1.addAll(nodes2); 737 return nodes1; 738 } 739 else if (nodes1.get(nodes1.size() - 1) == nodes2.get(nodes2.size() -1)) { 740 nodes1.remove(nodes1.size() -1); 741 for (int pos = nodes2.size() - 1; pos >= 0; pos --) { 742 nodes1.add(nodes2.get(pos)); 743 } 744 745 return nodes1; 746 } 747 else if (nodes1.get(0) == nodes2.get(nodes2.size() - 1)) { 748 nodes1.remove(0); 749 nodes1.addAll(0, nodes2); 750 return nodes1; 751 } 752 else if (nodes1.get(0) == nodes2.get(0)) { 753 nodes1.remove(0); 754 for (int pos = 0; pos < nodes2.size(); pos ++) { 755 nodes1.add(0, nodes2.get(pos)); 756 } 757 758 return nodes1; 759 } else { 760 return null; 761 } 762 } 763 764 public List<LayerContents> getLayers() { 765 return this.layers; 766 } 767 768 /** 769 * Test if paths are different only by offset. 770 * @return 771 */ 772 private boolean pathsSimilar(List<Point2D> path1, List<Point2D> path2) { 773 if (path1.size() != path2.size()) { 774 return false; 775 } 776 777 if (path1.size() < 3) { 778 return false; 779 //cannot judge so small paths 780 } 781 782 Point2D p1 = path1.get(0); 783 Point2D p2 = path2.get(0); 784 785 double offsetX = p1.getX() - p2.getX(); 786 double offsetY = p1.getY() - p2.getY(); 787 double tolerance = 1e-4; 788 789 for(int pos = 0; pos < path1.size(); pos ++) { 790 p1 = path1.get(pos); 791 p2 = path2.get(pos); 792 793 double errorX = p1.getX() - p2.getX() - offsetX; 794 double errorY = p1.getY() - p2.getY() - offsetY; 795 796 if (Math.abs(errorX) + Math.abs(errorY) > tolerance){ 797 return false; 798 } 799 } 800 801 return true; 802 } 803 804 805 17 public List<Point2D> uniquePoints; 18 public Map<Point2D, Point2D> uniquePointMap; 19 private final Map<LayerInfo, LayerContents> layerMap; 20 private List<LayerContents> layers; 21 public Rectangle2D bounds; 22 private final double pointsTolerance; 23 private final Color color; 24 boolean splitOnColorChange; 25 26 LayerContents prevLayer = null; 27 28 public PathOptimizer(double _pointsTolerance, Color _color, boolean _splitOnColorChange) { 29 uniquePointMap = new HashMap<>(); 30 uniquePoints = new ArrayList<>(); 31 layerMap = new HashMap<>(); 32 layers = new ArrayList<>(); 33 pointsTolerance = _pointsTolerance; 34 color = _color; 35 splitOnColorChange = _splitOnColorChange; 36 } 37 38 public Point2D getUniquePoint(Point2D point) { 39 40 if (uniquePointMap.containsKey(point)) { 41 return uniquePointMap.get(point); 42 } else { 43 uniquePointMap.put(point, point); 44 uniquePoints.add(point); 45 return point; 46 } 47 } 48 49 public void addPath(LayerInfo info, PdfPath path) { 50 if (!isColorOK(info)) { 51 return; 52 } 53 54 LayerContents layer = this.getLayer(info); 55 layer.paths.add(path); 56 } 57 58 public void addMultiPath(LayerInfo info, List<PdfPath> paths) { 59 60 if (!isColorOK(info)) { 61 return; 62 } 63 64 LayerContents layer = this.getLayer(info); 65 66 //optimize the paths 67 Set<Point2D> points = new HashSet<>(); 68 for (PdfPath path: paths) { 69 points.addAll(path.points); 70 } 71 LayerContents multipathLayer = new LayerContents(); 72 multipathLayer.paths = paths; 73 Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(points, pointsTolerance); 74 this.fixPoints(multipathLayer, pointMap); 75 this.concatenatePaths(multipathLayer); 76 77 paths = multipathLayer.paths; 78 79 boolean goodMultiPath = true; 80 for (PdfPath path: paths) { 81 goodMultiPath &= path.isClosed(); 82 } 83 84 if (goodMultiPath) { 85 PdfMultiPath p = new PdfMultiPath(paths); 86 layer.multiPaths.add(p); 87 } else { 88 layer.paths.addAll(paths); 89 } 90 } 91 92 private boolean isColorOK(LayerInfo info) { 93 94 if (color == null) { 95 return true; 96 } 97 98 int rgb = color.getRGB() & 0xffffff; 99 boolean good = false; 100 101 if (info.fill != null && (info.fill.getRGB() & 0xffffff) == rgb) { 102 good = true; 103 } 104 105 if (info.stroke != null && (info.stroke.getRGB() & 0xffffff) == rgb) { 106 good = true; 107 } 108 109 return good; 110 } 111 112 public void removeParallelLines(double maxDistance) { 113 for (LayerContents layer: this.layers) { 114 this.removeParallelLines(layer, maxDistance); 115 } 116 } 117 118 public void mergeNodes() { 119 Map<Point2D, Point2D> pointMap = DuplicateNodesFinder.findDuplicateNodes(uniquePoints, pointsTolerance); 120 121 for (LayerContents layer: this.layers) { 122 this.fixPoints(layer, pointMap); 123 } 124 } 125 126 public void mergeSegments() { 127 for (LayerContents layer: this.layers) { 128 this.concatenatePaths(layer); 129 } 130 } 131 132 public void removeSmallObjects(double tolerance) { 133 for (LayerContents layer: this.layers) { 134 this.removeSmallObjects(layer, tolerance, Double.POSITIVE_INFINITY); 135 } 136 } 137 138 public void removeLargeObjects(double tolerance) { 139 for (LayerContents layer: this.layers) { 140 this.removeSmallObjects(layer, 0.0, tolerance); 141 } 142 } 143 144 public void splitLayersBySimilarShapes(double tolerance) { 145 List<LayerContents> newLayers = new ArrayList<>(); 146 for (LayerContents l: this.layers) { 147 List<LayerContents> splitResult = splitBySimilarGroups(l); 148 149 for (LayerContents ll: splitResult) { 150 newLayers.add(ll); 151 } 152 } 153 this.layers = newLayers; 154 } 155 156 public void splitLayersByPathKind(boolean closed, boolean single, boolean orthogonal) { 157 List<LayerContents> newLayers = new ArrayList<>(); 158 for (LayerContents l: this.layers) { 159 List<LayerContents> splitResult = splitBySegmentKind(l, closed, single, orthogonal); 160 161 for (LayerContents ll: splitResult) { 162 newLayers.add(ll); 163 } 164 } 165 166 this.layers = newLayers; 167 } 168 169 public void finish() { 170 int nr = 0; 171 for (LayerContents layer: this.layers) { 172 layer.info.nr = nr; 173 nr++; 174 finalizeLayer(layer); 175 } 176 } 177 178 private LayerContents getLayer(LayerInfo info) { 179 180 LayerContents layer = null; 181 182 if (this.layerMap.containsKey(info)) { 183 layer = this.layerMap.get(info); 184 185 if (layer != this.prevLayer && this.splitOnColorChange) { 186 layer = null; 187 } 188 } 189 190 if (layer == null) { 191 layer = new LayerContents(); 192 layer.info = info.copy(); 193 layer.info.nr = this.layers.size(); 194 this.layerMap.put(layer.info, layer); 195 this.layers.add(layer); 196 } 197 198 this.prevLayer = layer; 199 return layer; 200 } 201 202 private void finalizeLayer(LayerContents layer) { 203 Set<Point2D> points = new HashSet<>(); 204 layer.points = new ArrayList<>(); 205 206 for (PdfPath pp: layer.paths) { 207 pp.layer = layer; 208 209 for (Point2D point: pp.points) { 210 if (!points.contains(point)) { 211 layer.points.add(point); 212 points.add(point); 213 } 214 } 215 } 216 217 for (PdfMultiPath multipath: layer.multiPaths) { 218 multipath.layer = layer; 219 for (PdfPath pp: multipath.paths) { 220 pp.layer = layer; 221 222 for (Point2D point: pp.points) { 223 if (!points.contains(point)) { 224 layer.points.add(point); 225 points.add(point); 226 } 227 } 228 } 229 } 230 } 231 232 private void fixPoints(LayerContents layer, Map<Point2D, Point2D> pointMap) { 233 234 List<PdfPath> newPaths = new ArrayList<>(layer.paths.size()); 235 236 for (PdfPath path: layer.paths) { 237 List<Point2D> points = fixPoints(path.points, pointMap); 238 path.points = points; 239 if (points.size() > 2 || (!path.isClosed() && points.size() > 1)) { 240 241 newPaths.add(path); 242 } 243 } 244 245 layer.paths = newPaths; 246 247 for (PdfMultiPath mp: layer.multiPaths) { 248 for (PdfPath path: mp.paths) { 249 path.points = fixPoints(path.points, pointMap); 250 } 251 } 252 } 253 254 private List<Point2D> fixPoints(List<Point2D> points, Map<Point2D, Point2D> pointMap) { 255 256 List<Point2D> newPoints = new ArrayList<>(points.size()); 257 Point2D prevPoint = null; 258 259 for (Point2D p: points) { 260 Point2D pp = p; 261 262 if (pointMap.containsKey(p)) { 263 pp = pointMap.get(p); 264 } 265 266 if (prevPoint != pp) { 267 newPoints.add(pp); 268 } 269 270 prevPoint = pp; 271 } 272 273 return newPoints; 274 } 275 276 private void removeSmallObjects(LayerContents layer, double min, double max) { 277 List<PdfPath> newPaths = new ArrayList<>(layer.paths.size()); 278 279 for (PdfPath path: layer.paths) { 280 double size = getShapeSize(path); 281 boolean good = size >= min && size <= max; 282 283 if (good) { 284 newPaths.add(path); 285 } 286 } 287 288 layer.paths = newPaths; 289 290 List<PdfMultiPath> newMPaths = new ArrayList<>(layer.multiPaths.size()); 291 292 for (PdfMultiPath mp: layer.multiPaths) { 293 boolean good = true; 294 for (PdfPath path: mp.paths) { 295 double size = getShapeSize(path); 296 good &= size >= min && size <= max; 297 } 298 299 if (good) { 300 newMPaths.add(mp); 301 } 302 } 303 304 layer.multiPaths = newMPaths; 305 } 306 307 private double getShapeSize(PdfPath path) { 308 309 Rectangle2D bounds = new Rectangle2D.Double(); 310 bounds.setRect(path.points.get(0).getX(), path.points.get(0).getY(), 0, 0); 311 312 for (Point2D n: path.points) { 313 bounds.add(n); 314 } 315 316 return Math.max(bounds.getWidth(), bounds.getHeight()); 317 } 318 319 /*** 320 * This method finds parralel lines with similar distance and removes them. 321 */ 322 private void removeParallelLines(LayerContents layer, double maxDistance) { 323 double angleTolerance = 1.0 / 180.0 * Math.PI; // 1 degree 324 int minSegments = 10; 325 326 //filter paths by direction 327 List<ParallelSegmentsFinder> angles = new ArrayList<>(); 328 329 for (PdfPath path: layer.paths) { 330 if (path.points.size() != 2) { 331 continue; 332 } 333 334 Point2D p1 = path.firstPoint(); 335 Point2D p2 = path.lastPoint(); 336 double angle = Math.atan2(p2.getX() - p1.getX(), p2.getY() - p1.getY()); 337 //normalize between 0 and 180 degrees 338 while (angle < 0) angle += Math.PI; 339 while (angle > Math.PI) angle -= Math.PI; 340 boolean added = false; 341 342 for (ParallelSegmentsFinder pa: angles) { 343 if (Math.abs(pa.angle - angle) < angleTolerance) { 344 pa.addPath(path, angle); 345 added = true; 346 break; 347 } 348 } 349 350 if (!added) { 351 ParallelSegmentsFinder pa = new ParallelSegmentsFinder(); 352 pa.addPath(path, angle); 353 angles.add(pa); 354 } 355 } 356 357 Set<PdfPath> pathsToRemove = new HashSet<>(); 358 359 //process each direction 360 for (ParallelSegmentsFinder pa: angles) { 361 if (pa.paths.size() < minSegments) { 362 continue; 363 } 364 365 List<ParallelSegmentsFinder> parts = pa.splitByDistance(maxDistance); 366 367 for (ParallelSegmentsFinder part: parts) { 368 if (part.paths.size() >= minSegments) { 369 pathsToRemove.addAll(part.paths); 370 } 371 } 372 } 373 374 //generate new path list 375 List<PdfPath> result = new ArrayList<>(layer.paths.size() - pathsToRemove.size()); 376 377 for (PdfPath path: layer.paths) { 378 if (!pathsToRemove.contains(path)) { 379 result.add(path); 380 } 381 } 382 383 layer.paths = result; 384 } 385 386 387 /** 388 * This method merges together paths with common end nodes. 389 * @param layer the layer to process. 390 */ 391 private void concatenatePaths(LayerContents layer) { 392 Map<Point2D, List<PdfPath>> pathEndpoints = new HashMap<>(); 393 Set<PdfPath> mergedPaths = new HashSet<>(); 394 List<PdfPath> newPaths = new ArrayList<>(); 395 396 //fill pathEndpoints map 397 for (PdfPath pp: layer.paths) { 398 if (pp.isClosed()) { 399 newPaths.add(pp); 400 continue; 401 } 402 403 List<PdfPath> paths = pathEndpoints.get(pp.firstPoint()); 404 if (paths == null) { 405 paths = new ArrayList<>(2); 406 pathEndpoints.put(pp.firstPoint(), paths); 407 } 408 paths.add(pp); 409 410 paths = pathEndpoints.get(pp.lastPoint()); 411 if (paths == null) { 412 paths = new ArrayList<>(2); 413 pathEndpoints.put(pp.lastPoint(), paths); 414 } 415 paths.add(pp); 416 } 417 418 List<PdfPath> pathChain = new ArrayList<>(2); 419 Set<Point2D> pointsInPath = new HashSet<>(); 420 421 //join the paths 422 for (PdfPath pp: layer.paths) { 423 424 if (pp.isClosed() || mergedPaths.contains(pp)) { 425 continue; 426 } 427 428 boolean changed = true; 429 430 PdfPath firstPath = pp; 431 PdfPath lastPath = pp; 432 Point2D firstPoint = pp.firstPoint(); 433 Point2D lastPoint = pp.lastPoint(); 434 435 436 pathChain.clear(); 437 pathChain.add(pp); 438 pointsInPath.clear(); 439 pointsInPath.add(firstPoint); 440 pointsInPath.add(lastPoint); 441 442 //process last point 443 while (changed && firstPoint != lastPoint) { 444 changed = false; 445 446 List<PdfPath> adjacentPaths = pathEndpoints.get(lastPoint); 447 PdfPath nextPath = findNextPath(adjacentPaths, lastPath); 448 449 if (nextPath != null) { 450 Point2D nextPoint = nextPath.getOtherEnd(lastPoint); 451 452 lastPoint = nextPoint; 453 lastPath = nextPath; 454 pathChain.add(lastPath); 455 456 if (!pointsInPath.contains(lastPoint)) { 457 pointsInPath.add(lastPoint); 458 changed = true; 459 } else { 460 //closed path found 461 //remove excess segments from start of chain 462 while (lastPoint != firstPoint) { 463 PdfPath pathToRemove = pathChain.remove(0); 464 firstPoint = pathToRemove.getOtherEnd(firstPoint); 465 } 466 467 changed = false; 468 } 469 } 470 } 471 472 //process first point 473 changed = true; 474 while (changed && firstPoint != lastPoint) { 475 changed = false; 476 477 List<PdfPath> adjacentPaths = pathEndpoints.get(firstPoint); 478 PdfPath nextPath = findNextPath(adjacentPaths, firstPath); 479 480 if (nextPath != null) { 481 Point2D nextPoint = nextPath.getOtherEnd(firstPoint); 482 483 firstPoint = nextPoint; 484 firstPath = nextPath; 485 pathChain.add(0, firstPath); 486 487 if (!pointsInPath.contains(firstPoint)) { 488 pointsInPath.add(firstPoint); 489 changed = true; 490 } else { 491 //closed path found 492 //remove excess segments from end of chain 493 while (lastPoint != firstPoint) { 494 PdfPath pathToRemove = pathChain.remove(pathChain.size() - 1); 495 lastPoint = pathToRemove.getOtherEnd(lastPoint); 496 } 497 498 changed = false; 499 } 500 } 501 } 502 503 //remove from map 504 for (PdfPath path: pathChain) { 505 pathEndpoints.get(path.firstPoint()).remove(path); 506 pathEndpoints.get(path.lastPoint()).remove(path); 507 mergedPaths.add(path); 508 } 509 510 //construct path 511 PdfPath path = pathChain.get(0); 512 513 for (int pos = 1; pos < pathChain.size(); pos++) { 514 path.points = tryMergeNodeLists(path.points, pathChain.get(pos).points); 515 516 if (path.points == null) { 517 throw new RuntimeException(); 518 } 519 } 520 521 newPaths.add(path); 522 } 523 524 layer.paths = newPaths; 525 } 526 527 private PdfPath findNextPath(List<PdfPath> adjacentPaths, PdfPath firstPath) { 528 for (int pos = 0; pos < adjacentPaths.size(); pos++) { 529 PdfPath p = adjacentPaths.get(pos); 530 if (p != firstPath && !isSubpathOf(firstPath, p)) { 531 return p; 532 } 533 } 534 535 return null; 536 } 537 538 /** 539 * Tests if sub is subpath of main. 540 */ 541 private boolean isSubpathOf(PdfPath main, PdfPath sub) { 542 543 Set<Point2D> points = new HashSet<>(main.points); 544 545 for (Point2D point: sub.points) { 546 if (!points.contains(point)) { 547 return false; 548 } 549 } 550 551 return true; 552 } 553 554 private List<LayerContents> splitBySegmentKind(LayerContents layer, boolean closed, boolean single, boolean orthogonal) { 555 if (!closed && !single) { 556 return Collections.singletonList(layer); 557 } 558 559 OrthogonalShapesFilter of = new OrthogonalShapesFilter(10); 560 561 List<PdfPath> singleSegmentPaths = new ArrayList<>(); 562 List<PdfPath> multiSegmentPaths = new ArrayList<>(); 563 List<PdfPath> closedPaths = new ArrayList<>(); 564 List<PdfPath> orthogonalPaths = new ArrayList<>(); 565 List<PdfPath> orthogonalClosedPaths = new ArrayList<>(); 566 567 for (PdfPath path: layer.paths) { 568 boolean pathOrthgonal = orthogonal && of.isOrthogonal(path); 569 boolean pathUnclosed = !path.isClosed() && closed; 570 boolean pathSingleSegment = path.points.size() <= 3 && single; 571 572 if (pathSingleSegment) { 573 singleSegmentPaths.add(path); 574 } else if (pathUnclosed) { 575 if (pathOrthgonal) { 576 orthogonalPaths.add(path); 577 } else { 578 multiSegmentPaths.add(path); 579 } 580 } else { 581 if (pathOrthgonal) { 582 orthogonalClosedPaths.add(path); 583 } else { 584 closedPaths.add(path); 585 } 586 } 587 } 588 589 List<LayerContents> layers = new ArrayList<>(); 590 591 if (multiSegmentPaths.size() > 0) { 592 LayerContents l = new LayerContents(); 593 l.paths = multiSegmentPaths; 594 l.info = layer.info.copy(); 595 596 layers.add(l); 597 } 598 599 if (singleSegmentPaths.size() > 0) { 600 LayerContents l = new LayerContents(); 601 l.paths = singleSegmentPaths; 602 l.info = layer.info.copy(); 603 layers.add(l); 604 } 605 606 if (orthogonalPaths.size() > 0) { 607 LayerContents l = new LayerContents(); 608 l.paths = orthogonalPaths; 609 l.info = layer.info.copy(); 610 layers.add(l); 611 } 612 613 if (orthogonalClosedPaths.size() > 0) { 614 LayerContents l = new LayerContents(); 615 l.paths = orthogonalClosedPaths; 616 l.info = layer.info.copy(); 617 layers.add(l); 618 } 619 620 if (closedPaths.size() > 0 || layer.multiPaths.size() > 0) { 621 LayerContents l = new LayerContents(); 622 l.paths = closedPaths; 623 l.info = layer.info.copy(); 624 l.multiPaths = layer.multiPaths; 625 layers.add(l); 626 } 627 628 return layers; 629 } 630 631 private List<LayerContents> splitBySimilarGroups(LayerContents layer) { 632 List<List<PdfPath>> subparts = new ArrayList<>(); 633 634 //split into similar parts 635 for (PdfPath path: layer.paths) { 636 List<PdfPath> sublayer = null; 637 638 for (List<PdfPath> ll: subparts) { 639 if (this.pathsSimilar(ll.get(0).points, path.points)) { 640 sublayer = ll; 641 break; 642 } 643 } 644 645 if (sublayer == null) { 646 sublayer = new ArrayList<>(); 647 subparts.add(sublayer); 648 } 649 650 sublayer.add(path); 651 } 652 653 //get groups 654 int minGroupTreshold = 10; 655 656 List<PdfPath> independantPaths = new ArrayList<>(); 657 List<LayerContents> result = new ArrayList<>(); 658 659 for (List<PdfPath> list: subparts) { 660 if (list.size() >= minGroupTreshold) { 661 LayerContents l = new LayerContents(); 662 l.paths = list; 663 l.info = layer.info.copy(); 664 l.info.isGroup = true; 665 l.multiPaths = Collections.emptyList(); 666 result.add(l); 667 } else { 668 independantPaths.addAll(list); 669 } 670 } 671 672 if (independantPaths.size() > 0 || layer.multiPaths.size() > 0) { 673 LayerContents l = new LayerContents(); 674 l.paths = independantPaths; 675 l.info = layer.info.copy(); 676 l.info.isGroup = false; 677 l.multiPaths = layer.multiPaths; 678 result.add(l); 679 } 680 681 return result; 682 } 683 684 private List<Point2D> tryMergeNodeLists(List<Point2D> nodes1, List<Point2D> nodes2) { 685 686 boolean nodes1Closed = (nodes1.get(0) == nodes1.get(nodes1.size() - 1)); 687 boolean nodes2Closed = (nodes2.get(0) == nodes2.get(nodes2.size() - 1)); 688 689 if (nodes1Closed || nodes2Closed) { 690 return null; 691 } 692 693 if (nodes1.get(nodes1.size() - 1) == nodes2.get(0)) { 694 nodes1.remove(nodes1.size() -1); 695 nodes1.addAll(nodes2); 696 return nodes1; 697 } else if (nodes1.get(nodes1.size() - 1) == nodes2.get(nodes2.size() -1)) { 698 nodes1.remove(nodes1.size() -1); 699 for (int pos = nodes2.size() - 1; pos >= 0; pos--) { 700 nodes1.add(nodes2.get(pos)); 701 } 702 703 return nodes1; 704 } else if (nodes1.get(0) == nodes2.get(nodes2.size() - 1)) { 705 nodes1.remove(0); 706 nodes1.addAll(0, nodes2); 707 return nodes1; 708 } else if (nodes1.get(0) == nodes2.get(0)) { 709 nodes1.remove(0); 710 for (int pos = 0; pos < nodes2.size(); pos++) { 711 nodes1.add(0, nodes2.get(pos)); 712 } 713 714 return nodes1; 715 } else { 716 return null; 717 } 718 } 719 720 public List<LayerContents> getLayers() { 721 return this.layers; 722 } 723 724 /** 725 * Test if paths are different only by offset. 726 */ 727 private boolean pathsSimilar(List<Point2D> path1, List<Point2D> path2) { 728 if (path1.size() != path2.size()) { 729 return false; 730 } 731 732 if (path1.size() < 3) { 733 return false; 734 //cannot judge so small paths 735 } 736 737 Point2D p1 = path1.get(0); 738 Point2D p2 = path2.get(0); 739 740 double offsetX = p1.getX() - p2.getX(); 741 double offsetY = p1.getY() - p2.getY(); 742 double tolerance = 1e-4; 743 744 for (int pos = 0; pos < path1.size(); pos++) { 745 p1 = path1.get(pos); 746 p2 = path2.get(pos); 747 748 double errorX = p1.getX() - p2.getX() - offsetX; 749 double errorY = p1.getY() - p2.getY() - offsetY; 750 751 if (Math.abs(errorX) + Math.abs(errorY) > tolerance) { 752 return false; 753 } 754 } 755 756 return true; 757 } 806 758 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfImportAction.java
r27867 r32542 1 // License: GPL. 1 // License: GPL. For details, see LICENSE file. 2 2 package pdfimport; 3 3 … … 16 16 public class PdfImportAction extends JosmAction { 17 17 18 public PdfImportAction() { 19 super(tr("Import PDF file"), "pdf_import", 20 tr("Import PDF file."), 21 Shortcut.registerShortcut("tools:pdfimport", tr("Tool: {0}",tr("Import PDF file")), 22 KeyEvent.VK_F, Shortcut.ALT_CTRL_SHIFT) 23 , true); 24 } 18 public PdfImportAction() { 19 super(tr("Import PDF file"), "pdf_import", 20 tr("Import PDF file."), 21 Shortcut.registerShortcut("tools:pdfimport", tr("Tool: {0}", tr("Import PDF file")), 22 KeyEvent.VK_F, Shortcut.ALT_CTRL_SHIFT), true); 23 } 25 24 26 /** 27 * The action button has been clicked 28 * 29 * @param e 30 * Action Event 31 */ 32 public void actionPerformed(ActionEvent e) { 25 /** 26 * The action button has been clicked 27 * 28 * @param e 29 * Action Event 30 */ 31 @Override 32 public void actionPerformed(ActionEvent e) { 33 33 34 35 36 37 38 39 34 //show dialog asking to select coordinate axes and input coordinates and projection. 35 LoadPdfDialog dialog = new LoadPdfDialog(); 36 dialog.setAlwaysOnTop(true); 37 dialog.setTitle(tr("Import PDF")); 38 dialog.setVisible(true); 39 } 40 40 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfImportPlugin.java
r29805 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 13 14 public class PdfImportPlugin extends Plugin { 14 15 15 16 protected String name; 16 17 17 18 19 20 21 18 public PdfImportPlugin(PluginInformation info) { 19 super(info); 20 name = tr("Import PDF file"); 21 MainMenu.add(Main.main.menu.imagerySubMenu, new PdfImportAction()); 22 } 22 23 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfMultiPath.java
r29854 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 4 5 5 6 public class PdfMultiPath { 6 7 7 public List<PdfPath> paths; 8 public LayerContents layer; 8 9 9 public PdfMultiPath(List<PdfPath> paths2) { 10 paths = paths2; 11 } 12 10 public PdfMultiPath(List<PdfPath> paths2) { 11 paths = paths2; 12 } 13 13 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfPath.java
r25349 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport; 2 3 … … 5 6 6 7 public class PdfPath { 7 8 8 public List<Point2D> points; 9 public double length; 9 10 10 11 11 LayerContents layer; 12 public int nr; 12 13 14 public PdfPath(List<Point2D> nodes) { 15 points = nodes; 16 } 13 17 14 PdfPath(List<Point2D> nodes) {15 points = nodes;16 18 public boolean isClosed() { 19 return points.size() > 1 && points.get(0) == points.get(points.size() - 1); 20 } 17 21 18 boolean isClosed() {19 size() > 1 && points.get(0) == points.get(points.size() - 1);20 22 public Point2D firstPoint() { 23 return points.get(0); 24 } 21 25 22 firstPoint() {23 0);24 26 public Point2D lastPoint() { 27 return points.get(points.size() - 1); 28 } 25 29 26 public Point2D lastPoint() { 27 return points.get(points.size() - 1); 28 } 30 public void calculateLength() { 31 double len = 0; 29 32 30 public void calculateLength() { 31 double len = 0; 33 for (int pos = 1; pos < points.size(); pos++) { 34 len += points.get(pos).distance(points.get(pos -1)); 35 } 32 36 33 for(int pos =1; pos < points.size(); pos ++) { 34 len += points.get(pos).distance(points.get(pos -1)); 35 } 37 this.length = len; 38 } 36 39 37 this.length = len; 38 } 40 public Point2D getOtherEnd(Point2D endPoint) { 41 if (this.firstPoint() == endPoint) { 42 return this.lastPoint(); 43 } 39 44 40 public Point2D getOtherEnd(Point2D endPoint) { 41 if (this.firstPoint() == endPoint) { 42 return this.lastPoint(); 43 } 45 if (this.lastPoint() == endPoint) { 46 return this.firstPoint(); 47 } 44 48 45 if (this.lastPoint() == endPoint) { 46 return this.firstPoint(); 47 } 49 throw new RuntimeException("Unexpected point"); 48 50 49 throw new RuntimeException("Unexpected point"); 50 51 } 51 } 52 52 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/ProjectionInfo.java
r30737 r32542 10 10 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference; 11 11 12 public class ProjectionInfo { 12 public final class ProjectionInfo { 13 13 private static Map<String, ProjectionChoice> allCodesPC = new HashMap<>(); 14 14 private static Map<String, Projection> allCodes = new HashMap<>(); … … 20 20 } 21 21 } 22 } 23 24 private ProjectionInfo() { 25 // Hide default constructor for utilities classes 22 26 } 23 27 -
applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/GraphicsProcessor.java
r30737 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport.pdfbox; 2 3 … … 19 20 import pdfimport.PdfPath; 20 21 21 public class GraphicsProcessor{ 22 23 public PathOptimizer target; 24 private Shape clipShape; 25 private List<PdfPath> clipPath; 26 private final LayerInfo info = new LayerInfo(); 27 int pathNo = 0; 28 private boolean complexClipShape; 29 private boolean clipAreaDrawn; 30 31 private final AffineTransform transform; 32 private final ProgressMonitor monitor; 33 private final int maxPaths; 34 35 36 public GraphicsProcessor(PathOptimizer target, int rotation, int maxPaths, ProgressMonitor monitor) 37 { 38 this.maxPaths = maxPaths; 39 this.target = target; 40 this.transform = new AffineTransform(); 41 this.transform.rotate(-Math.toRadians(rotation)); 42 this.info.stroke = Color.BLACK; 43 this.info.fill = Color.BLACK; 44 this.monitor = monitor; 45 } 46 47 48 private void addPath(Shape s, boolean closed) { 49 pathNo ++; 50 51 if (pathNo % 100 == 0) { 52 this.monitor.setCustomText(tr(" {0} objects so far", pathNo)); 53 } 54 55 if (pathNo >= maxPaths) { 56 return; 57 } 58 59 List<PdfPath> paths = this.parsePath(s, closed); 60 61 for (PdfPath p: paths){ 62 p.nr = pathNo; 63 } 64 65 66 if (paths.size() > 1) { 67 this.target.addMultiPath(this.info, paths); 68 this.parsePath(s, closed); 69 } 70 else if (paths.size() == 1) { 71 this.target.addPath(this.info, paths.get(0)); 72 } 73 74 } 75 76 77 private List<PdfPath> parsePath(Shape s, boolean closed) { 78 List<PdfPath> result = new ArrayList<>(2); 79 List<Point2D> points = new ArrayList<>(2); 80 81 PathIterator iter = s.getPathIterator(null); 82 double[] coords = new double[6]; 83 84 while (!iter.isDone()) { 85 int type = iter.currentSegment(coords); 86 87 if (type == PathIterator.SEG_CLOSE) { 88 //close polygon 89 this.addPoint(points, points.get(0)); 90 if (points.size() > 1) { 91 result.add(new PdfPath(points)); 92 } 93 points = new ArrayList<>(2); 94 } else if (type == PathIterator.SEG_CUBICTO) { 95 //cubic curve 96 this.addPoint(points, this.parsePoint(coords, 4)); 97 } 98 else if (type == PathIterator.SEG_LINETO) { 99 this.addPoint(points, this.parsePoint(coords, 0)); 100 } 101 else if (type == PathIterator.SEG_MOVETO) { 102 //new path 103 if (points.size() > 1){ 104 result.add(new PdfPath(points)); 105 } 106 points = new ArrayList<>(2); 107 this.addPoint(points, this.parsePoint(coords, 0)); 108 } 109 else if (type == PathIterator.SEG_QUADTO) { 110 //quadratic curve 111 this.addPoint(points, this.parsePoint(coords, 2)); 112 } 113 else if (type == PathIterator.WIND_EVEN_ODD) { 114 //fill even odd 115 } 116 else if (type == PathIterator.WIND_NON_ZERO) { 117 //fill all 118 } 119 else { 120 //Unexpected operation 121 } 122 123 iter.next(); 124 } 125 126 if (points.size() > 1 ) 127 { 128 if (closed) { 129 this.addPoint(points, points.get(0)); 130 } 131 132 result.add(new PdfPath(points)); 133 } 134 135 return result; 136 } 137 138 private void addPoint(List<Point2D> points, Point2D point) { 139 if (points.size() > 0) { 140 Point2D prevPoint = points.get(points.size() - 1); 141 142 if (prevPoint.getX() == point.getX() && prevPoint.getY() == point.getY()) { 143 return; 144 } 145 } 146 147 points.add(point); 148 } 149 150 private Point2D parsePoint(double[] buffer, int offset) { 151 //invert Y. 152 Point2D point = new Point2D.Double(buffer[offset], buffer[offset + 1]); 153 Point2D dest = new Point2D.Double(); 154 this.transform.transform(point, dest); 155 return this.target.getUniquePoint(dest); 156 } 157 158 public void drawPath(Shape path, Color stroke, Color fill, 159 int windingRule) { 160 161 if (complexClipShape) { 162 if (!this.clipAreaDrawn) { 163 this.info.stroke = null; 164 this.info.fill = Color.CYAN; 165 this.addPath(this.clipShape, true); 166 this.clipAreaDrawn = true; 167 } 168 } 169 170 if (!complexClipShape || fill != null) { 171 this.info.stroke = stroke; 172 this.info.fill = fill; 173 this.addPath(path, fill != null); 174 } 175 } 176 177 178 public void drawImage() { 179 180 if (!this.clipAreaDrawn) { 181 this.info.stroke = null; 182 this.info.fill = Color.CYAN; 183 this.addPath(this.clipShape, true); 184 this.clipAreaDrawn = true; 185 } 186 } 187 188 189 public void setClip(Shape clip) { 190 if (this.shapesEqual(this.clipShape,clip)) 191 return; 192 193 this.clipPath = this.parsePath(clip, true); 194 195 boolean complexClipPath = false; 196 197 if (clipPath.size() > 1) 198 { 199 complexClipPath = true; 200 } 201 else if (clipPath.size() == 1 && clipPath.get(0).points.size() > 5) 202 { 203 //more than 4 points. 204 complexClipPath = true; 205 } 206 207 this.complexClipShape = complexClipPath; 208 this.clipAreaDrawn = false; 209 this.clipShape = clip; 210 } 211 212 213 private boolean shapesEqual(Shape shape1, Shape shape2) { 214 215 if (shape1== null || shape2 == null){ 216 return false; 217 } 218 219 return shape1.getBounds2D().equals(shape2.getBounds2D()); 220 } 221 222 223 public void setStroke(Stroke s) { 224 BasicStroke stroke = (BasicStroke) s; 225 this.info.width = stroke.getLineWidth(); 226 this.info.dash = 0; 227 228 if (stroke.getDashArray() != null) { 229 this.info.dash = stroke.getDashArray().hashCode(); 230 } 231 } 232 233 public void drawString(float x, float y, String character, Color color) { 234 // TODO Auto-generated method stub 235 } 22 public class GraphicsProcessor { 23 24 public PathOptimizer target; 25 private Shape clipShape; 26 private List<PdfPath> clipPath; 27 private final LayerInfo info = new LayerInfo(); 28 int pathNo = 0; 29 private boolean complexClipShape; 30 private boolean clipAreaDrawn; 31 32 private final AffineTransform transform; 33 private final ProgressMonitor monitor; 34 private final int maxPaths; 35 36 public GraphicsProcessor(PathOptimizer target, int rotation, int maxPaths, ProgressMonitor monitor) { 37 this.maxPaths = maxPaths; 38 this.target = target; 39 this.transform = new AffineTransform(); 40 this.transform.rotate(-Math.toRadians(rotation)); 41 this.info.stroke = Color.BLACK; 42 this.info.fill = Color.BLACK; 43 this.monitor = monitor; 44 } 45 46 private void addPath(Shape s, boolean closed) { 47 pathNo++; 48 49 if (pathNo % 100 == 0) { 50 this.monitor.setCustomText(tr(" {0} objects so far", pathNo)); 51 } 52 53 if (pathNo >= maxPaths) { 54 return; 55 } 56 57 List<PdfPath> paths = this.parsePath(s, closed); 58 59 for (PdfPath p: paths) { 60 p.nr = pathNo; 61 } 62 63 64 if (paths.size() > 1) { 65 this.target.addMultiPath(this.info, paths); 66 this.parsePath(s, closed); 67 } else if (paths.size() == 1) { 68 this.target.addPath(this.info, paths.get(0)); 69 } 70 } 71 72 private List<PdfPath> parsePath(Shape s, boolean closed) { 73 List<PdfPath> result = new ArrayList<>(2); 74 List<Point2D> points = new ArrayList<>(2); 75 76 PathIterator iter = s.getPathIterator(null); 77 double[] coords = new double[6]; 78 79 while (!iter.isDone()) { 80 int type = iter.currentSegment(coords); 81 82 if (type == PathIterator.SEG_CLOSE) { 83 //close polygon 84 this.addPoint(points, points.get(0)); 85 if (points.size() > 1) { 86 result.add(new PdfPath(points)); 87 } 88 points = new ArrayList<>(2); 89 } else if (type == PathIterator.SEG_CUBICTO) { 90 //cubic curve 91 this.addPoint(points, this.parsePoint(coords, 4)); 92 } else if (type == PathIterator.SEG_LINETO) { 93 this.addPoint(points, this.parsePoint(coords, 0)); 94 } else if (type == PathIterator.SEG_MOVETO) { 95 //new path 96 if (points.size() > 1) { 97 result.add(new PdfPath(points)); 98 } 99 points = new ArrayList<>(2); 100 this.addPoint(points, this.parsePoint(coords, 0)); 101 } else if (type == PathIterator.SEG_QUADTO) { 102 //quadratic curve 103 this.addPoint(points, this.parsePoint(coords, 2)); 104 } else if (type == PathIterator.WIND_EVEN_ODD) { 105 //fill even odd 106 } else if (type == PathIterator.WIND_NON_ZERO) { 107 //fill all 108 } 109 110 iter.next(); 111 } 112 113 if (points.size() > 1) { 114 if (closed) { 115 this.addPoint(points, points.get(0)); 116 } 117 118 result.add(new PdfPath(points)); 119 } 120 121 return result; 122 } 123 124 private void addPoint(List<Point2D> points, Point2D point) { 125 if (points.size() > 0) { 126 Point2D prevPoint = points.get(points.size() - 1); 127 128 if (prevPoint.getX() == point.getX() && prevPoint.getY() == point.getY()) { 129 return; 130 } 131 } 132 133 points.add(point); 134 } 135 136 private Point2D parsePoint(double[] buffer, int offset) { 137 //invert Y. 138 Point2D point = new Point2D.Double(buffer[offset], buffer[offset + 1]); 139 Point2D dest = new Point2D.Double(); 140 this.transform.transform(point, dest); 141 return this.target.getUniquePoint(dest); 142 } 143 144 public void drawPath(Shape path, Color stroke, Color fill, 145 int windingRule) { 146 147 if (complexClipShape) { 148 if (!this.clipAreaDrawn) { 149 this.info.stroke = null; 150 this.info.fill = Color.CYAN; 151 this.addPath(this.clipShape, true); 152 this.clipAreaDrawn = true; 153 } 154 } 155 156 if (!complexClipShape || fill != null) { 157 this.info.stroke = stroke; 158 this.info.fill = fill; 159 this.addPath(path, fill != null); 160 } 161 } 162 163 public void drawImage() { 164 165 if (!this.clipAreaDrawn) { 166 this.info.stroke = null; 167 this.info.fill = Color.CYAN; 168 this.addPath(this.clipShape, true); 169 this.clipAreaDrawn = true; 170 } 171 } 172 173 public void setClip(Shape clip) { 174 if (this.shapesEqual(this.clipShape, clip)) 175 return; 176 177 this.clipPath = this.parsePath(clip, true); 178 179 boolean complexClipPath = false; 180 181 if (clipPath.size() > 1) { 182 complexClipPath = true; 183 } else if (clipPath.size() == 1 && clipPath.get(0).points.size() > 5) { 184 //more than 4 points. 185 complexClipPath = true; 186 } 187 188 this.complexClipShape = complexClipPath; 189 this.clipAreaDrawn = false; 190 this.clipShape = clip; 191 } 192 193 private boolean shapesEqual(Shape shape1, Shape shape2) { 194 195 if (shape1 == null || shape2 == null) { 196 return false; 197 } 198 199 return shape1.getBounds2D().equals(shape2.getBounds2D()); 200 } 201 202 public void setStroke(Stroke s) { 203 BasicStroke stroke = (BasicStroke) s; 204 this.info.width = stroke.getLineWidth(); 205 this.info.dash = 0; 206 207 if (stroke.getDashArray() != null) { 208 this.info.dash = stroke.getDashArray().hashCode(); 209 } 210 } 211 212 public void drawString(float x, float y, String character, Color color) { 213 // TODO Auto-generated method stub 214 } 236 215 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/PageDrawer.java
r29912 r32542 47 47 * @version $Revision: 1.22 $ 48 48 */ 49 public class PageDrawer extends PDFStreamEngine 50 { 51 52 private GraphicsProcessor graphics; 53 private BasicStroke stroke; 54 protected PDPage page; 55 56 private final GeneralPath linePath = new GeneralPath(); 57 58 /** 59 * Default constructor, loads properties from file. 60 * 61 * @throws IOException If there is an error loading properties from the file. 62 */ 63 public PageDrawer() throws IOException 64 { 65 super( ResourceLoader.loadProperties( 66 "resources/pdfimport/pdfbox/PageDrawer.properties", true ) ); 67 } 68 69 /** 70 * This will draw the page to the requested context. 71 * 72 * @param g The graphics context to draw onto. 73 * @param p The page to draw. 74 * @param pageDimension The size of the page to draw. 75 * 76 * @throws IOException If there is an IO error while drawing the page. 77 */ 78 public void drawPage( GraphicsProcessor g, PDPage p) throws IOException 79 { 80 graphics = g; 81 page = p; 82 // Only if there is some content, we have to process it. 83 // Otherwise we are done here and we will produce an empty page 84 if ( page.getContents() != null) 85 { 86 PDResources resources = page.findResources(); 87 processStream( page, resources, page.getContents().getStream() ); 88 } 89 90 List<?> annotations = page.getAnnotations(); 91 for( int i=0; i<annotations.size(); i++ ) 92 { 93 PDAnnotation annot = (PDAnnotation)annotations.get( i ); 94 String appearanceName = annot.getAppearanceStream(); 95 PDAppearanceDictionary appearDictionary = annot.getAppearance(); 96 if( appearDictionary != null ) 97 { 98 if( appearanceName == null ) 99 { 100 appearanceName = "default"; 101 } 102 Map<?, ?> appearanceMap = appearDictionary.getNormalAppearance(); 103 if (appearanceMap != null) { 104 PDAppearanceStream appearance = 105 (PDAppearanceStream)appearanceMap.get( appearanceName ); 106 if( appearance != null ) 107 { 108 processSubStream( page, appearance.getResources(), appearance.getStream() ); 109 } 110 } 111 } 112 } 113 114 } 115 116 /** 117 * You should override this method if you want to perform an action when a 118 * text is being processed. 119 * 120 * @param text The text to process 121 */ 122 @Override 123 protected void processTextPosition( TextPosition text ) 124 { 125 126 Color color = null; 127 128 try 129 { 130 switch(this.getGraphicsState().getTextState().getRenderingMode()) { 131 case PDTextState.RENDERING_MODE_FILL_TEXT: 132 color = this.getGraphicsState().getNonStrokingColor().getJavaColor(); 133 break; 134 case PDTextState.RENDERING_MODE_STROKE_TEXT: 135 color = this.getGraphicsState().getStrokingColor().getJavaColor(); 136 break; 137 case PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT: 138 //basic support for text rendering mode "invisible" 139 Color nsc = this.getGraphicsState().getStrokingColor().getJavaColor(); 140 float[] components = {Color.black.getRed(),Color.black.getGreen(),Color.black.getBlue()}; 141 color = new Color(nsc.getColorSpace(),components,0f); 142 break; 143 default: 144 color = this.getGraphicsState().getNonStrokingColor().getJavaColor(); 145 } 146 147 Matrix textPos = text.getTextPos().copy(); 148 float x = textPos.getXPosition(); 149 float y = textPos.getYPosition(); 150 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 151 graphics.drawString(x,y,text.getCharacter(), color); 152 } 153 catch( IOException io ) 154 { 155 io.printStackTrace(); 156 } 157 } 158 159 160 /** 161 * Get the page that is currently being drawn. 162 * 163 * @return The page that is being drawn. 164 */ 165 public PDPage getPage() 166 { 167 return page; 168 } 169 170 171 /** 172 * Get the current line path to be drawn. 173 * 174 * @return The current line path to be drawn. 175 */ 176 public GeneralPath getLinePath() 177 { 178 return linePath; 179 } 180 181 182 /** 183 * This will set the current stroke. 184 * 185 * @param newStroke The current stroke. 186 * 187 */ 188 public void setStroke(BasicStroke newStroke) 189 { 190 this.stroke = newStroke; 191 } 192 193 public BasicStroke getStroke() { 194 return this.stroke; 195 } 196 197 198 public void drawPath(boolean stroke, boolean fill, int windingRule) throws IOException 199 { 200 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 201 GeneralPath path = getLinePath(); 202 203 Color strokeColor = getGraphicsState().getStrokingColor().getJavaColor(); 204 Color fillColor = getGraphicsState().getNonStrokingColor().getJavaColor(); 205 graphics.drawPath(path, stroke ? strokeColor : null, fill ? fillColor : null, windingRule); 206 207 path.reset(); 208 } 209 210 211 /** 212 * Draw the AWT image. Called by Invoke. 213 * Moved into PageDrawer so that Invoke doesn't have to reach in here for Graphics as that breaks extensibility. 214 * 215 * @param awtImage The image to draw. 216 * @param at The transformation to use when drawing. 217 * 218 */ 219 public void drawImage(){ 220 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 221 graphics.drawImage( ); 222 } 223 224 /** 225 * Fill with Shading. Called by SHFill operator. 226 * 227 * @param ShadingName The name of the Shading Dictionary to use for this fill instruction. 228 * 229 * @throws IOException If there is an IO error while shade-filling the path/clipping area. 230 */ 231 public void SHFill(COSName ShadingName) throws IOException 232 { 233 this.drawPath(false, true, Path2D.WIND_NON_ZERO); 234 } 235 236 237 238 //This code generalizes the code Jim Lynch wrote for AppendRectangleToPath 239 /** 240 * use the current transformation matrix to transform a single point. 241 * @param x x-coordinate of the point to be transform 242 * @param y y-coordinate of the point to be transform 243 * @return the transformed coordinates as Point2D.Double 244 */ 245 public java.awt.geom.Point2D.Double transformedPoint(double x, double y) 246 { 247 double[] position = {x,y}; 248 getGraphicsState().getCurrentTransformationMatrix().createAffineTransform().transform( 249 position, 0, position, 0, 1); 250 return new Point2D.Double(position[0],position[1]); 251 } 252 253 /** 254 * Set the clipping Path. 255 * 256 * @param windingRule The winding rule this path will use. 257 * 258 */ 259 public void setClippingPath(int windingRule) 260 { 261 PDGraphicsState graphicsState = getGraphicsState(); 262 GeneralPath clippingPath = (GeneralPath)getLinePath().clone(); 263 clippingPath.setWindingRule(windingRule); 264 // If there is already set a clipping path, we have to intersect the new with the existing one 265 if (graphicsState.getCurrentClippingPath() != null) 266 { 267 Area currentArea = new Area(getGraphicsState().getCurrentClippingPath()); 268 Area newArea = new Area(clippingPath); 269 currentArea.intersect(newArea); 270 graphicsState.setCurrentClippingPath(currentArea); 271 } 272 else 273 { 274 graphicsState.setCurrentClippingPath(clippingPath); 275 } 276 getLinePath().reset(); 277 } 49 public class PageDrawer extends PDFStreamEngine { 50 51 private GraphicsProcessor graphics; 52 private BasicStroke stroke; 53 protected PDPage page; 54 55 private final GeneralPath linePath = new GeneralPath(); 56 57 /** 58 * Default constructor, loads properties from file. 59 * 60 * @throws IOException If there is an error loading properties from the file. 61 */ 62 public PageDrawer() throws IOException { 63 super(ResourceLoader.loadProperties( 64 "resources/pdfimport/pdfbox/PageDrawer.properties", true)); 65 } 66 67 /** 68 * This will draw the page to the requested context. 69 * 70 * @param g The graphics context to draw onto. 71 * @param p The page to draw. 72 * @param pageDimension The size of the page to draw. 73 * 74 * @throws IOException If there is an IO error while drawing the page. 75 */ 76 public void drawPage(GraphicsProcessor g, PDPage p) throws IOException { 77 graphics = g; 78 page = p; 79 // Only if there is some content, we have to process it. 80 // Otherwise we are done here and we will produce an empty page 81 if (page.getContents() != null) { 82 PDResources resources = page.findResources(); 83 processStream(page, resources, page.getContents().getStream()); 84 } 85 86 List<?> annotations = page.getAnnotations(); 87 for (int i = 0; i < annotations.size(); i++) { 88 PDAnnotation annot = (PDAnnotation) annotations.get(i); 89 String appearanceName = annot.getAppearanceStream(); 90 PDAppearanceDictionary appearDictionary = annot.getAppearance(); 91 if (appearDictionary != null) { 92 if (appearanceName == null) { 93 appearanceName = "default"; 94 } 95 Map<?, ?> appearanceMap = appearDictionary.getNormalAppearance(); 96 if (appearanceMap != null) { 97 PDAppearanceStream appearance = 98 (PDAppearanceStream) appearanceMap.get(appearanceName); 99 if (appearance != null) { 100 processSubStream(page, appearance.getResources(), appearance.getStream()); 101 } 102 } 103 } 104 } 105 106 } 107 108 /** 109 * You should override this method if you want to perform an action when a 110 * text is being processed. 111 * 112 * @param text The text to process 113 */ 114 @Override 115 protected void processTextPosition(TextPosition text) { 116 117 Color color = null; 118 119 try { 120 switch(this.getGraphicsState().getTextState().getRenderingMode()) { 121 case PDTextState.RENDERING_MODE_FILL_TEXT: 122 color = this.getGraphicsState().getNonStrokingColor().getJavaColor(); 123 break; 124 case PDTextState.RENDERING_MODE_STROKE_TEXT: 125 color = this.getGraphicsState().getStrokingColor().getJavaColor(); 126 break; 127 case PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT: 128 //basic support for text rendering mode "invisible" 129 Color nsc = this.getGraphicsState().getStrokingColor().getJavaColor(); 130 float[] components = {Color.black.getRed(), Color.black.getGreen(), Color.black.getBlue()}; 131 color = new Color(nsc.getColorSpace(), components, 0f); 132 break; 133 default: 134 color = this.getGraphicsState().getNonStrokingColor().getJavaColor(); 135 } 136 137 Matrix textPos = text.getTextPos().copy(); 138 float x = textPos.getXPosition(); 139 float y = textPos.getYPosition(); 140 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 141 graphics.drawString(x, y, text.getCharacter(), color); 142 } catch (IOException io) { 143 io.printStackTrace(); 144 } 145 } 146 147 /** 148 * Get the page that is currently being drawn. 149 * 150 * @return The page that is being drawn. 151 */ 152 public PDPage getPage() { 153 return page; 154 } 155 156 /** 157 * Get the current line path to be drawn. 158 * 159 * @return The current line path to be drawn. 160 */ 161 public GeneralPath getLinePath() { 162 return linePath; 163 } 164 165 /** 166 * This will set the current stroke. 167 * 168 * @param newStroke The current stroke. 169 * 170 */ 171 public void setStroke(BasicStroke newStroke) { 172 this.stroke = newStroke; 173 } 174 175 public BasicStroke getStroke() { 176 return this.stroke; 177 } 178 179 public void drawPath(boolean stroke, boolean fill, int windingRule) throws IOException { 180 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 181 GeneralPath path = getLinePath(); 182 183 Color strokeColor = getGraphicsState().getStrokingColor().getJavaColor(); 184 Color fillColor = getGraphicsState().getNonStrokingColor().getJavaColor(); 185 graphics.drawPath(path, stroke ? strokeColor : null, fill ? fillColor : null, windingRule); 186 187 path.reset(); 188 } 189 190 191 /** 192 * Draw the AWT image. Called by Invoke. 193 * Moved into PageDrawer so that Invoke doesn't have to reach in here for Graphics as that breaks extensibility. 194 * 195 * @param awtImage The image to draw. 196 * @param at The transformation to use when drawing. 197 * 198 */ 199 public void drawImage() { 200 graphics.setClip(getGraphicsState().getCurrentClippingPath()); 201 graphics.drawImage(); 202 } 203 204 /** 205 * Fill with Shading. Called by SHFill operator. 206 * 207 * @param ShadingName The name of the Shading Dictionary to use for this fill instruction. 208 * 209 * @throws IOException If there is an IO error while shade-filling the path/clipping area. 210 */ 211 public void SHFill(COSName ShadingName) throws IOException { 212 this.drawPath(false, true, Path2D.WIND_NON_ZERO); 213 } 214 215 //This code generalizes the code Jim Lynch wrote for AppendRectangleToPath 216 /** 217 * use the current transformation matrix to transform a single point. 218 * @param x x-coordinate of the point to be transform 219 * @param y y-coordinate of the point to be transform 220 * @return the transformed coordinates as Point2D.Double 221 */ 222 public java.awt.geom.Point2D.Double transformedPoint(double x, double y) { 223 double[] position = {x, y}; 224 getGraphicsState().getCurrentTransformationMatrix().createAffineTransform().transform( 225 position, 0, position, 0, 1); 226 return new Point2D.Double(position[0], position[1]); 227 } 228 229 /** 230 * Set the clipping Path. 231 * 232 * @param windingRule The winding rule this path will use. 233 * 234 */ 235 public void setClippingPath(int windingRule) { 236 PDGraphicsState graphicsState = getGraphicsState(); 237 GeneralPath clippingPath = (GeneralPath) getLinePath().clone(); 238 clippingPath.setWindingRule(windingRule); 239 // If there is already set a clipping path, we have to intersect the new with the existing one 240 if (graphicsState.getCurrentClippingPath() != null) { 241 Area currentArea = new Area(getGraphicsState().getCurrentClippingPath()); 242 Area newArea = new Area(clippingPath); 243 currentArea.intersect(newArea); 244 graphicsState.setCurrentClippingPath(currentArea); 245 } else { 246 graphicsState.setCurrentClippingPath(clippingPath); 247 } 248 getLinePath().reset(); 249 } 278 250 } -
applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/PdfBoxParser.java
r32524 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport.pdfbox; 2 3 … … 16 17 import pdfimport.PathOptimizer; 17 18 18 public class PdfBoxParser extends PDFStreamEngine{ 19 19 public class PdfBoxParser extends PDFStreamEngine { 20 private final PathOptimizer target; 20 21 21 22 23 22 public PdfBoxParser(PathOptimizer target) { 23 this.target = target; 24 } 24 25 25 26 public void parse(File file, int maxPaths, ProgressMonitor monitor) throws IOException { … … 37 38 throw new IllegalArgumentException(tr("The PDF file must have exactly one page.")); 38 39 } 39 40 40 41 PDPage page = (PDPage) allPages.get(0); 41 42 PDRectangle pageSize = page.findMediaBox(); … … 45 46 rotation = rotationVal.intValue(); 46 47 } 47 48 48 49 new PageDrawer().drawPage(new GraphicsProcessor(target, rotation, maxPaths, monitor), page); 49 50 this.target.bounds = new Rectangle2D.Double( 50 51 pageSize.getLowerLeftX(), 51 pageSize.getLowerLeftY(), 52 pageSize.getWidth(), 52 pageSize.getLowerLeftY(), 53 pageSize.getWidth(), 53 54 pageSize.getHeight()); 54 55 } -
applications/editors/josm/plugins/pdfimport/test/unit/pdfimport/pdfbox/PDFParserTest.java
r32524 r32542 1 // License: GPL. For details, see LICENSE file. 1 2 package pdfimport.pdfbox; 2 3
Note:
See TracChangeset
for help on using the changeset viewer.