All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nikolaybespalov.gtozi.OziMapFileReader Maven / Gradle / Ivy

Go to download

GeoTools plugin that allows you to read OziExplorer spatial reference file(.MAP) without using GDAL/OziApi or any other environment dependencies.

There is a newer version: 0.1.17
Show newest version
package com.github.nikolaybespalov.gtozi;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.geotools.data.DataSourceException;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.CRS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.cs.DefaultCartesianCS;
import org.geotools.referencing.cs.DefaultEllipsoidalCS;
import org.geotools.referencing.datum.BursaWolfParameters;
import org.geotools.referencing.datum.DefaultEllipsoid;
import org.geotools.referencing.datum.DefaultGeodeticDatum;
import org.geotools.referencing.datum.DefaultPrimeMeridian;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.geotools.referencing.operation.DefiningConversion;
import org.geotools.referencing.operation.projection.MapProjection;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.referencing.operation.transform.ConcatenatedTransform;
import org.opengis.geometry.DirectPosition;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchIdentifierException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.datum.DatumFactory;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;

import javax.measure.unit.SI;
import java.awt.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.*;
import java.util.List;

@SuppressWarnings("WeakerAccess")
final class OziMapFileReader {
    private static final Map ellips = new HashMap<>();
    private static final Map datums = new HashMap<>();

    static {
        System.setProperty("org.geotools.referencing.forceXY", "true");
    }

    static {
        //
        // Read ozi_datum.csv and ozi_ellips.csv
        //

        try (CSVParser csvParser = new CSVParser(new InputStreamReader(OziMapFileReader.class.getClassLoader().getResourceAsStream("com/github/nikolaybespalov/gtozi/data/ozi_ellips.csv")), CSVFormat.RFC4180.withFirstRecordAsHeader().withCommentMarker('#'))) {
            for (CSVRecord csvRecord : csvParser) {
                String ellipsoidCode = csvRecord.get("ELLIPSOID_CODE");
                String name = csvRecord.get("NAME");
                String a = csvRecord.get("A");
                String invf = csvRecord.get("INVF");

                Ellipsoid ellipsoid = DefaultEllipsoid.createFlattenedSphere(name, NumberUtils.toDouble(a), NumberUtils.toDouble(invf), SI.METER);

                ellips.put(ellipsoidCode, ellipsoid);
            }
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }

        try (CSVParser csvParser = new CSVParser(new InputStreamReader(OziMapFileReader.class.getClassLoader().getResourceAsStream("com/github/nikolaybespalov/gtozi/data/ozi_datum.csv")), CSVFormat.RFC4180.withFirstRecordAsHeader().withCommentMarker('#'))) {
            for (CSVRecord csvRecord : csvParser) {
                String name = csvRecord.get("NAME");
                String epsgDatumCode = csvRecord.get("EPSG_DATUM_CODE");
                String ellipsoidCode = csvRecord.get("ELLIPSOID_CODE");
                String dx = csvRecord.get("DELTAX");
                String dy = csvRecord.get("DELTAY");
                String dz = csvRecord.get("DELTAZ");

                GeodeticDatum datum;

                if (!StringUtils.isEmpty(epsgDatumCode)) {
                    GeographicCRS geoCrs = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null).createGeographicCRS(epsgDatumCode);
                    datum = geoCrs.getDatum();
                } else {
                    Ellipsoid ellipsoid = ellips.get(ellipsoidCode);

                    datum = createGeodeticDatum(name, ellipsoid, NumberUtils.toDouble(dx), NumberUtils.toDouble(dy), NumberUtils.toDouble(dz));
                }

                datums.put(name, datum);
            }
        } catch (IOException | FactoryException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private CoordinateReferenceSystem crs;
    private MathTransform grid2Crs;
    private File imageFile;

    public OziMapFileReader(File file) throws DataSourceException {
        try {
            if (!file.exists()) {
                throw new FileNotFoundException("File " + file.getAbsolutePath() + " does not exist.");
            } else if (file.isDirectory()) {
                throw new IOException("File " + file.getAbsolutePath() + " is a directory.");
            } else if (!file.canRead()) {
                throw new IOException("File " + file.getAbsolutePath() + " can not be read.");
            }

            //
            // Read all lines of the file
            //

            List lines = Files.readAllLines(file.toPath(), Charset.forName("windows-1251"));

            //
            // Parse and validate file header
            //

            String header = parseHeader(lines);

            if (!StringUtils.startsWith(header, "OziExplorer Map Data File")) {
                throw new DataSourceException("File " + file.getAbsolutePath() + " does not a OziExplorer map data file.");
            }

            //
            // Parse and validate image filename
            //

            String imageFilename = parseImageFilename(lines);

            if (StringUtils.isEmpty(imageFilename)) {
                throw new IOException("Map file does not contain an image filename");
            }

            imageFile = new File(imageFilename);

            if (!imageFile.exists()) {
                imageFile = new File(file.getParent(), imageFilename);
            }

            if (!imageFile.exists()) {
                throw new FileNotFoundException("Image file " + imageFile.getAbsolutePath() + " does not exist.");
            } else if (imageFile.isDirectory()) {
                throw new IOException("Image file " + imageFile.getAbsolutePath() + " is a directory.");
            } else if (!imageFile.canRead()) {
                throw new IOException("Image file " + imageFile.getAbsolutePath() + " can not be read.");
            }

            //
            // Parse datum
            //

            GeodeticDatum datum = parseDatum(lines);

            GeographicCRS geoCrs = ReferencingFactoryFinder.getCRSFactory(null).createGeographicCRS(Collections.singletonMap("name", datum.getName().getCode()), datum, DefaultEllipsoidalCS.GEODETIC_2D);

            //
            // Parse projection
            //

            String projectionName = parseMapProjection(lines);

            if ("Albers Equal Area".equals(projectionName)) {
                geoCrs = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null).createGeographicCRS("NAD27");
            }

            crs = parseProjectionSetup(lines, projectionName, geoCrs);

            MathTransform world2Crs = CRS.findMathTransform(geoCrs, crs, true);

            List calibrationPoints = parseCalibrationPoints(lines, world2Crs);

            if (calibrationPoints.size() < 2) {
                throw new IOException("too few calibration points!");
            }

            double xPixelSize;
            double yPixelSize;
            double xULC;
            double yULC;

            if (calibrationPoints.size() == 2) {
                CalibrationPoint cp1 = calibrationPoints.get(calibrationPoints.size() - 1);
                CalibrationPoint cp0 = calibrationPoints.get(0);

                xPixelSize = (cp1.getXy().x - cp0.getXy().x) / (double) (cp1.getPixelLine().x - cp0.getPixelLine().x);
                yPixelSize = (cp1.getXy().y - cp0.getXy().y) / (double) (cp1.getPixelLine().y - cp0.getPixelLine().y);
                xULC = cp0.getXy().x - (double) cp0.getPixelLine().x * xPixelSize;
                yULC = cp0.getXy().y - (double) cp0.getPixelLine().y * yPixelSize;

                grid2Crs = new AffineTransform2D(xPixelSize, 0, 0, yPixelSize, xULC, yULC);
            } else {
                int nGCPCount = calibrationPoints.size();
                //throw new IOException("Too much calibration points (TEMP)");
                CalibrationPoint cp0 = calibrationPoints.get(0);

                double min_pixel = cp0.pixelLine.x;
                double max_pixel = cp0.pixelLine.x;
                double min_line = cp0.pixelLine.y;
                double max_line = cp0.pixelLine.y;
                double min_geox = cp0.xy.x;
                double max_geox = cp0.xy.x;
                double min_geoy = cp0.xy.y;
                double max_geoy = cp0.xy.y;

                for (int i = 1; i < calibrationPoints.size(); ++i) {
                    CalibrationPoint cp = calibrationPoints.get(i);

                    min_pixel = Math.min(min_pixel, cp.pixelLine.x);
                    max_pixel = Math.max(max_pixel, cp.pixelLine.x);
                    min_line = Math.min(min_line, cp.pixelLine.y);
                    max_line = Math.max(max_line, cp.pixelLine.y);
                    min_geox = Math.min(min_geox, cp.xy.x);
                    max_geox = Math.max(max_geox, cp.xy.x);
                    min_geoy = Math.min(min_geoy, cp.xy.y);
                    max_geoy = Math.max(max_geoy, cp.xy.y);
                }

                double EPS = 1.0e-12;

                if (Math.abs(max_pixel - min_pixel) < EPS
                        || Math.abs(max_line - min_line) < EPS
                        || Math.abs(max_geox - min_geox) < EPS
                        || Math.abs(max_geoy - min_geoy) < EPS) {
                    throw new IOException("Degenerate in at least one dimension");
                }

                double pl_normalize[] = new double[6];
                double geo_normalize[] = new double[6];

                pl_normalize[0] = -min_pixel / (max_pixel - min_pixel);
                pl_normalize[1] = 1.0 / (max_pixel - min_pixel);
                pl_normalize[2] = 0.0;
                pl_normalize[3] = -min_line / (max_line - min_line);
                pl_normalize[4] = 0.0;
                pl_normalize[5] = 1.0 / (max_line - min_line);

                AffineTransform2D pl_normalize2 = new AffineTransform2D(pl_normalize[1], pl_normalize[2], pl_normalize[4], pl_normalize[5], pl_normalize[0], pl_normalize[3]);

                geo_normalize[0] = -min_geox / (max_geox - min_geox);
                geo_normalize[1] = 1.0 / (max_geox - min_geox);
                geo_normalize[2] = 0.0;
                geo_normalize[3] = -min_geoy / (max_geoy - min_geoy);
                geo_normalize[4] = 0.0;
                geo_normalize[5] = 1.0 / (max_geoy - min_geoy);

                AffineTransform2D geo_normalize2 = new AffineTransform2D(geo_normalize[1], geo_normalize[2], geo_normalize[4], geo_normalize[5], geo_normalize[0], geo_normalize[3]);


                /* -------------------------------------------------------------------- */
                /* In the general case, do a least squares error approximation by       */
                /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum          */
                /* -------------------------------------------------------------------- */

                double sum_x = 0.0;
                double sum_y = 0.0;
                double sum_xy = 0.0;
                double sum_xx = 0.0;
                double sum_yy = 0.0;
                double sum_Lon = 0.0;
                double sum_Lonx = 0.0;
                double sum_Lony = 0.0;
                double sum_Lat = 0.0;
                double sum_Latx = 0.0;
                double sum_Laty = 0.0;


                for (CalibrationPoint cp : calibrationPoints) {
                    DirectPosition2D pixelLine = new DirectPosition2D();

                    pl_normalize2.transform(cp.pixelLine, pixelLine);

                    double pixel = pixelLine.x;
                    double line = pixelLine.y;

                    DirectPosition2D xy = new DirectPosition2D();

                    geo_normalize2.transform((DirectPosition) cp.xy, xy);

                    double geox = xy.x;
                    double geoy = xy.y;

                    sum_x += pixel;
                    sum_y += line;
                    sum_xy += pixel * line;
                    sum_xx += pixel * pixel;
                    sum_yy += line * line;
                    sum_Lon += geox;
                    sum_Lonx += geox * pixel;
                    sum_Lony += geox * line;
                    sum_Lat += geoy;
                    sum_Latx += geoy * pixel;
                    sum_Laty += geoy * line;
                }

                double divisor =
                        nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy)
                                + 2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx
                                - sum_x * sum_x * sum_yy;

                /* -------------------------------------------------------------------- */
                /*      If the divisor is zero, there is no valid solution.             */
                /* -------------------------------------------------------------------- */
                if (divisor == 0.0) {
                    throw new IOException("Divisor is zero, there is no valid solution");
                }


                /* -------------------------------------------------------------------- */
                /*      Compute top/left origin.                                        */
                /* -------------------------------------------------------------------- */
                double gt_normalized[] = new double[]{0, 0, 0, 0, 0, 0};

                gt_normalized[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy)
                        + sum_Lonx * (sum_y * sum_xy - sum_x * sum_yy)
                        + sum_Lony * (sum_x * sum_xy - sum_y * sum_xx))
                        / divisor;

                gt_normalized[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy)
                        + sum_Latx * (sum_y * sum_xy - sum_x * sum_yy)
                        + sum_Laty * (sum_x * sum_xy - sum_y * sum_xx))
                        / divisor;

                /* -------------------------------------------------------------------- */
                /*      Compute X related coefficients.                                 */
                /* -------------------------------------------------------------------- */
                gt_normalized[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy)
                        + sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y)
                        + sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount))
                        / divisor;

                gt_normalized[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx)
                        + sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy)
                        + sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x))
                        / divisor;

                /* -------------------------------------------------------------------- */
                /*      Compute Y related coefficients.                                 */
                /* -------------------------------------------------------------------- */
                gt_normalized[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy)
                        + sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y)
                        + sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount))
                        / divisor;

                gt_normalized[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx)
                        + sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy)
                        + sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x))
                        / divisor;

                AffineTransform2D gt_normalized2 = new AffineTransform2D(gt_normalized[1], gt_normalized[2], 0, 0, gt_normalized[0], gt_normalized[3]);

                /* -------------------------------------------------------------------- */
                /*      Compose the resulting transformation with the normalization     */
                /*      geotransformations.                                             */
                /* -------------------------------------------------------------------- */
                MathTransform2D inv_geo_normalize2 = geo_normalize2.inverse();
                MathTransform gt1p2 = ConcatenatedTransform.create(pl_normalize2, gt_normalized2);

                grid2Crs = ConcatenatedTransform.create(gt1p2, inv_geo_normalize2);
            }
        } catch (IOException | FactoryException | TransformException e) {
            throw new DataSourceException(e);
        }
    }

    public CoordinateReferenceSystem getCoordinateReferenceSystem() {
        return crs;
    }

    public MathTransform getGrid2Crs() {
        return grid2Crs;
    }

    public File getImageFile() {
        return imageFile;
    }

    private String parseHeader(List lines) throws IOException {
        if (lines.isEmpty()) {
            throw new IOException("Not enough data");
        }

        return lines.get(0);
    }

    private String parseImageFilename(List lines) throws IOException {
        if (lines.size() < 3) {
            throw new IOException("Not enough data");
        }

        return lines.get(2);
    }

    private GeodeticDatum parseDatum(List lines) throws IOException {
        if (lines.size() < 5) {
            throw new IOException("Not enough data");
        }

        String[] values = lineValues(lines.get(4));

        if (values.length == 0) {
            throw new IOException("Not enough data");
        }

        String datumName = values[0];

        GeodeticDatum datum = datums.get(datumName);

        if (datum == null) {
            throw new IOException("Unknown datum: " + datumName);
        }

        return datum;
    }

    private String parseMapProjection(List lines) throws IOException {
        String projectionName = null;

        for (String line : lines) {
            if (StringUtils.startsWith(line, "Map Projection")) {
                String[] values = lineValues(line);

                if (values.length < 2) {
                    throw new IOException("Not enough data");
                }

                projectionName = values[1];
            }
        }

        return projectionName;
    }

    private CoordinateReferenceSystem parseProjectionSetup(List lines, String projectionName, GeographicCRS geoCrs) throws IOException, FactoryException {
        CoordinateReferenceSystem crs;

        //  Parameters:
        //    1. Latitude Origin
        //    2. Longitude Origin
        //    3. K Factor
        //    4. False Easting
        //    5. False Northing
        //    6. Latitude 1
        //    7. Latitude 2
        //    8. Height - used in the Vertical Near-Sided Perspective Projection
        //    9. Sat - not used
        //    10. Path - not used

        if ("Latitude/Longitude".equals(projectionName)) {
            crs = geoCrs;
        } else {
            String[] values = null;

            for (String line : lines) {
                if (StringUtils.startsWith(line, "Projection Setup")) {
                    values = lineValues(line);
                }
            }

            if (values == null) {
                throw new IOException("'Projection Setup' is required");
            }

            Conversion conversion = createConversion(projectionName, values);

            crs = ReferencingFactoryFinder.getCRSFactory(null).createProjectedCRS(Collections.singletonMap("name", "unnamed"), geoCrs, conversion, DefaultCartesianCS.PROJECTED);
        }

        return crs;
    }

    private List parseCalibrationPoints(List lines, MathTransform world2Crs) throws TransformException {
        List calibrationPoints = new ArrayList<>();

        for (String line : lines) {
            if (!StringUtils.startsWith(line, "Point")) {
                continue;
            }

            String[] values = lineValues(line);

            String v0 = values[0];
            String v2 = values.length > 2 ? values[2] : "";
            String v3 = values.length > 3 ? values[3] : "";
            String v6 = values.length > 6 ? values[6] : "";
            String v7 = values.length > 7 ? values[7] : "";
            String v8 = values.length > 8 ? values[8] : "";
            String v9 = values.length > 9 ? values[9] : "";
            String v10 = values.length > 10 ? values[10] : "";
            String v11 = values.length > 11 ? values[11] : "";
            String v14 = values.length > 14 ? values[14] : "";
            String v15 = values.length > 15 ? values[15] : "";

            if (v0.startsWith("Point")) {
                Point pixelLine = null;

                if (NumberUtils.isCreatable(v2) && NumberUtils.isCreatable(v3)) {
                    pixelLine = new Point(NumberUtils.toInt(v2), NumberUtils.toInt(v3));
                }

                DirectPosition2D xy = null;

                if (NumberUtils.isCreatable(v6) && NumberUtils.isCreatable(v7) &&
                        NumberUtils.isCreatable(v9) && NumberUtils.isCreatable(v10)) {
                    DirectPosition2D latLon = new DirectPosition2D(DefaultGeographicCRS.WGS84,
                            NumberUtils.toDouble(v9) + NumberUtils.toDouble(v10) / 60.0,
                            NumberUtils.toDouble(v6) + NumberUtils.toDouble(v7) / 60.0);

                    if ("W".equals(v11)) {
                        latLon.x = -latLon.x;
                    }

                    if ("S".equals(v8)) {
                        latLon.y = -latLon.y;
                    }

                    DirectPosition2D p = new DirectPosition2D(crs);

                    MapProjection.SKIP_SANITY_CHECKS = true;

                    if (world2Crs.transform(latLon, p) != null) {
                        xy = p;
                    }
                } else if (NumberUtils.isCreatable(v14) && NumberUtils.isCreatable(v15)) {
                    xy = new DirectPosition2D(crs, NumberUtils.toDouble(v14), NumberUtils.toDouble(v15));
                }

                if (pixelLine != null && xy != null) {
                    calibrationPoints.add(new CalibrationPoint(pixelLine, xy));
                }
            }
        }

        return calibrationPoints;
    }

    private static GeodeticDatum createGeodeticDatum(String name, Ellipsoid ellipsoid, double dx, double dy, double dz) throws FactoryException {
        Map parameters = new HashMap<>();

        parameters.put("name", name);

        final BursaWolfParameters bursaWolfParameters = new BursaWolfParameters(DefaultGeodeticDatum.WGS84);

        bursaWolfParameters.dx = dx;
        bursaWolfParameters.dy = dy;
        bursaWolfParameters.dz = dz;

        if (!bursaWolfParameters.isIdentity()) {
            parameters.put(DefaultGeodeticDatum.BURSA_WOLF_KEY, bursaWolfParameters);
        }

        DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(null);

        return datumFactory.createGeodeticDatum(parameters, ellipsoid, DefaultPrimeMeridian.GREENWICH);
    }

    private static final class CalibrationPoint {
        private final Point pixelLine;
        private final Point.Double xy;

        public CalibrationPoint(Point pixelLine, Point.Double xy) {
            this.pixelLine = pixelLine;
            this.xy = xy;
        }

        public Point getPixelLine() {
            return pixelLine;
        }

        public Point.Double getXy() {
            return xy;
        }
    }

    private static String[] lineValues(String line) {
        return Arrays.stream(line.split(",", -1)).map(String::trim).toArray(String[]::new);
    }

    // нужно замутить универсальную функцию, которая мапит параметры на геотулс имена
    // http://docs.geotools.org/latest/userguide/library/referencing/transform.html
    private static Conversion createConversion(String projectionName, String[] values) throws IOException, NoSuchIdentifierException {
        Map asd = new HashMap<>();

        asd.put("Mercator", "Mercator_1SP");
        asd.put("Transverse Mercator", "Transverse_Mercator");
        asd.put("Lambert Conformal Conic", "Lambert_Conformal_Conic_2SP");
        asd.put("Sinusoidal", "Sinusoidal");
        asd.put("Albers Equal Area", "Albers_Conic_Equal_Area");

        final String methodName = asd.get(projectionName);

        DefaultMathTransformFactory mathTransformFactory = new DefaultMathTransformFactory();
        ParameterValueGroup parameters = mathTransformFactory.getDefaultParameters(methodName);

        if (values.length < 6) {
            throw new IOException("Not enough data");
        }

        if (!"Sinusoidal".equals(projectionName)) {
            //if (NumberUtils.isCreatable(values[1])) {
            parameters.parameter("latitude_of_origin").setValue(NumberUtils.toDouble(values[1]));
        }
        ////// }

        //    if (NumberUtils.isCreatable(values[2])) {
        parameters.parameter("central_meridian").setValue(NumberUtils.toDouble(values[2]));
        ////    }


        //     if (NumberUtils.isCreatable(values[4])) {
        parameters.parameter("false_easting").setValue(NumberUtils.toDouble(values[4]));
        ////    }

        //   if (NumberUtils.isCreatable(values[5])) {
        parameters.parameter("false_northing").setValue(NumberUtils.toDouble(values[5]));
        //   }

        if (("Mercator".equals(projectionName) || "Transverse Mercator".equals(projectionName)) && NumberUtils.isCreatable(values[3])) {
            parameters.parameter("scale_factor").setValue(NumberUtils.toDouble(values[3]));
        } //else {
//            if (values.length < 8) {
//                throw new IOException("Not enough data");
//            }

        if ("Lambert Conformal Conic".equals(projectionName) || "Albers Equal Area".equals(projectionName)) {
            if (values.length > 6 && NumberUtils.isCreatable(values[6])) {
                parameters.parameter("standard_parallel_1").setValue(NumberUtils.toDouble(values[6]));
            }

            if (values.length > 7 && NumberUtils.isCreatable(values[7])) {
                parameters.parameter("standard_parallel_2").setValue(NumberUtils.toDouble(values[7]));
            }
            //     }
        }

        return new DefiningConversion(methodName, parameters);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy