[
https://issues.apache.org/jira/browse/SIS-432?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16646134#comment-16646134
]
Ferenc Hechler commented on SIS-432:
------------------------------------
I tried to find primary information about the NTv2 format. But the official
documentation from the Canadian government contains a
[PDF|https://dr6j45jk9xcmk.cloudfront.net/documents/1886/go-its-45-2-ntv2-national-transformation-version-2.pdf],
where the relevant *Appendix B: NTV2 DEVELOPER’S GUIDE* is missing.
So I found the following secondary information in a GitHub Project:
https://github.com/Esri/ntv2-file-routines/blob/master/README.md
{code:title=README.md}
...
### GSA file syntax
...
Grid-shift record:
Two or four numbers per line:
Latitude shift (in gs-units)
Longitude shift (in gs-units)
Latitude accuracy (in meters ) - optional
Longitude accuracy (in meters ) - optional
Notes:
1. ...
2. ...
3. Many published NTv2 files have all their accuracy values set
to either 0 or -1, which we assume indicates that no accuracy
data is provided. No GIS software that we know of makes use of
the accuracy data.
4. ...
...
{code}
So, the accuracy information in the NTv2 file is optional.
> 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
> Assignee: Martin Desruisseaux
> Priority: Major
> 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)