Ignore:
Timestamp:
2018-05-06T19:12:14+02:00 (6 years ago)
Author:
Don-vip
Message:

see #16129 - call PROJ by JNI if available. Faster and removes the problem of escaping quote characters via command line

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/test/unit/org/openstreetmap/josm/data/projection/ProjectionRefTest.java

    r13703 r13705  
    1212import java.io.OutputStream;
    1313import java.io.OutputStreamWriter;
     14import java.lang.reflect.Constructor;
     15import java.lang.reflect.Method;
    1416import java.nio.charset.StandardCharsets;
    1517import java.security.SecureRandom;
     
    6668    private static final String PROJ_LIB_DIR = "data_nodist/projection";
    6769
    68     private static final int MAX_LENGTH = 524288;
    69 
    7070    private static class RefEntry {
    7171        String code;
     
    193193                    System.out.print(".");
    194194                    System.out.flush();
     195                    if (debug) {
     196                        System.out.println();
     197                    }
    195198                    LatLon ll = forced ? ref.data.get(i).a : getRandom(b);
    196199                    EastNorth en = latlon2eastNorthProj4(def, ll);
     
    235238
    236239    /**
     240     * Run external PROJ.4 library to convert lat/lon to east/north value.
     241     * @param def the proj.4 projection definition string
     242     * @param ll the LatLon
     243     * @return projected EastNorth or null in case of error
     244     */
     245    private static EastNorth latlon2eastNorthProj4(String def, LatLon ll) {
     246        try {
     247            Class<?> projClass = Class.forName("org.proj4.PJ");
     248            Constructor<?> constructor = projClass.getConstructor(String.class);
     249            Method transform = projClass.getMethod("transform", projClass, int.class, double[].class, int.class, int.class);
     250            Object sourcePJ = constructor.newInstance("+proj=longlat +datum=WGS84");
     251            Object targetPJ = constructor.newInstance(def);
     252            double[] coordinates = {ll.lon(), ll.lat()};
     253            if (debug) {
     254                System.out.println(def);
     255                System.out.print(Arrays.toString(coordinates));
     256            }
     257            transform.invoke(sourcePJ, targetPJ, 2, coordinates, 0, 1);
     258            if (debug) {
     259                System.out.println(" -> " + Arrays.toString(coordinates));
     260            }
     261            return new EastNorth(coordinates[0], coordinates[1]);
     262        } catch (ReflectiveOperationException | LinkageError | SecurityException e) {
     263            if (debug) {
     264                e.printStackTrace();
     265            }
     266            // PROJ JNI bindings not available, fallback to cs2cs
     267            return latlon2eastNorthProj4cs2cs(def, ll);
     268        }
     269    }
     270
     271    /**
    237272     * Run external cs2cs command from the PROJ.4 library to convert lat/lon to east/north value.
    238273     * @param def the proj.4 projection definition string
     
    241276     */
    242277    @SuppressFBWarnings(value = "COMMAND_INJECTION")
    243     private static EastNorth latlon2eastNorthProj4(String def, LatLon ll) {
     278    private static EastNorth latlon2eastNorthProj4cs2cs(String def, LatLon ll) {
    244279        List<String> args = new ArrayList<>();
    245280        args.add(CS2CS_EXE);
     
    342377    public void testProjections() throws IOException {
    343378        StringBuilder fail = new StringBuilder();
     379        Map<String, Set<String>> failingProjs = new HashMap<>();
    344380        Set<String> allCodes = new HashSet<>(Projections.getAllProjectionCodes());
    345381        Collection<RefEntry> refs = readData();
     
    353389                fail.append("definitions for ").append(ref.code).append(" do not match\n");
    354390            } else {
    355                 Projection proj = Projections.getProjectionByCode(ref.code);
    356                 double scale = ((CustomProjection) proj).getToMeter();
     391                CustomProjection proj = (CustomProjection) Projections.getProjectionByCode(ref.code);
     392                double scale = proj.getToMeter();
    357393                for (Pair<LatLon, EastNorth> p : ref.data) {
    358394                    LatLon ll = p.a;
     
    372408                                proj.toString(), proj.toCode(), ll.lat(), ll.lon(), enRef.east(), enRef.north(), en.east(), en.north());
    373409                        fail.append(errorEN);
     410                        failingProjs.computeIfAbsent(proj.proj.getProj4Id(), x -> new TreeSet<>()).add(ref.code);
    374411                    }
    375412                }
     
    381418        }
    382419        if (fail.length() > 0) {
    383             String s = fail.toString();
    384             if (s.length() > MAX_LENGTH) {
    385                 // SonarQube/Surefire can't parse XML attributes longer than 524288 characters
    386                 s = s.substring(0, MAX_LENGTH - 4) + "...";
    387             }
    388             System.err.println(s);
    389             throw new AssertionError(s);
     420            System.err.println(fail.toString());
     421            throw new AssertionError("Failing:\n" +
     422                    failingProjs.keySet().size() + " projections: " + failingProjs.keySet() + "\n" +
     423                    failingProjs.values().stream().mapToInt(Set::size).sum() + " definitions: " + failingProjs);
    390424        }
    391425    }
Note: See TracChangeset for help on using the changeset viewer.