Ignore:
Timestamp:
2016-07-03T12:20:52+02:00 (8 years ago)
Author:
donvip
Message:

checkstyle

Location:
applications/editors/josm/plugins/pdfimport
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pdfimport/.project

    r32286 r32542  
    1616                        </arguments>
    1717                </buildCommand>
     18                <buildCommand>
     19                        <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
     20                        <arguments>
     21                        </arguments>
     22                </buildCommand>
    1823        </buildSpec>
    1924        <natures>
    2025                <nature>org.eclipse.jdt.core.javanature</nature>
     26                <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
    2127        </natures>
    2228</projectDescription>
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/DuplicateNodesFinder.java

    r30737 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1112import java.util.TreeMap;
    1213
    13 public class DuplicateNodesFinder {
     14public final class DuplicateNodesFinder {
    1415
    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    }
    2919
    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        });
    3435
    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();
    3841
    39                                 return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
    40                         }
    41                 });
     42                if (Math.abs(diff) <= tolerance) {
     43                    return 0;
     44                }
    4245
    43                 //sweep from top to bottom.
    44                 double prevY = Double.NEGATIVE_INFINITY;
     46                return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
     47            }
     48        });
    4549
    46                 for(Point2D point: points) {
    47                         boolean mappedToOtherPoint = false;
     50        //sweep from top to bottom.
     51        double prevY = Double.NEGATIVE_INFINITY;
    4852
    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;
    5455
    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)
    6761
    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);
    7172
    72                         if (!mappedToOtherPoint) {
    73                                 sweepLine.put(point, point);
    74                         }
     73                    }
     74                }
     75            }
    7576
    76                         prevY = point.getY();
    77                 }
     77            if (!mappedToOtherPoint) {
     78                sweepLine.put(point, point);
     79            }
    7880
    79                 return result;
    80         }
     81            prevY = point.getY();
     82        }
     83
     84        return result;
     85    }
    8186}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/FilePlacement.java

    r29854 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1314
    1415public 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    }
    219208
    220209}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/LayerContents.java

    r30737 r32542  
    1 /**
    2  *
    3  */
     1// License: GPL. For details, see LICENSE file.
    42package pdfimport;
    53
     
    86import java.util.List;
    97
    10 public class LayerContents{
     8public class LayerContents {
    119
    12         List<Point2D> points = new ArrayList<>();
    13         List<PdfPath> paths = new ArrayList<>();
    14         List<PdfMultiPath> multiPaths = new ArrayList<>();
    15         LayerInfo info;
     10    List<Point2D> points = new ArrayList<>();
     11    List<PdfPath> paths = new ArrayList<>();
     12    List<PdfMultiPath> multiPaths = new ArrayList<>();
     13    LayerInfo info;
    1614}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/LayerInfo.java

    r25349 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
    34import java.awt.Color;
    45
    5 public class LayerInfo{
    6         public Color fill;
    7         public Color stroke;
    8         public int dash;
    9         public double width;
    10         public int divider;
    11         public boolean isGroup;
     6public 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;
    1213
    13         public int nr;
     14    public int nr;
    1415
    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;
    1919
    20                 if (this.fill != null) {
    21                         code ^= this.fill.hashCode();
    22                 }
     20        if (this.fill != null) {
     21            code ^= this.fill.hashCode();
     22        }
    2323
    24                 if (this.stroke != null) {
    25                         code ^= this.stroke.hashCode();
    26                 }
     24        if (this.stroke != null) {
     25            code ^= this.stroke.hashCode();
     26        }
    2727
    28                 return code;
    29         }
     28        return code;
     29    }
    3030
    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;
    3837
    3938
    40                 if (this.fill != null){
    41                         eq &= this.fill.equals(l.fill);
    42                 }
     39        if (this.fill != null) {
     40            eq &= this.fill.equals(l.fill);
     41        }
    4342
    44                 if (this.stroke != null) {
    45                         eq &= this.stroke.equals(l.stroke);
    46                 }
     43        if (this.stroke != null) {
     44            eq &= this.stroke.equals(l.stroke);
     45        }
    4746
    48                 return eq;
    49         }
     47        return eq;
     48    }
    5049
    51         public LayerInfo copy() {
    52                 LayerInfo result = new LayerInfo();
    53                 result.fill = this.fill;
    54                 result.stroke = this.stroke;
    55                 result.dash = this.dash;
    56                 result.width = this.width;
    57                 result.divider = this.divider;
    58                 return result;
    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    }
    6059
    6160}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/LoadPdfDialog.java

    r32515 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    6364import pdfimport.pdfbox.PdfBoxParser;
    6465
    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         }
     66public 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    }
    10961074
    10971075}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/OrthogonalShapesFilter.java

    r25349 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    45
    56public class OrthogonalShapesFilter {
    6         private double tolerance;
     7    private double tolerance;
    78
    8         public OrthogonalShapesFilter(double toleranceDegrees) {
    9                 tolerance = Math.toRadians(toleranceDegrees);
    10         }
     9    public OrthogonalShapesFilter(double toleranceDegrees) {
     10        tolerance = Math.toRadians(toleranceDegrees);
     11    }
    1112
    12         public boolean isOrthogonal(PdfPath path) {
     13    public boolean isOrthogonal(PdfPath path) {
    1314
    14                 if (path.points.size() < 3)
    15                         return false;
     15        if (path.points.size() < 3)
     16            return false;
    1617
    17                 int targetPos = path.isClosed() ? path.points.size(): path.points.size() - 1;
     18        int targetPos = path.isClosed() ? path.points.size() : path.points.size() - 1;
    1819
    19                 for(int pos = 1; pos < targetPos; pos++) {
    20                         Point2D p1 = path.points.get(pos -1);
    21                         Point2D p2 = path.points.get(pos);
    22                         Point2D p3 = pos+1 == path.points.size() ? path.points.get(1) : path.points.get(pos+1);
     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);
    2324
    24                         double angle1 = Math.atan2(p2.getY() - p1.getY(),p2.getX() - p1.getX());
    25                         double angle2 = Math.atan2(p3.getY() - p2.getY(),p3.getX() - p2.getX());
     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());
    2627
    27                         double angleDifference = angle1 - angle2;
    28                         while (angleDifference < 0) angleDifference += Math.PI;
     28            double angleDifference = angle1 - angle2;
     29            while (angleDifference < 0) angleDifference += Math.PI;
    2930
    30                         //test straight angles
    31                         boolean hasGoodVariant = false;
     31            //test straight angles
     32            boolean hasGoodVariant = false;
    3233
    33                         for (int quadrant = 0; quadrant <= 4; quadrant ++) {
    34                                 double difference = angleDifference - Math.PI / 2 * quadrant;
    35                                 if (Math.abs(difference) <= tolerance)
    36                                         hasGoodVariant = true;
    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            }
    3839
    39                         if (!hasGoodVariant)
    40                                 return false;
    41                 }
     40            if (!hasGoodVariant)
     41                return false;
     42        }
    4243
    43                 return true;
    44         }
     44        return true;
     45    }
    4546}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/OsmBuilder.java

    r30737 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1920public class OsmBuilder {
    2021
    21         enum Mode {Draft, Final, Debug};
     22    enum Mode { Draft, Final, Debug }
    2223
    23         private final FilePlacement placement;
     24    private final FilePlacement placement;
    2425
    25         private String layerName;
    26         private String fillName;
    27         private String lineName;
    28         private Mode mode;
     26    private String layerName;
     27    private String fillName;
     28    private String lineName;
     29    private Mode mode;
    2930
    30         private ProgressMonitor monitor;
    31         private int monitorPos;
    32         private int monitorTotal;
     31    private ProgressMonitor monitor;
     32    private int monitorPos;
     33    private int monitorTotal;
    3334
    34         public OsmBuilder(FilePlacement placement)
    35         {
    36                 this.placement = placement;
    37         }
     35    public OsmBuilder(FilePlacement placement) {
     36        this.placement = placement;
     37    }
    3838
    39         public DataSet build(List<LayerContents> data, Mode mode, ProgressMonitor monitor) {
     39    public DataSet build(List<LayerContents> data, Mode mode, ProgressMonitor monitor) {
    4040
    41                 this.monitor = monitor;
    42                 this.monitorPos = 0;
    43                 this.mode = mode;
    44                 DataSet result = new DataSet();
     41        this.monitor = monitor;
     42        this.monitorPos = 0;
     43        this.mode = mode;
     44        DataSet result = new DataSet();
    4545
    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                 }
     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        }
    5454
    55                 monitor.beginTask(tr("Building JOSM layer."), this.monitorTotal);
     55        monitor.beginTask(tr("Building JOSM layer."), this.monitorTotal);
    5656
    5757
    58                 for (LayerContents layer: data) {
    59                         this.addLayer(result, layer);
    60                 }
     58        for (LayerContents layer: data) {
     59            this.addLayer(result, layer);
     60        }
    6161
    62                 monitor.finishTask();
    63                 return result;
    64         }
     62        monitor.finishTask();
     63        return result;
     64    }
    6565
     66    private void addLayer(DataSet target, LayerContents layer) {
     67        Map<Point2D, Node> point2Node = new HashMap<>();
    6668
    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;
    6972
    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));
    7377
    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        }
    7881
    79                         target.addPrimitive(node);
    80                         point2Node.put(pt, node);
    81                 }
     82        //insert ways
     83        Map<PdfPath, Way> path2Way = new HashMap<>();
    8284
    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        }
    8590
    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        }
    91100
    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();
    101105
    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);
    106110
    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                }
    111115
    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    }
    116120
    117                                 target.addPrimitive(rel);
    118                         }
    119                 }
    120         }
     121    private Way insertWay(PdfPath path, Map<Point2D, Node> point2Node, int multipathId, boolean multipolygon) {
    121122
    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++;
    123128
    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());
    129130
    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            }
    131136
    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        }
    137139
    138                         nodes.add(node);
    139                 }
     140        Map<String, String> keys = new HashMap<>();
    140141
    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);
    142145
    143                 if (this.mode != Mode.Draft) {
    144                         keys.put("PDF_nr", "" + path.nr);
    145                         keys.put("PDF_layer", this.layerName);
     146            if (path.isClosed()) {
     147                keys.put("PDF_closed", "yes");
     148            }
    146149
    147                         if (path.isClosed()){
    148                                 keys.put("PDF_closed", "yes");
    149                         }
     150            if (this.fillName != null) {
     151                keys.put("PDF_fillColor", this.fillName);
     152            }
    150153
    151                         if (this.fillName != null){
    152                                 keys.put("PDF_fillColor", this.fillName);
    153                         }
     154            if (this.lineName != null) {
     155                keys.put("PDF_lineColor", this.lineName);
     156            }
    154157
    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        }
    158164
    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) {
    166166
    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        }
    168173
    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    }
    175179
    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        }
    181184
     185        String s = Integer.toHexString(col.getRGB() & 0xffffff);
     186        while (s.length() < 6) {
     187            s = "0" + s;
     188        }
    182189
    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    }
    196192}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/ParallelSegmentsFinder.java

    r30737 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1314
    1415public class ParallelSegmentsFinder {
    15         public double angle;
    16         public double angleSum;
    17         public int refCount;
    18         public List<PdfPath> paths = new ArrayList<>();
     16    public double angle;
     17    public double angleSum;
     18    public int refCount;
     19    public List<PdfPath> paths = new ArrayList<>();
    1920
    20         public void addPath(PdfPath path, double angle2) {
    21                 angleSum += angle2;
    22                 paths.add(path);
    23                 angle = angleSum /paths.size();
    24         }
     21    public void addPath(PdfPath path, double angle2) {
     22        angleSum += angle2;
     23        paths.add(path);
     24        angle = angleSum /paths.size();
     25    }
    2526
    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);
    3131
    32                 final Map<PdfPath, Point2D> positions = new HashMap<>();
    33                 Point2D src = new Point2D.Double();
     32        final Map<PdfPath, Point2D> positions = new HashMap<>();
     33        Point2D src = new Point2D.Double();
    3434
    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
    4746
    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        });
    5555
    56                 //process sweep
    57                 List<ParallelSegmentsFinder> result = new ArrayList<>();
     56        //process sweep
     57        List<ParallelSegmentsFinder> result = new ArrayList<>();
    5858
    59                 Map<PdfPath, ParallelSegmentsFinder> sweepLine = new HashMap<>();
     59        Map<PdfPath, ParallelSegmentsFinder> sweepLine = new HashMap<>();
    6060
    61                 Set<ParallelSegmentsFinder> adjacentClustersSet = new HashSet<>();
    62                 List<ParallelSegmentsFinder> adjacentClusters = new ArrayList<>();
    63                 List<PdfPath> pathsToRemove = new ArrayList<>();
     61        Set<ParallelSegmentsFinder> adjacentClustersSet = new HashSet<>();
     62        List<ParallelSegmentsFinder> adjacentClusters = new ArrayList<>();
     63        List<PdfPath> pathsToRemove = new ArrayList<>();
    6464
    65                 for (PdfPath path: paths){
    66                         adjacentClusters.clear();
    67                         adjacentClustersSet.clear();
    68                         pathsToRemove.clear();
     65        for (PdfPath path: paths) {
     66            adjacentClusters.clear();
     67            adjacentClustersSet.clear();
     68            pathsToRemove.clear();
    6969
    70                         for (PdfPath p: sweepLine.keySet()) {
    71                                 Point2D pathPos = positions.get(path);
    72                                 Point2D pPos = positions.get(p);
     70            for (PdfPath p: sweepLine.keySet()) {
     71                Point2D pathPos = positions.get(path);
     72                Point2D pPos = positions.get(p);
    7373
    74                                 if (pathPos.getY() - pPos.getY() > maxDistance) {
    75                                         //path too far from sweep line
    76                                         pathsToRemove.add(p);
    77                                 } else {
     74                if (pathPos.getY() - pPos.getY() > maxDistance) {
     75                    //path too far from sweep line
     76                    pathsToRemove.add(p);
     77                } else {
    7878
    79                                         double distance = distanceLineLine(path, p);
     79                    double distance = distanceLineLine(path, p);
    8080
    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            }
    8988
    90                         //remove segments too far apart
    91                         for(PdfPath p: pathsToRemove){
    92                                 ParallelSegmentsFinder finder = sweepLine.remove(p);
    93                                 finder.refCount --;
    94                                 if (finder.refCount == 0){
    95                                         result.add(finder);
    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            }
    9897
    99                         //join together joinable parts
    100                         if (adjacentClusters.size() > 0){
    101                                 ParallelSegmentsFinder finder = adjacentClusters.remove(0);
    102                                 finder.paths.add(path);
    103                                 sweepLine.put(path, finder);
    104                                 finder.refCount ++;
     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++;
    105104
    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        }
    122119
    123                 //process remaining paths in sweep line
    124                 for (PdfPath p: sweepLine.keySet()) {
    125                         ParallelSegmentsFinder finder = sweepLine.get(p);
    126                         finder.refCount --;
    127                         if (finder.refCount == 0){
    128                                 result.add(finder);
    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        }
    131128
    132                 return result;
    133         }
     129        return result;
     130    }
    134131
    135         private double distanceLineLine(PdfPath p1, PdfPath p2) {
    136                 return distanceLineLine(p1.firstPoint(), p1.lastPoint(), p2.firstPoint(), p2.lastPoint());
    137         }
     132    private double distanceLineLine(PdfPath p1, PdfPath p2) {
     133        return distanceLineLine(p1.firstPoint(), p1.lastPoint(), p2.firstPoint(), p2.lastPoint());
     134    }
    138135
    139         private double distanceLineLine(Point2D p1, Point2D p2, Point2D p3, Point2D p4) {
    140                 double dist1 = closestPointToSegment(p1, p2, p3).distance(p3);
    141                 double dist2 = closestPointToSegment(p1, p2, p4).distance(p4);
    142                 double dist3 = closestPointToSegment(p3, p4, p1).distance(p1);
    143                 double dist4 = closestPointToSegment(p3, p4, p2).distance(p2);
    144                 return Math.min(Math.min(dist1, dist2),Math.min(dist3, dist4));
    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    }
    146143
    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) {
    156150
    157                 double ldx = segmentP2.getX() - segmentP1.getX();
    158                 double ldy = segmentP2.getY() - segmentP1.getY();
     151        double ldx = segmentP2.getX() - segmentP1.getX();
     152        double ldy = segmentP2.getY() - segmentP1.getY();
    159153
    160                 if (ldx == 0 && ldy == 0) //segment zero length
    161                         return segmentP1;
     154        if (ldx == 0 && ldy == 0) //segment zero length
     155            return segmentP1;
    162156
    163                 double pdx = point.getX() - segmentP1.getX();
    164                 double pdy = point.getY() - segmentP1.getY();
     157        double pdx = point.getX() - segmentP1.getX();
     158        double pdy = point.getY() - segmentP1.getY();
    165159
    166                 double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
     160        double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
    167161
    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    }
    176169}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/PathOptimizer.java

    r30737 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1415public class PathOptimizer {
    1516
    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    }
    806758}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfImportAction.java

    r27867 r32542  
    1 // License: GPL.
     1// License: GPL. For details, see LICENSE file.
    22package pdfimport;
    33
     
    1616public class PdfImportAction extends JosmAction {
    1717
    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    }
    2524
    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) {
    3333
    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         }
     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    }
    4040}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfImportPlugin.java

    r29805 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    1314public class PdfImportPlugin extends Plugin {
    1415
    15         protected String name;
     16    protected String name;
    1617
    17         public PdfImportPlugin(PluginInformation info) {
    18                 super(info);
    19                 name = tr("Import PDF file");
    20                 MainMenu.add(Main.main.menu.imagerySubMenu, new PdfImportAction());
    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    }
    2223}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfMultiPath.java

    r29854 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    45
    56public class PdfMultiPath {
    6         public List<PdfPath> paths;
    7         public LayerContents layer;
     7    public List<PdfPath> paths;
     8    public LayerContents layer;
    89
    9         public PdfMultiPath(List<PdfPath> paths2) {
    10                 paths = paths2;
    11         }
    12 
     10    public PdfMultiPath(List<PdfPath> paths2) {
     11        paths = paths2;
     12    }
    1313}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/PdfPath.java

    r25349 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport;
    23
     
    56
    67public class PdfPath {
    7         public List<Point2D> points;
    8         public double length;
     8    public List<Point2D> points;
     9    public double length;
    910
    10         LayerContents layer;
    11         public int nr;
     11    LayerContents layer;
     12    public int nr;
    1213
     14    public PdfPath(List<Point2D> nodes) {
     15        points = nodes;
     16    }
    1317
    14         public 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    }
    1721
    18         public boolean isClosed() {
    19                 return points.size() > 1 && points.get(0) == points.get(points.size() - 1);
    20         }
     22    public Point2D firstPoint() {
     23        return points.get(0);
     24    }
    2125
    22         public Point2D firstPoint() {
    23                 return points.get(0);
    24         }
     26    public Point2D lastPoint() {
     27        return points.get(points.size() - 1);
     28    }
    2529
    26         public Point2D lastPoint() {
    27                 return points.get(points.size() - 1);
    28         }
     30    public void calculateLength() {
     31        double len = 0;
    2932
    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        }
    3236
    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    }
    3639
    37                 this.length = len;
    38         }
     40    public Point2D getOtherEnd(Point2D endPoint) {
     41        if (this.firstPoint() == endPoint) {
     42            return this.lastPoint();
     43        }
    3944
    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        }
    4448
    45                 if (this.lastPoint() == endPoint) {
    46                         return this.firstPoint();
    47                 }
     49        throw new RuntimeException("Unexpected point");
    4850
    49                 throw new RuntimeException("Unexpected point");
    50 
    51         }
     51    }
    5252}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/ProjectionInfo.java

    r30737 r32542  
    1010import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
    1111
    12 public class ProjectionInfo {
     12public final class ProjectionInfo {
    1313    private static Map<String, ProjectionChoice> allCodesPC = new HashMap<>();
    1414    private static Map<String, Projection> allCodes = new HashMap<>();
     
    2020            }
    2121        }
     22    }
     23
     24    private ProjectionInfo() {
     25        // Hide default constructor for utilities classes
    2226    }
    2327
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/GraphicsProcessor.java

    r30737 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport.pdfbox;
    23
     
    1920import pdfimport.PdfPath;
    2021
    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         }
     22public 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    }
    236215}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/PageDrawer.java

    r29912 r32542  
    4747 * @version $Revision: 1.22 $
    4848 */
    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         }
     49public 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    }
    278250}
  • applications/editors/josm/plugins/pdfimport/src/pdfimport/pdfbox/PdfBoxParser.java

    r32524 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport.pdfbox;
    23
     
    1617import pdfimport.PathOptimizer;
    1718
    18 public class PdfBoxParser extends PDFStreamEngine{
    19         private final PathOptimizer target;
     19public class PdfBoxParser extends PDFStreamEngine {
     20    private final PathOptimizer target;
    2021
    21         public PdfBoxParser(PathOptimizer target){
    22                 this.target = target;
    23         }
     22    public PdfBoxParser(PathOptimizer target) {
     23        this.target = target;
     24    }
    2425
    2526    public void parse(File file, int maxPaths, ProgressMonitor monitor) throws IOException {
     
    3738                throw new IllegalArgumentException(tr("The PDF file must have exactly one page."));
    3839            }
    39            
     40
    4041            PDPage page = (PDPage) allPages.get(0);
    4142            PDRectangle pageSize = page.findMediaBox();
     
    4546                rotation = rotationVal.intValue();
    4647            }
    47    
     48
    4849            new PageDrawer().drawPage(new GraphicsProcessor(target, rotation, maxPaths, monitor), page);
    4950            this.target.bounds = new Rectangle2D.Double(
    5051                    pageSize.getLowerLeftX(),
    51                     pageSize.getLowerLeftY(), 
    52                     pageSize.getWidth(), 
     52                    pageSize.getLowerLeftY(),
     53                    pageSize.getWidth(),
    5354                    pageSize.getHeight());
    5455        }
  • applications/editors/josm/plugins/pdfimport/test/unit/pdfimport/pdfbox/PDFParserTest.java

    r32524 r32542  
     1// License: GPL. For details, see LICENSE file.
    12package pdfimport.pdfbox;
    23
Note: See TracChangeset for help on using the changeset viewer.