Uploaded image for project: 'Spatial Information Systems'
  1. Spatial Information Systems
  2. SIS-432

Using BETA2007.gsb grid throws IllegalArgumentException

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 0.8
    • 1.0
    • None
    • None

    Description

      The following program transforms Gauß-Krüger coordinates (used in Germany) to the WGS84 format:

      Main.java
      public static void main(String[] args) throws Exception {
        double hochwert = 5500000.0;
        double rechtswert = 3500000.0;
        
        CoordinateReferenceSystem sourceCRS = CRS.forCode("EPSG:31467");
        CoordinateReferenceSystem targetCRS = CRS.forCode("EPSG:4326");
        CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null);
        
        DirectPosition ptSrc = new DirectPosition2D(hochwert, rechtswert);
        DirectPosition ptDst = operation.getMathTransform().transform(ptSrc, null);
      
        System.out.println("Source:   " + ptSrc);
        System.out.println("Target:   " + ptDst);  
        System.out.println("Expected: POINT(49.63670826166641 8.99895896840875)");
      }
      

       
      Running the program gives the following output:

      console.log
      Okt 09, 2018 10:45:00 PM org.apache.sis.referencing.operation.CoordinateOperationFinder createOperation
      WARNUNG: Can not parse “BETA2007.gsb” as a file in the NTv2 format.
      Source:   POINT(5500000 3500000)
      Target:   POINT(49.636710642245184 8.99896356404719)
      Expected: POINT(49.63670826166641 8.99895896840875)
      

      As you can see, the result is not as expected.
      The reason is, that the grid shift file BETA2007.gsb was not found, as the warning before already stated: WARNUNG: Can not parse “BETA2007.gsb” as a file in the NTv2 format.

      The grid shift file "BETA2007.gsb" can be downloaded from the following website: http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/de_dhdn2etrs_beta.php

      There is a link to the ASCII version BETA2007.gsa and the binary format, which is needed for Apache SIS BETA2007.gsb

      I downloaded the BETA2007.gsb file and copied it into the current working directory (or into the project folder in Eclipse).
      Then I started the same main program again and got the follwoing exception:

      console.log
      Exception in thread "main" org.apache.sis.referencing.factory.InvalidGeodeticParameterException: Value ‘grid.cellPrecision’ = ? is invalid. Expected a number greater than 0.
      	at org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.createParameterizedTransform(DefaultMathTransformFactory.java:1050)
      	at org.apache.sis.referencing.factory.sql.EPSGDataAccess.createCoordinateOperation(EPSGDataAccess.java:2927)
      	at org.apache.sis.referencing.factory.AuthorityFactoryProxy$34.create(AuthorityFactoryProxy.java:515)
      	at org.apache.sis.referencing.factory.AuthorityFactoryProxy$34.create(AuthorityFactoryProxy.java:513)
      	at org.apache.sis.referencing.factory.ConcurrentAuthorityFactory.create(ConcurrentAuthorityFactory.java:1679)
      	at org.apache.sis.referencing.factory.ConcurrentAuthorityFactory.createCoordinateOperation(ConcurrentAuthorityFactory.java:1590)
      	at org.apache.sis.internal.referencing.DeferredCoordinateOperation.create(DeferredCoordinateOperation.java:71)
      	at org.apache.sis.referencing.operation.CoordinateOperationRegistry.search(CoordinateOperationRegistry.java:506)
      	at org.apache.sis.referencing.operation.CoordinateOperationRegistry.createOperation(CoordinateOperationRegistry.java:333)
      	at org.apache.sis.referencing.operation.CoordinateOperationFinder.createOperation(CoordinateOperationFinder.java:236)
      	at org.apache.sis.referencing.operation.CoordinateOperationFinder.createOperationStep(CoordinateOperationFinder.java:358)
      	at org.apache.sis.referencing.operation.CoordinateOperationFinder.createOperation(CoordinateOperationFinder.java:250)
      	at org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory.createOperation(DefaultCoordinateOperationFactory.java:811)
      	at org.apache.sis.referencing.CRS.findOperation(CRS.java:640)
      	at de.hechler.apsistest.GK3toWGS84.main(GK3toWGS84.java:23)
      Caused by: java.lang.IllegalArgumentException: Value ‘grid.cellPrecision’ = ? is invalid. Expected a number greater than 0.
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform$Inverse.<init>(InterpolatedTransform.java:440)
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform2D$Inverse.<init>(InterpolatedTransform2D.java:107)
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform2D.createInverse(InterpolatedTransform2D.java:87)
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform.<init>(InterpolatedTransform.java:198)
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform2D.<init>(InterpolatedTransform2D.java:47)
      	at org.apache.sis.referencing.operation.transform.InterpolatedTransform.createGeodeticTransformation(InterpolatedTransform.java:235)
      	at org.apache.sis.internal.referencing.provider.NTv2.createMathTransform(NTv2.java:128)
      	at org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.createParameterizedTransform(DefaultMathTransformFactory.java:1048)
      	... 14 more
      

      I debugged into the code and found the following.

      In InterpolatedTransform the DataShiftGrid is checked for its accuracy (getCellPrecision() returns accuracy/10):

      InterpolatedTransform.java
      tolerance = grid.getCellPrecision();
      if (!(tolerance > 0)) {         // Use ! for catching NaN.
          throw new IllegalArgumentException(Errors.format(
              Errors.Keys.ValueNotGreaterThanZero_2, "grid.cellPrecision", tolerance));
      

      In NTv2.java a DatumShiftGridFile.Float instance is created to read in the BETA2007.gsb file. In DatumShiftGridFile.Float the accuracy member variable is initialized with NaN:

      DatumShiftGridFile.java
          /**
           * The best translation accuracy that we can expect from this file.
           *
           * <p>This field is initialized to Double#NaN. It is loader responsibility
           * to assign a value to this field after DatumShiftGridFile construction.</p>
           */
          protected double accuracy;
      

      The loader, in this case, is NTv2.java and so it is responsible to set the accuracy field. And there is code to set the accuracy based on the data in the BETA2007.gsb file:

      NTv2.java
      for (int i=0; i<count; i++) {
        ensureBufferContains(4 * (Float.SIZE / Byte.SIZE));
        ty[i] = (float) (buffer.getFloat() / dy);   // Division by dx and dy because isCellValueRatio = true.
        tx[i] = (float) (buffer.getFloat() / dx);
        final double accuracy = Math.min(buffer.getFloat() / dy, buffer.getFloat() / dx);
        if (accuracy > 0 && !(accuracy >= grid.accuracy)) {   // Use '!' for replacing the initial NaN.
          grid.accuracy = accuracy;
        }
      }
      

      So, the grid.accuracy is set to the minimum accuracy from longitude and latitude.
      But as to see in the ASCII file, all precision fields (third and fourth column) are set to 0.000000:

      BETA2007.gsa
      ...
      GS_COUNT  5208
       -2.749746  7.165792  0.000000  0.000000
       -2.750032  7.067153  0.000000  0.000000
       -2.750411  6.968641  0.000000  0.000000
      ...
       -6.330753  2.260298  0.000000  0.000000
       -6.338144  2.193162  0.000000  0.000000
       -6.345754  2.126569  0.000000  0.000000
      END
      

      (the .gsb file is the binary created from the .gsa file)

      And because of this, the grid.accuracy is never set and remains NaN.
      And then the validation in InterpolatedTransform throws the IllegalArgumentException.

      I patched the BETA2007.gsb file at position 0x168:

      The change would be in ASCII:

      BETA2007.gsa(PATCHED)
      ...
      GS_COUNT  5208
       -2.749746  7.165792  0.000001  0.000001
       -2.750032  7.067153  0.000000  0.000000
       -2.750411  6.968641  0.000000  0.000000
      ...
       -6.330753  2.260298  0.000000  0.000000
       -6.338144  2.193162  0.000000  0.000000
       -6.345754  2.126569  0.000000  0.000000
      END
      

      So the first shift gets an accuracy value greater then 0.0.
      With this patched BETA2007.gsb file the program runs as expected:

      Source:   POINT(5500000 3500000)
      Target:   POINT(49.63670826166641 8.99895896840875)
      Expected: POINT(49.63670826166641 8.99895896840875)
      

      So may be, that this is in real an issue for the BETA2007 file, because it does not provide an accuracy for any shift value.
      But the BETA2007.gsb file from above is the official file and I did not find any other source providing accuracy values.
      On the website it is stated, that the accuracy is less than one meter.

      I think the issue could be fixed In NTv2.java, so that it initializes the grid.accuracy to some default value if it is NaN after checking all shifts.

      LocalizationGridBuilder has some similiair intialization:

      (gridPrecision > 0) ? gridPrecision : DEFAULT_PRECISION);
      

      Maybe this can be done in NTv2 for NaN values.

      Attachments

        1. patch_BETA2007_gsb.png
          12 kB
          Ferenc Hechler

        Activity

          People

            desruisseaux Martin Desruisseaux
            feri Ferenc Hechler
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: