Ferenc Hechler created SIS-432:
----------------------------------

             Summary: Using BETA2007.gsb grid throws IllegalArgumentException
                 Key: SIS-432
                 URL: https://issues.apache.org/jira/browse/SIS-432
             Project: Spatial Information Systems
          Issue Type: Bug
    Affects Versions: 0.8
            Reporter: Ferenc Hechler
         Attachments: patch_BETA2007_gsb.png

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

{code:title=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)");
}
{code}
 
Running the program gives the following output:

{code:title=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)
{code}

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|http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/BETA2007.gsa] 
and the binary format, which is needed for Apache SIS 
[BETA2007.gsb|http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/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:

{code:title=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
{code}

I debugged into the code and found the following.

In InterpolatedTransform the DataShiftGrid is checked for its accuracy 
(getCellPrecision() returns accuracy/10):
{code:title=InterpolatedTransform.java}
tolerance = grid.getCellPrecision();
if (!(tolerance > 0)) {         // Use ! for catching NaN.
    throw new IllegalArgumentException(Errors.format(
        Errors.Keys.ValueNotGreaterThanZero_2, "grid.cellPrecision", 
tolerance));
{code}

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:

{code:title=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;
{code}

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:

{code:title=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;
  }
}
{code}

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:
{code:title=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
{code}

(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:
!patch_BETA2007_gsb.png! 

The change would be in ASCII:
{code:title=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
{code}

So the first shift gets an accuracy value greater then 0.0.
With this patched BETA2007.gsb file the program runs as expected:
{code}
Source:   POINT(5500000 3500000)
Target:   POINT(49.63670826166641 8.99895896840875)
Expected: POINT(49.63670826166641 8.99895896840875)
{code}

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:
{code}
(gridPrecision > 0) ? gridPrecision : DEFAULT_PRECISION);
{code}

Maybe this can be done in NTv2 for NaN values.







--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to