Ticket #22179: 22179.patch

File 22179.patch, 63.7 KB (added by taylor.smock, 3 years ago)
  • plugins/geotools/ivy.xml

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/geotools/ivy.xml b/plugins/geotools/ivy.xml
    a b  
    1313        <dependency org="org.geotools" name="gt-opengis" rev="${gt.version}" conf="default->default"/>
    1414        <dependency org="org.geotools" name="gt-referencing" rev="${gt.version}" conf="default->default"/>
    1515        <dependency org="org.geotools" name="gt-shapefile" rev="${gt.version}" conf="default->default"/>
     16        <dependency org="org.geotools" name="gt-geopkg" rev="${gt.version}" conf="default->default"/>
    1617        <!-- Dependencies that were not needed in 22.0 (according to lib in svn) -->
    1718        <exclude org="org.geotools" module="gt-imagemosaic"/>
    1819        <exclude org="net.sourceforge.hatbox" module="hatbox"/>
  • plugins/geotools/ivy_settings.xml

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/geotools/ivy_settings.xml b/plugins/geotools/ivy_settings.xml
    a b  
    11<?xml version="1.0" encoding="utf-8"?>
    22<ivysettings>
    33  <!-- When geotools is updated, run `ant merge-geotools-services` -->
    4   <property name="gt.version" value="27.0"/>
     4  <property name="gt.version" value="27.1"/>
    55  <settings defaultResolver="ordered-resolvers"/>
    66  <resolvers>
    77    <chain name="ordered-resolvers">
  • plugins/geotools/README

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/geotools/README b/plugins/geotools/README
    a b  
    33This plugin provides parts of the GeoTools library for JOSM plugins.
    44    * Licensed under GPL v3 (see LICENSE)
    55
    6 The current embedded version of GeoTools is 26.2.
     6The current embedded version of GeoTools is 27.1.
    77
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java
    a b  
    55import org.geotools.referencing.operation.projection.LambertConformal2SP;
    66import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
    77import org.opengis.referencing.FactoryException;
    8 import org.opengis.referencing.NoSuchAuthorityCodeException;
    98import org.opengis.referencing.crs.CoordinateReferenceSystem;
    109import org.opengis.referencing.crs.ProjectedCRS;
    1110import org.opengis.referencing.datum.GeodeticDatum;
    1211import org.opengis.referencing.operation.MathTransform;
    1312import org.openstreetmap.josm.plugins.opendata.core.io.geographic.DefaultShpHandler;
     13import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeotoolsHandler;
    1414
     15/**
     16 * A handler for french-specific shapefiles
     17 */
    1518public class FrenchShpHandler extends DefaultShpHandler {
    1619
    1720    @Override
    18     public CoordinateReferenceSystem getCrsFor(String crsName) throws NoSuchAuthorityCodeException, FactoryException {
    19         if (crsName.equalsIgnoreCase("RGM04")) {
     21    public CoordinateReferenceSystem getCrsFor(String crsName) throws FactoryException {
     22        if ("RGM04".equalsIgnoreCase(crsName)) {
    2023            return CRS.decode("EPSG:4471");
    21         } else if (crsName.equalsIgnoreCase("RGFG95_UTM_Zone_22N")) {
     24        } else if ("RGFG95_UTM_Zone_22N".equalsIgnoreCase(crsName)) {
    2225            return CRS.decode("EPSG:2972");
    2326        } else {
    2427            return super.getCrsFor(crsName);
     
    2831    @Override
    2932    public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
    3033            throws FactoryException {
    31         if (sourceCRS.getName().getCode().equalsIgnoreCase("Lambert I Nord")) {
    32             if (sourceCRS instanceof ProjectedCRS) {
    33                 GeodeticDatum datum = ((ProjectedCRS) sourceCRS).getDatum();
    34                 if (datum.getPrimeMeridian().getGreenwichLongitude() > 0.0
    35                         && ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform() instanceof LambertConformal2SP) {
    36                     LambertConformal2SP lambert = (LambertConformal2SP) ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform();
    37                     Double falseNorthing = get(lambert.getParameterValues(), AbstractProvider.FALSE_NORTHING);
    38                     Double centralmeridian = get(lambert.getParameterValues(), AbstractProvider.CENTRAL_MERIDIAN);
    39                     if (centralmeridian.equals(0.0)) {
    40                         if (falseNorthing.equals(200000.0)) {
    41                             return CRS.findMathTransform(CRS.decode("EPSG:27561"), targetCRS, lenient);
    42                         } else if (falseNorthing.equals(1200000.0)) {
    43                             return CRS.findMathTransform(CRS.decode("EPSG:27571"), targetCRS, lenient);
    44                         }
     34        if ("Lambert I Nord".equalsIgnoreCase(sourceCRS.getName().getCode()) && sourceCRS instanceof ProjectedCRS) {
     35            GeodeticDatum datum = ((ProjectedCRS) sourceCRS).getDatum();
     36            if (datum.getPrimeMeridian().getGreenwichLongitude() > 0.0
     37                    && ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform() instanceof LambertConformal2SP) {
     38                LambertConformal2SP lambert = (LambertConformal2SP) ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform();
     39                Double falseNorthing = GeotoolsHandler.get(lambert.getParameterValues(), AbstractProvider.FALSE_NORTHING);
     40                Double centralmeridian = GeotoolsHandler.get(lambert.getParameterValues(), AbstractProvider.CENTRAL_MERIDIAN);
     41                if (centralmeridian.equals(0.0)) {
     42                    if (falseNorthing.equals(200000.0)) {
     43                        return CRS.findMathTransform(CRS.decode("EPSG:27561"), targetCRS, lenient);
     44                    } else if (falseNorthing.equals(1200000.0)) {
     45                        return CRS.findMathTransform(CRS.decode("EPSG:27571"), targetCRS, lenient);
    4546                    }
    4647                }
    4748            }
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java
    a b  
    2828import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GmlHandler;
    2929import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifHandler;
    3030import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpHandler;
     31import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.DefaultGeoPackageHandler;
     32import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.GeoPackageHandler;
    3133import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvHandler;
    3234import org.openstreetmap.josm.plugins.opendata.core.io.tabular.DefaultCsvHandler;
    3335import org.openstreetmap.josm.plugins.opendata.core.io.tabular.SpreadSheetHandler;
     
    8284        setArchiveHandler(new DefaultArchiveHandler());
    8385        setCsvHandler(new DefaultCsvHandler());
    8486        setGmlHandler(new DefaultGmlHandler());
     87        setGeoPackageHandler(new DefaultGeoPackageHandler());
    8588    }
    8689
    8790    private boolean acceptsFilename(String filename, String[] expected, String ... extensions) {
     
    162165        return acceptsFilename(filename, expected, OdConstants.CSV_EXT, OdConstants.XLS_EXT);
    163166    }
    164167
     168    protected final boolean acceptsGpkgFilename(String filename, String... expected) {
     169        return acceptsFilename(filename, expected, OdConstants.GEOPACKAGE_EXT);
     170    }
     171
    165172    // -------------------- License --------------------
    166173
    167174    private License license;
     
    479486        return gmlHandler;
    480487    }
    481488
     489    // ------------ GeoPackage handling ------------
     490
     491    private GeoPackageHandler geoPackageHandler;
     492
     493    public final void setGeoPackageHandler(GeoPackageHandler handler) {
     494        this.geoPackageHandler = handler;
     495    }
     496
     497    public final GeoPackageHandler getGeoPackageHandler() {
     498        return this.geoPackageHandler;
     499    }
     500
    482501    // ------------ Archive handling ------------
    483502
    484503    private ArchiveHandler archiveHandler;
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java
    a b  
    22package org.openstreetmap.josm.plugins.opendata.core.io.geographic;
    33
    44import java.nio.charset.Charset;
    5 import java.util.ArrayList;
    6 import java.util.List;
    75import java.util.Set;
    86
    9 import org.geotools.referencing.CRS;
    10 import org.geotools.referencing.crs.AbstractDerivedCRS;
    11 import org.geotools.referencing.datum.DefaultEllipsoid;
    12 import org.geotools.referencing.operation.projection.LambertConformal;
    13 import org.geotools.referencing.operation.projection.LambertConformal1SP;
    14 import org.geotools.referencing.operation.projection.LambertConformal2SP;
    15 import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
    16 import org.opengis.parameter.ParameterDescriptor;
    17 import org.opengis.parameter.ParameterValueGroup;
    18 import org.opengis.referencing.FactoryException;
    19 import org.opengis.referencing.crs.CoordinateReferenceSystem;
    20 import org.opengis.referencing.datum.GeodeticDatum;
    21 import org.opengis.referencing.operation.MathTransform;
    227import org.openstreetmap.josm.data.osm.DataSet;
    238import org.openstreetmap.josm.data.osm.OsmPrimitive;
    24 import org.openstreetmap.josm.data.projection.AbstractProjection;
    25 import org.openstreetmap.josm.data.projection.Ellipsoid;
    26 import org.openstreetmap.josm.data.projection.Projection;
    27 import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
    28 import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters;
    29 import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters1SP;
    30 import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters2SP;
    31 import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
    32 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
    33 import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
    34 import org.openstreetmap.josm.spi.preferences.Config;
    35 import org.openstreetmap.josm.tools.Logging;
    36 import org.openstreetmap.josm.tools.Pair;
    37 
    38 public class DefaultShpHandler extends DefaultGeographicHandler implements ShpHandler {
    399
    40     private static final List<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>>
    41     ellipsoids = new ArrayList<>();
    42     static {
    43         ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.GRS80, Ellipsoid.GRS80));
    44         ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.WGS84, Ellipsoid.WGS84));
    45     }
     10/**
     11 * The default shapefile handler
     12 */
     13public class DefaultShpHandler extends DefaultGeographicHandler implements ShpHandler, GeotoolsHandler {
    4614
    47     protected static final Double get(ParameterValueGroup values, ParameterDescriptor<?> desc) {
    48         return (Double) values.parameter(desc.getName().getCode()).getValue();
    49     }
    50 
    51     private static boolean equals(Double a, Double b) {
    52         boolean res = Math.abs(a - b) <= Config.getPref().getDouble(
    53                 OdConstants.PREF_CRS_COMPARISON_TOLERANCE, OdConstants.DEFAULT_CRS_COMPARISON_TOLERANCE);
    54         if (Config.getPref().getBoolean(OdConstants.PREF_CRS_COMPARISON_DEBUG, false)) {
    55             Logging.debug("Comparing "+a+" and "+b+" -> "+res);
    56         }
    57         return res;
    58     }
    59 
    60     private Charset dbfCharset = null;
    61 
    62     @Override
    63     public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
    64             throws FactoryException {
    65         if (getCrsFor(sourceCRS.getName().getCode()) != null) {
    66             return CRS.findMathTransform(getCrsFor(sourceCRS.getName().getCode()), targetCRS, lenient);
    67         } else if (sourceCRS instanceof AbstractDerivedCRS && sourceCRS.getName().getCode().equalsIgnoreCase("Lambert_Conformal_Conic")) {
    68             List<MathTransform> result = new ArrayList<>();
    69             AbstractDerivedCRS crs = (AbstractDerivedCRS) sourceCRS;
    70             MathTransform transform = crs.getConversionFromBase().getMathTransform();
    71             if (transform instanceof LambertConformal && crs.getDatum() instanceof GeodeticDatum) {
    72                 LambertConformal lambert = (LambertConformal) transform;
    73                 GeodeticDatum geo = (GeodeticDatum) crs.getDatum();
    74                 for (ProjectionChoice choice : ProjectionPreference.getProjectionChoices()) {
    75                     Projection p = choice.getProjection();
    76                     if (p instanceof AbstractProjection) {
    77                         AbstractProjection ap = (AbstractProjection) p;
    78                         if (ap.getProj() instanceof LambertConformalConic) {
    79                             for (Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid> pair : ellipsoids) {
    80                                 if (pair.a.equals(geo.getEllipsoid()) && pair.b.equals(ap.getEllipsoid())) {
    81                                     boolean ok = true;
    82                                     ParameterValueGroup values = lambert.getParameterValues();
    83                                     Parameters params = ((LambertConformalConic) ap.getProj()).getParameters();
    84 
    85                                     ok = ok ? equals(get(values, AbstractProvider.LATITUDE_OF_ORIGIN), params.latitudeOrigin) : ok;
    86                                     ok = ok ? equals(get(values, AbstractProvider.CENTRAL_MERIDIAN), ap.getCentralMeridian()) : ok;
    87                                     ok = ok ? equals(get(values, AbstractProvider.SCALE_FACTOR), ap.getScaleFactor()) : ok;
    88                                     ok = ok ? equals(get(values, AbstractProvider.FALSE_EASTING), ap.getFalseEasting()) : ok;
    89                                     ok = ok ? equals(get(values, AbstractProvider.FALSE_NORTHING), ap.getFalseNorthing()) : ok;
    90 
    91                                     if (lambert instanceof LambertConformal2SP && params instanceof Parameters2SP) {
    92                                         Parameters2SP param = (Parameters2SP) params;
    93                                         ok = ok ? equals(Math.min(get(values, AbstractProvider.STANDARD_PARALLEL_1),
    94                                                 get(values, AbstractProvider.STANDARD_PARALLEL_2)),
    95                                                 Math.min(param.standardParallel1, param.standardParallel2)) : ok;
    96                                         ok = ok ? equals(Math.max(get(values, AbstractProvider.STANDARD_PARALLEL_1),
    97                                                 get(values, AbstractProvider.STANDARD_PARALLEL_2)),
    98                                                 Math.max(param.standardParallel1, param.standardParallel2)) : ok;
    99 
    100                                     } else if (!(lambert instanceof LambertConformal1SP && params instanceof Parameters1SP)) {
    101                                         ok = false;
    102                                     }
    103 
    104                                     if (ok) {
    105                                         try {
    106                                             result.add(CRS.findMathTransform(CRS.decode(p.toCode()), targetCRS, lenient));
    107                                         } catch (FactoryException e) {
    108                                             Logging.error(e.getMessage());
    109                                         }
    110                                     }
    111                                 }
    112                             }
    113                         }
    114                     }
    115                 }
    116             }
    117             if (!result.isEmpty()) {
    118                 if (result.size() > 1) {
    119                     Logging.warn("Found multiple projections !"); // TODO: something
    120                 }
    121                 return result.get(0);
    122             }
    123         }
    124         return null;
    125     }
     15    private Charset dbfCharset;
    12616
    12717    @Override
    12818    public void notifyFeatureParsed(Object feature, DataSet result, Set<OsmPrimitive> featurePrimitives) {
    129         // To be overriden by modules handlers
     19        // To be overridden by modules handlers
    13020    }
    13121
    13222    @Override
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java
    a b  
    7171import org.openstreetmap.josm.tools.Utils;
    7272
    7373/**
    74  * Superclass of geographic format readers (currently GML and SHP).
     74 * Superclass of geographic format readers (currently GML, GPKG, and SHP).
    7575 */
    7676public abstract class GeographicReader extends AbstractReader {
    7777
     
    107107        return null;
    108108    }
    109109
     110    public GeographicHandler getHandler() {
     111        return this.handler;
     112    }
     113
    110114    protected Node getNode(Point p, LatLon key) {
    111115        Node n = nodes.get(key);
    112116        if (n == null && handler != null && handler.checkNodeProximity()) {
     
    343347        return esriWkid.get(wkid);
    344348    }
    345349
     350    /**
     351     * Find the math transform for the CRS used by this reader
     352     * @param parent The parent component, used for showing dialogs
     353     * @param findSimiliarCrs {@code true} if we don't need to find the exact CRS
     354     * @throws FactoryException See {@link CRS#findMathTransform}, {@link org.opengis.referencing.AuthorityFactory#getAuthorityCodes}
     355     * @throws UserCancelException If the user cancelled in one of the message dialogs
     356     * @throws GeoMathTransformException If no transform could be found
     357     */
    346358    protected void findMathTransform(Component parent, boolean findSimiliarCrs)
    347359            throws FactoryException, UserCancelException, GeoMathTransformException {
    348360        try {
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/DefaultGeoPackageHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/DefaultGeoPackageHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/DefaultGeoPackageHandler.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage;
     3
     4import org.openstreetmap.josm.plugins.opendata.core.io.geographic.DefaultGeographicHandler;
     5import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeotoolsHandler;
     6
     7/**
     8 * The default handler for GeoPackages
     9 * @author Taylor Smock
     10 */
     11public class DefaultGeoPackageHandler extends DefaultGeographicHandler implements GeoPackageHandler, GeotoolsHandler {
     12    private boolean preferMultipolygonToSimpleWay;
     13    private boolean checkNodeProximity;
     14    private boolean useNodeMap;
     15    @Override
     16    public void setPreferMultipolygonToSimpleWay(boolean prefer) {
     17        this.preferMultipolygonToSimpleWay = prefer;
     18    }
     19
     20    @Override
     21    public boolean preferMultipolygonToSimpleWay() {
     22        return this.preferMultipolygonToSimpleWay;
     23    }
     24
     25    @Override
     26    public void setCheckNodeProximity(boolean check) {
     27        this.checkNodeProximity = check;
     28    }
     29
     30    @Override
     31    public boolean checkNodeProximity() {
     32        return this.checkNodeProximity;
     33    }
     34
     35    @Override
     36    public void setUseNodeMap(boolean use) {
     37        this.useNodeMap = use;
     38    }
     39
     40    @Override
     41    public boolean useNodeMap() {
     42        return this.useNodeMap;
     43    }
     44}
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageHandler.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage;
     3
     4import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeographicHandler;
     5
     6public interface GeoPackageHandler extends GeographicHandler {
     7}
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageImporter.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageImporter.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageImporter.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.io.IOException;
     7import java.io.InputStream;
     8
     9import org.openstreetmap.josm.actions.ExtensionFileFilter;
     10import org.openstreetmap.josm.data.osm.DataSet;
     11import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     12import org.openstreetmap.josm.io.IllegalDataException;
     13import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
     14import org.openstreetmap.josm.plugins.opendata.core.io.AbstractImporter;
     15
     16public class GeoPackageImporter extends AbstractImporter {
     17    public static final ExtensionFileFilter GEOPACKAGE_FILE_FILTER = new ExtensionFileFilter(
     18            OdConstants.GEOPACKAGE_EXT, OdConstants.GEOPACKAGE_EXT, tr("Shapefiles") + " (*."+ OdConstants.GEOPACKAGE_EXT+")");
     19    public GeoPackageImporter() {
     20        super(GEOPACKAGE_FILE_FILTER);
     21    }
     22
     23    @Override
     24    protected DataSet parseDataSet(InputStream in, ProgressMonitor progressMonitor) throws IllegalDataException {
     25        try {
     26            return GeoPackageReader.parseDataSet(in, file, handler, progressMonitor);
     27        } catch (IOException e) {
     28            throw new IllegalDataException(e);
     29        }
     30    }
     31}
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageReader.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageReader.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/geopackage/GeoPackageReader.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage;
     3
     4
     5import java.io.File;
     6import java.io.IOException;
     7import java.io.InputStream;
     8import java.io.Serializable;
     9import java.util.HashMap;
     10import java.util.Map;
     11
     12import org.geotools.data.DataStore;
     13import org.geotools.data.DataStoreFinder;
     14import org.geotools.geopkg.GeoPkgDataStoreFactory;
     15import org.opengis.referencing.FactoryException;
     16import org.opengis.referencing.operation.TransformException;
     17import org.openstreetmap.josm.data.osm.DataSet;
     18import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     19import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
     20import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeoCrsException;
     21import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeoMathTransformException;
     22import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeographicReader;
     23import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeotoolsConverter;
     24
     25/**
     26 * Read a geopackage file
     27 * @author Taylor Smock
     28 */
     29public final class GeoPackageReader extends GeographicReader {
     30    /**
     31     * Parse the dataset
     32     * @param in The {@link InputStream} to read (we actually close it and use the file instead)
     33     * @param file The originating file
     34     * @param handler The handler to use, may be {@code null}
     35     * @param instance The {@link ProgressMonitor} instance to update
     36     * @return The parsed dataset
     37     * @throws IOException If something prevented us from parsing the dataset
     38     */
     39    public static DataSet parseDataSet(InputStream in, File file,
     40                                       AbstractDataSetHandler handler, ProgressMonitor instance) throws IOException {
     41        if (in != null) {
     42            in.close();
     43        }
     44        return new GeoPackageReader(handler != null ? handler.getGeoPackageHandler() : null).parse(file, instance);
     45    }
     46
     47    private GeoPackageReader(GeoPackageHandler handler) {
     48        super(handler, new GeoPackageHandler[0]);
     49    }
     50
     51    private DataSet parse(File file, ProgressMonitor instance) throws IOException {
     52        if (file != null) {
     53            Map<String, Serializable> params = new HashMap<>();
     54            params.put(GeoPkgDataStoreFactory.DATABASE.key, file);
     55            params.put(GeoPkgDataStoreFactory.READ_ONLY.key, true);
     56            params.put(GeoPkgDataStoreFactory.DBTYPE.key, (String) GeoPkgDataStoreFactory.DBTYPE.sample);
     57            DataStore dataStore = DataStoreFinder.getDataStore(params);
     58            try {
     59                new GeotoolsConverter(this, dataStore).convert(instance);
     60            } catch (FactoryException | GeoCrsException | GeoMathTransformException | TransformException e) {
     61                throw new IOException(e);
     62            }
     63        }
     64        return ds;
     65    }
     66}
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsConverter.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsConverter.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsConverter.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic;
     3
     4import static org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeographicReader.wgs84;
     5import static org.openstreetmap.josm.tools.I18n.tr;
     6
     7import java.awt.Component;
     8import java.awt.GraphicsEnvironment;
     9import java.io.IOException;
     10import java.text.SimpleDateFormat;
     11import java.util.Collection;
     12import java.util.Date;
     13import java.util.HashSet;
     14import java.util.LinkedHashMap;
     15import java.util.Map;
     16import java.util.Set;
     17
     18import javax.swing.JOptionPane;
     19
     20import org.geotools.data.DataStore;
     21import org.geotools.data.FeatureSource;
     22import org.geotools.feature.FeatureCollection;
     23import org.geotools.feature.FeatureIterator;
     24import org.locationtech.jts.geom.Geometry;
     25import org.locationtech.jts.geom.GeometryCollection;
     26import org.locationtech.jts.geom.LineString;
     27import org.locationtech.jts.geom.Point;
     28import org.locationtech.jts.geom.Polygon;
     29import org.opengis.feature.Feature;
     30import org.opengis.feature.GeometryAttribute;
     31import org.opengis.feature.Property;
     32import org.opengis.feature.type.GeometryDescriptor;
     33import org.opengis.feature.type.Name;
     34import org.opengis.geometry.MismatchedDimensionException;
     35import org.opengis.referencing.FactoryException;
     36import org.opengis.referencing.operation.TransformException;
     37import org.openstreetmap.josm.data.osm.DataSet;
     38import org.openstreetmap.josm.data.osm.OsmPrimitive;
     39import org.openstreetmap.josm.data.osm.Relation;
     40import org.openstreetmap.josm.data.osm.Way;
     41import org.openstreetmap.josm.gui.MainApplication;
     42import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     43import org.openstreetmap.josm.gui.util.GuiHelper;
     44import org.openstreetmap.josm.tools.Logging;
     45import org.openstreetmap.josm.tools.UserCancelException;
     46
     47/**
     48 * Convert a {@link DataStore} to a {@link DataSet}
     49 */
     50public class GeotoolsConverter {
     51    private final DataStore dataStore;
     52    private final GeographicReader reader;
     53    private final Set<OsmPrimitive> featurePrimitives = new HashSet<>();
     54
     55    /**
     56     * Create a new converter
     57     * @param reader The reader which should have a dataset
     58     * @param original The original data store
     59     */
     60    public GeotoolsConverter(GeographicReader reader, DataStore original) {
     61        this.dataStore = original;
     62        this.reader = reader;
     63    }
     64
     65    /**
     66     * Run the actual conversion process
     67     * @param progressMonitor The monitor to show progress on
     68     * @throws IOException If something could not be read
     69     * @throws FactoryException See {@link GeographicReader#findMathTransform(Component, boolean)}
     70     * @throws GeoMathTransformException See {@link GeographicReader#findMathTransform(Component, boolean)}
     71     * @throws TransformException See {@link GeographicReader#createOrGetNode(Point)}
     72     * @throws GeoCrsException If the CRS cannot be detected
     73     */
     74    public void convert(ProgressMonitor progressMonitor)
     75            throws IOException, FactoryException, GeoMathTransformException, TransformException, GeoCrsException {
     76        String[] typeNames = dataStore.getTypeNames();
     77        String typeName = typeNames[0];
     78
     79        FeatureSource<?, ?> featureSource = dataStore.getFeatureSource(typeName);
     80        FeatureCollection<?, ?> collection = featureSource.getFeatures();
     81
     82        if (progressMonitor != null) {
     83            progressMonitor.beginTask(tr("Loading shapefile ({0} features)", collection.size()), collection.size());
     84        }
     85
     86        int n = 0;
     87
     88        Component parent = progressMonitor != null ? progressMonitor.getWindowParent() : MainApplication.getMainFrame();
     89
     90        int size = collection.size();
     91        this.reader.getDataSet().beginUpdate();
     92        try (FeatureIterator<?> iterator = collection.features()) {
     93            while (iterator.hasNext()) {
     94                n++;
     95                try {
     96                    Feature feature = iterator.next();
     97                    parseFeature(feature, parent);
     98                    if (reader.getHandler() instanceof ShpHandler) {
     99                        ((ShpHandler) reader.getHandler()).notifyFeatureParsed(feature, reader.getDataSet(), featurePrimitives);
     100                    }
     101                } catch (UserCancelException e) {
     102                    Logging.error(e);
     103                    return;
     104                }
     105                if (progressMonitor != null) {
     106                    progressMonitor.worked(1);
     107                    progressMonitor.setCustomText(n+"/"+size);
     108                    if (progressMonitor.isCanceled()) {
     109                        return;
     110                    }
     111                }
     112            }
     113        } finally {
     114            reader.nodes.clear();
     115            this.reader.getDataSet().endUpdate();
     116            if (progressMonitor != null) {
     117                progressMonitor.setCustomText(null);
     118            }
     119        }
     120    }
     121
     122    private void parseFeature(Feature feature, final Component parent) throws UserCancelException, GeoMathTransformException,
     123            FactoryException, GeoCrsException, MismatchedDimensionException, TransformException {
     124        featurePrimitives.clear();
     125        GeometryAttribute geometry = feature.getDefaultGeometryProperty();
     126        if (geometry != null) {
     127
     128            GeometryDescriptor desc = geometry.getDescriptor();
     129            if (reader.crs == null) {
     130                if (desc != null && desc.getCoordinateReferenceSystem() != null) {
     131                    reader.crs = desc.getCoordinateReferenceSystem();
     132                } else if (!GraphicsEnvironment.isHeadless()) {
     133                    GuiHelper.runInEDTAndWait(() -> {
     134                        if (0 == JOptionPane.showConfirmDialog(
     135                                parent,
     136                                tr("Unable to detect Coordinate Reference System.\nWould you like to fallback to ESPG:4326 (WGS 84) ?"),
     137                                tr("Warning: CRS not found"),
     138                                JOptionPane.YES_NO_CANCEL_OPTION
     139                        )) {
     140                            reader.crs = wgs84;
     141                        }
     142                    });
     143                } else {
     144                    // Always use WGS84 in headless mode (used for unit tests only)
     145                    reader.crs = wgs84;
     146                }
     147                if (reader.crs != null) {
     148                    reader.findMathTransform(parent, true);
     149                } else {
     150                    throw new GeoCrsException(tr("Unable to detect CRS !"));
     151                }
     152            }
     153
     154            Object geomObject = geometry.getValue();
     155            if (geomObject instanceof Point) {  // TODO: Support LineString and Polygon.
     156                // Sure you could have a Set of 1 object and join these 2 branches of
     157                // code, but I feel there would be a performance hit.
     158                OsmPrimitive primitive = reader.createOrGetEmptyNode((Point) geomObject);
     159                readNonGeometricAttributes(feature, primitive);
     160            } else if (geomObject instanceof GeometryCollection) { // Deals with both MultiLineString and MultiPolygon
     161                Set<OsmPrimitive> primitives = processGeometryCollection((GeometryCollection) geomObject);
     162                for (OsmPrimitive prim : primitives) {
     163                    readNonGeometricAttributes(feature, prim);
     164                }
     165            } else {
     166                // Debug unknown geometry
     167                Logging.debug("\ttype: "+geometry.getType());
     168                Logging.debug("\tbounds: "+geometry.getBounds());
     169                Logging.debug("\tdescriptor: "+desc);
     170                Logging.debug("\tname: "+geometry.getName());
     171                Logging.debug("\tvalue: "+geomObject);
     172                Logging.debug("\tid: "+geometry.getIdentifier());
     173                Logging.debug("-------------------------------------------------------------");
     174            }
     175        }
     176    }
     177
     178    protected Set<OsmPrimitive> processGeometryCollection(GeometryCollection gc) throws TransformException {
     179        // A feture may be a collection.  This set holds the items of the collection.
     180        Set<OsmPrimitive> primitives = new HashSet<>();
     181        int nGeometries = gc.getNumGeometries();
     182        if (nGeometries < 1) {
     183            Logging.error("empty geometry collection found");
     184        } else {
     185            // Create the primitive "op" and add it to the set of primitives.
     186            for (int i = 0; i < nGeometries; i++) {
     187                OsmPrimitive op = null;
     188                Geometry g = gc.getGeometryN(i);
     189                if (g instanceof Polygon) {
     190                    // TODO: Split this section between Polygon and MultiPolygon.
     191                    Relation r = (Relation) op;
     192                    Polygon p = (Polygon) g;
     193                    // Do not create relation if there's only one polygon without interior ring
     194                    // except if handler prefers it
     195                    if (r == null && (nGeometries > 1 || p.getNumInteriorRing() > 0 ||
     196                            (reader.getHandler() != null && reader.getHandler().preferMultipolygonToSimpleWay()))) {
     197                        r = reader.createMultipolygon();
     198                    }
     199                    Way w = reader.createOrGetWay(p.getExteriorRing());
     200                    if (r != null) {
     201                        reader.addWayToMp(r, "outer", w);
     202                        for (int j = 0; j < p.getNumInteriorRing(); j++) {
     203                            reader.addWayToMp(r, "inner", reader.createOrGetWay(p.getInteriorRingN(j)));
     204                        }
     205                    }
     206                    op = r != null ? r : w;
     207                } else if (g instanceof LineString) {
     208                    op = reader.createOrGetWay((LineString) g);
     209                } else if (g instanceof Point) {
     210                    op = reader.createOrGetNode((Point) g);
     211                } else {
     212                    Logging.error("unsupported geometry : "+g);
     213                }
     214                if (op != null) {
     215                    primitives.add(op);
     216                }
     217            }
     218        }
     219        return primitives;
     220    }
     221
     222    private static void readNonGeometricAttributes(Feature feature, OsmPrimitive primitive) {
     223        try {
     224            Collection<Property> properties = feature.getProperties();
     225            Map<String, String> tagMap = new LinkedHashMap<>(properties.size());
     226            for (Property prop : properties) {
     227                if (!(prop instanceof GeometryAttribute)) {
     228                    Name name = prop.getName();
     229                    Object value = prop.getValue();
     230                    if (name != null && value != null) {
     231                        String sName = name.toString();
     232                        String sValue = value.toString();
     233                        if (value instanceof Date) {
     234                            sValue = new SimpleDateFormat("yyyy-MM-dd").format(value);
     235                        }
     236                        if (!sName.isEmpty() && !sValue.isEmpty()) {
     237                            tagMap.put(sName, sValue);
     238                            //primitive.put(sName, sValue);
     239                        }
     240                    }
     241                }
     242            }
     243            primitive.putAll(tagMap);
     244        } catch (Exception e) {
     245            Logging.error(e);
     246        }
     247    }
     248}
  • new file plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsHandler.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsHandler.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeotoolsHandler.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.opendata.core.io.geographic;
     3
     4import java.util.ArrayList;
     5import java.util.Arrays;
     6import java.util.Collections;
     7import java.util.List;
     8
     9import org.geotools.referencing.CRS;
     10import org.geotools.referencing.crs.AbstractDerivedCRS;
     11import org.geotools.referencing.datum.DefaultEllipsoid;
     12import org.geotools.referencing.operation.projection.LambertConformal;
     13import org.geotools.referencing.operation.projection.LambertConformal1SP;
     14import org.geotools.referencing.operation.projection.LambertConformal2SP;
     15import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
     16import org.opengis.parameter.ParameterDescriptor;
     17import org.opengis.parameter.ParameterValueGroup;
     18import org.opengis.referencing.FactoryException;
     19import org.opengis.referencing.crs.CoordinateReferenceSystem;
     20import org.opengis.referencing.datum.GeodeticDatum;
     21import org.opengis.referencing.operation.MathTransform;
     22import org.openstreetmap.josm.data.projection.AbstractProjection;
     23import org.openstreetmap.josm.data.projection.Ellipsoid;
     24import org.openstreetmap.josm.data.projection.Projection;
     25import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
     26import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters1SP;
     27import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters2SP;
     28import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
     29import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
     30import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
     31import org.openstreetmap.josm.spi.preferences.Config;
     32import org.openstreetmap.josm.tools.Logging;
     33import org.openstreetmap.josm.tools.Pair;
     34
     35/**
     36 * A common handler for geotools
     37 */
     38public interface GeotoolsHandler extends GeographicHandler {
     39    /**
     40     * A mapping of GeoTools ellipsoid to JOSM ellipsoids. Don't use outside the {@link GeotoolsHandler} class.
     41     */
     42    List<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>>
     43            ellipsoids = Collections.unmodifiableList(Arrays.asList(
     44            new Pair<>(DefaultEllipsoid.GRS80, Ellipsoid.GRS80),
     45            new Pair<>(DefaultEllipsoid.WGS84, Ellipsoid.WGS84)
     46    ));
     47
     48    @Override
     49    default MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
     50            throws FactoryException {
     51        if (getCrsFor(sourceCRS.getName().getCode()) != null) {
     52            return CRS.findMathTransform(getCrsFor(sourceCRS.getName().getCode()), targetCRS, lenient);
     53        } else if (sourceCRS instanceof AbstractDerivedCRS && sourceCRS.getName().getCode().equalsIgnoreCase("Lambert_Conformal_Conic")) {
     54            List<MathTransform> result = new ArrayList<>();
     55            AbstractDerivedCRS crs = (AbstractDerivedCRS) sourceCRS;
     56            MathTransform transform = crs.getConversionFromBase().getMathTransform();
     57            if (transform instanceof LambertConformal && crs.getDatum() instanceof GeodeticDatum) {
     58                LambertConformal lambert = (LambertConformal) transform;
     59                GeodeticDatum geo = (GeodeticDatum) crs.getDatum();
     60                for (ProjectionChoice choice : ProjectionPreference.getProjectionChoices()) {
     61                    Projection p = choice.getProjection();
     62                    if (p instanceof AbstractProjection) {
     63                        AbstractProjection ap = (AbstractProjection) p;
     64                        if (ap.getProj() instanceof LambertConformalConic) {
     65                            for (Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid> pair : ellipsoids) {
     66                                if (pair.a.equals(geo.getEllipsoid()) && pair.b.equals(ap.getEllipsoid())) {
     67                                    boolean ok = true;
     68                                    ParameterValueGroup values = lambert.getParameterValues();
     69                                    LambertConformalConic.Parameters params = ((LambertConformalConic) ap.getProj()).getParameters();
     70
     71                                    ok = ok ? equals(get(values, AbstractProvider.LATITUDE_OF_ORIGIN), params.latitudeOrigin) : ok;
     72                                    ok = ok ? equals(get(values, AbstractProvider.CENTRAL_MERIDIAN), ap.getCentralMeridian()) : ok;
     73                                    ok = ok ? equals(get(values, AbstractProvider.SCALE_FACTOR), ap.getScaleFactor()) : ok;
     74                                    ok = ok ? equals(get(values, AbstractProvider.FALSE_EASTING), ap.getFalseEasting()) : ok;
     75                                    ok = ok ? equals(get(values, AbstractProvider.FALSE_NORTHING), ap.getFalseNorthing()) : ok;
     76
     77                                    if (lambert instanceof LambertConformal2SP && params instanceof Parameters2SP) {
     78                                        Parameters2SP param = (Parameters2SP) params;
     79                                        ok = ok ? equals(Math.min(get(values, AbstractProvider.STANDARD_PARALLEL_1),
     80                                                        get(values, AbstractProvider.STANDARD_PARALLEL_2)),
     81                                                Math.min(param.standardParallel1, param.standardParallel2)) : ok;
     82                                        ok = ok ? equals(Math.max(get(values, AbstractProvider.STANDARD_PARALLEL_1),
     83                                                        get(values, AbstractProvider.STANDARD_PARALLEL_2)),
     84                                                Math.max(param.standardParallel1, param.standardParallel2)) : ok;
     85
     86                                    } else if (!(lambert instanceof LambertConformal1SP && params instanceof Parameters1SP)) {
     87                                        ok = false;
     88                                    }
     89
     90                                    if (ok) {
     91                                        try {
     92                                            result.add(CRS.findMathTransform(CRS.decode(p.toCode()), targetCRS, lenient));
     93                                        } catch (FactoryException e) {
     94                                            Logging.error(e.getMessage());
     95                                        }
     96                                    }
     97                                }
     98                            }
     99                        }
     100                    }
     101                }
     102            }
     103            if (!result.isEmpty()) {
     104                if (result.size() > 1) {
     105                    Logging.warn("Found multiple projections !"); // TODO: something
     106                }
     107                return result.get(0);
     108            }
     109        }
     110        return null;
     111    }
     112
     113    /**
     114     * Get a value from a group of values
     115     * @param values The values to look at
     116     * @param desc The description of the value to get
     117     * @return The value
     118     */
     119    static Double get(ParameterValueGroup values, ParameterDescriptor<?> desc) {
     120        return (Double) values.parameter(desc.getName().getCode()).getValue();
     121    }
     122
     123    /**
     124     * Check if two doubles are equal to within the {@link OdConstants#PREF_CRS_COMPARISON_TOLERANCE}
     125     * @param a The first double
     126     * @param b The second double
     127     * @return {@code true} if the difference is less than the tolerance
     128     */
     129    static boolean equals(Double a, Double b) {
     130        boolean res = Math.abs(a - b) <= Config.getPref().getDouble(
     131                OdConstants.PREF_CRS_COMPARISON_TOLERANCE, OdConstants.DEFAULT_CRS_COMPARISON_TOLERANCE);
     132        if (Config.getPref().getBoolean(OdConstants.PREF_CRS_COMPARISON_DEBUG, false)) {
     133            Logging.debug("Comparing "+a+" and "+b+" -> "+res);
     134        }
     135        return res;
     136    }
     137}
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java
    a b  
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Component;
    7 import java.awt.GraphicsEnvironment;
    86import java.io.BufferedReader;
    97import java.io.File;
    108import java.io.IOException;
     
    1614import java.nio.charset.UnsupportedCharsetException;
    1715import java.nio.file.Files;
    1816import java.nio.file.Path;
    19 import java.text.SimpleDateFormat;
    2017import java.util.Arrays;
    21 import java.util.Date;
    2218import java.util.HashMap;
    2319import java.util.HashSet;
    2420import java.util.Map;
    2521import java.util.Set;
    2622
    27 import javax.swing.JOptionPane;
    28 
    2923import org.geotools.data.DataStore;
    30 import org.geotools.data.FeatureSource;
    3124import org.geotools.data.shapefile.ShapefileDataStoreFactory;
    32 import org.geotools.feature.FeatureCollection;
    33 import org.geotools.feature.FeatureIterator;
    34 import org.locationtech.jts.geom.Geometry;
    35 import org.locationtech.jts.geom.GeometryCollection;
    36 import org.locationtech.jts.geom.LineString;
    3725import org.locationtech.jts.geom.Point;
    38 import org.locationtech.jts.geom.Polygon;
    39 import org.opengis.feature.Feature;
    40 import org.opengis.feature.GeometryAttribute;
    41 import org.opengis.feature.Property;
    42 import org.opengis.feature.type.GeometryDescriptor;
    43 import org.opengis.feature.type.Name;
    4426import org.opengis.geometry.MismatchedDimensionException;
    45 import org.opengis.referencing.FactoryException;
    4627import org.opengis.referencing.operation.TransformException;
    4728import org.openstreetmap.josm.data.osm.DataSet;
    4829import org.openstreetmap.josm.data.osm.Node;
    4930import org.openstreetmap.josm.data.osm.OsmPrimitive;
    50 import org.openstreetmap.josm.data.osm.Relation;
    51 import org.openstreetmap.josm.data.osm.Way;
    52 import org.openstreetmap.josm.gui.MainApplication;
    5331import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    54 import org.openstreetmap.josm.gui.util.GuiHelper;
    5532import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
    5633import org.openstreetmap.josm.plugins.opendata.core.datasets.NationalHandlers;
    5734import org.openstreetmap.josm.tools.Logging;
    58 import org.openstreetmap.josm.tools.UserCancelException;
    5935
    6036/**
    6137 * Reader of SHP (Shapefile) files.
     
    8460        }
    8561    }
    8662
    87     private void parseFeature(Feature feature, final Component parent) throws UserCancelException, GeoMathTransformException,
    88     FactoryException, GeoCrsException, MismatchedDimensionException, TransformException {
    89         featurePrimitives.clear();
    90         GeometryAttribute geometry = feature.getDefaultGeometryProperty();
    91         if (geometry != null) {
    92 
    93             GeometryDescriptor desc = geometry.getDescriptor();
    94 
    95             if (crs == null) {
    96                 if (desc != null && desc.getCoordinateReferenceSystem() != null) {
    97                     crs = desc.getCoordinateReferenceSystem();
    98                 } else if (!GraphicsEnvironment.isHeadless()) {
    99                     GuiHelper.runInEDTAndWait(() -> {
    100                         if (0 == JOptionPane.showConfirmDialog(
    101                                 parent,
    102                                 tr("Unable to detect Coordinate Reference System.\nWould you like to fallback to ESPG:4326 (WGS 84) ?"),
    103                                 tr("Warning: CRS not found"),
    104                                 JOptionPane.YES_NO_CANCEL_OPTION
    105                                 )) {
    106                             crs = wgs84;
    107                         }
    108                     });
    109                 } else {
    110                     // Always use WGS84 in headless mode (used for unit tests only)
    111                     crs = wgs84;
    112                 }
    113                 if (crs != null) {
    114                     findMathTransform(parent, true);
    115                 } else {
    116                     throw new GeoCrsException(tr("Unable to detect CRS !"));
    117                 }
    118             }
    119 
    120             Object geomObject = geometry.getValue();
    121             if (geomObject instanceof Point) {  // TODO: Support LineString and Polygon.
    122                 // Sure you could have a Set of 1 object and join these 2 branches of
    123                 // code, but I feel there would be a performance hit.
    124                 OsmPrimitive primitive = createOrGetEmptyNode((Point) geomObject);
    125                 readNonGeometricAttributes(feature, primitive);
    126             } else if (geomObject instanceof GeometryCollection) { // Deals with both MultiLineString and MultiPolygon
    127                 Set<OsmPrimitive> primitives = processGeometryCollection((GeometryCollection) geomObject);
    128                 for (OsmPrimitive prim : primitives) {
    129                     readNonGeometricAttributes(feature, prim);
    130                 }
    131             } else {
    132                 // Debug unknown geometry
    133                 Logging.debug("\ttype: "+geometry.getType());
    134                 Logging.debug("\tbounds: "+geometry.getBounds());
    135                 Logging.debug("\tdescriptor: "+desc);
    136                 Logging.debug("\tname: "+geometry.getName());
    137                 Logging.debug("\tvalue: "+geomObject);
    138                 Logging.debug("\tid: "+geometry.getIdentifier());
    139                 Logging.debug("-------------------------------------------------------------");
    140             }
    141         }
    142     }
    143 
    144     protected Set<OsmPrimitive> processGeometryCollection(GeometryCollection gc) throws TransformException {
    145         // A feture may be a collection.  This set holds the items of the collection.
    146         Set<OsmPrimitive> primitives = new HashSet<>();
    147         int nGeometries = gc.getNumGeometries();
    148         if (nGeometries < 1) {
    149             Logging.error("empty geometry collection found");
    150         } else {
    151             // Create the primitive "op" and add it to the set of primitives.
    152             for (int i = 0; i < nGeometries; i++) {
    153                 OsmPrimitive op = null;
    154                 Geometry g = gc.getGeometryN(i);
    155                 if (g instanceof Polygon) {
    156                     // TODO: Split this section between Polygon and MultiPolygon.
    157                     Relation r = (Relation) op;
    158                     Polygon p = (Polygon) g;
    159                     // Do not create relation if there's only one polygon without interior ring
    160                     // except if handler prefers it
    161                     if (r == null && (nGeometries > 1 || p.getNumInteriorRing() > 0 ||
    162                             (handler != null && handler.preferMultipolygonToSimpleWay()))) {
    163                         r = createMultipolygon();
    164                     }
    165                     Way w = createOrGetWay(p.getExteriorRing());
    166                     if (r != null) {
    167                         addWayToMp(r, "outer", w);
    168                         for (int j = 0; j < p.getNumInteriorRing(); j++) {
    169                             addWayToMp(r, "inner", createOrGetWay(p.getInteriorRingN(j)));
    170                         }
    171                     }
    172                     op = r != null ? r : w;
    173                 } else if (g instanceof LineString) {
    174                     op = createOrGetWay((LineString) g);
    175                 } else if (g instanceof Point) {
    176                     op = createOrGetNode((Point) g);
    177                 } else {
    178                     Logging.error("unsupported geometry : "+g);
    179                 }
    180                 if (op != null) {
    181                     primitives.add(op);
    182                 }
    183             }
    184         }
    185         return primitives;
    186     }
    187 
    18863    public DataSet parse(File file, ProgressMonitor instance) throws IOException {
    18964        crs = null;
    19065        transform = null;
     
    231106                if (dataStore == null) {
    232107                    throw new IOException(tr("Unable to find a data store for file {0}", file.getName()));
    233108                }
    234 
    235                 String[] typeNames = dataStore.getTypeNames();
    236                 String typeName = typeNames[0];
    237 
    238                 FeatureSource<?, ?> featureSource = dataStore.getFeatureSource(typeName);
    239                 FeatureCollection<?, ?> collection = featureSource.getFeatures();
    240 
    241                 if (instance != null) {
    242                     instance.beginTask(tr("Loading shapefile ({0} features)", collection.size()), collection.size());
    243                 }
    244 
    245                 int n = 0;
    246 
    247                 Component parent = instance != null ? instance.getWindowParent() : MainApplication.getMainFrame();
    248 
    249                 try (FeatureIterator<?> iterator = collection.features()) {
    250                     while (iterator.hasNext()) {
    251                         n++;
    252                         try {
    253                             Feature feature = iterator.next();
    254                             parseFeature(feature, parent);
    255                             if (handler != null) {
    256                                 handler.notifyFeatureParsed(feature, ds, featurePrimitives);
    257                             }
    258                         } catch (UserCancelException e) {
    259                             e.printStackTrace();
    260                             return ds;
    261                         }
    262                         if (instance != null) {
    263                             instance.worked(1);
    264                             instance.setCustomText(n+"/"+collection.size());
    265                         }
    266                     }
    267                 } finally {
    268                     nodes.clear();
    269                     if (instance != null) {
    270                         instance.setCustomText(null);
    271                     }
    272                 }
     109                new GeotoolsConverter(this, dataStore).convert(instance);
    273110            }
    274111        } catch (IOException e) {
    275112            Logging.error(e);
     
    281118        return ds;
    282119    }
    283120
    284     private static void readNonGeometricAttributes(Feature feature, OsmPrimitive primitive) {
    285         try {
    286             for (Property prop : feature.getProperties()) {
    287                 if (!(prop instanceof GeometryAttribute)) {
    288                     Name name = prop.getName();
    289                     Object value = prop.getValue();
    290                     if (name != null && value != null) {
    291                         String sName = name.toString();
    292                         String sValue = value.toString();
    293                         if (value instanceof Date) {
    294                             sValue = new SimpleDateFormat("yyyy-MM-dd").format(value);
    295                         }
    296                         if (!sName.isEmpty() && !sValue.isEmpty()) {
    297                             primitive.put(sName, sValue);
    298                         }
    299                     }
    300                 }
    301             }
    302         } catch (Exception e) {
    303             Logging.error(e);
    304         }
    305     }
    306 
    307121    @Override
    308122    protected Node createOrGetNode(Point p) throws MismatchedDimensionException, TransformException {
    309123        Node n = super.createOrGetNode(p);
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java
    a b  
    9191    public static final String XML_EXT = "xml";
    9292    public static final String JSON_EXT = "json";
    9393    public static final String GEOJSON_EXT = "geojson";
     94    public static final String GEOPACKAGE_EXT = "gpkg";
    9495
    9596    /**
    9697     * Protocols
  • plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java b/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java
    a b  
    4040import org.openstreetmap.josm.plugins.opendata.core.io.geographic.KmlKmzImporter;
    4141import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifTabImporter;
    4242import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpImporter;
     43import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.GeoPackageImporter;
    4344import org.openstreetmap.josm.plugins.opendata.core.io.session.OpenDataSessionExporter;
    4445import org.openstreetmap.josm.plugins.opendata.core.io.session.OpenDataSessionImporter;
    4546import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvImporter;
     
    6667
    6768    private OdDialog dialog;
    6869
    69     public final List<AbstractImporter> importers = Arrays.asList(new AbstractImporter[] {
    70             new CsvImporter(), new OdsImporter(), new XlsImporter(), // Tabular file formats
    71             new KmlKmzImporter(), new ShpImporter(), new MifTabImporter(), new GmlImporter(), // Geographic file formats
    72             new ZipImporter(), // Zip archive containing any of the others
    73             new SevenZipImporter(), // 7Zip archive containing any of the others
    74             xmlImporter // Generic importer for XML files (currently used for Neptune files)
    75     });
     70    /**
     71     * The importers that will get registered for use by file import
     72     */
     73    public final List<AbstractImporter> importers = Arrays.asList(
     74            // Tabular file formats
     75            new CsvImporter(), new OdsImporter(), new XlsImporter(),
     76            // Geographic file formats
     77            new KmlKmzImporter(), new ShpImporter(), new MifTabImporter(), new GeoPackageImporter(), new GmlImporter(),
     78            // Zip archive containing any of the others
     79            new ZipImporter(),
     80            // 7Zip archive containing any of the others
     81            new SevenZipImporter(),
     82            // Generic importer for XML files (currently used for Neptune files)
     83            xmlImporter
     84    );
    7685
    7786    public OdPlugin(PluginInformation info) {
    7887        super(info);