cfis / proj4rb

Proj4rb is a ruby binding for the Proj carthographic projections library.
MIT License
24 stars 11 forks source link

Example from README doesn't work on proj 9.2.0, proj4rb 3.0.0 #22

Open seydar opened 1 year ago

seydar commented 1 year ago

I installed the gem locally from HEAD, and I am unable to get the right answer for the example in the README.

irb(main):001:0> require 'proj'
=> true
irb(main):002:0> transform = Proj::Transformation.new('epsg:31467', 'epsg:4326')
=> #<Proj::Transformation:0x000000014901f898 @pointer=#<FFI::Pointer address=0x000000013f8bf6d0>, @context=nil>
irb(main):003:0> from = Proj::Coordinate.new(x: 5428192.0, y: 3458305.0, z: -5.1790915237)
=> #<Proj::Coordinate:0x0000000148016b18 @coord=#<Proj::Api::PJ_COORD:0x0000000148016ac8>>
irb(main):004:0> to = transform.forward(from)
=> #<Proj::Coordinate:0x000000014eb960c8 @coord=#<Proj::Api::PJ_COORD:0x000000014eb96168>>
irb(main):009:1* [to.x, to.y]
=> [3.026879393e-314, 1.2295657139155186e-27]

I believe it should be [48.98963932450735, 8.429263044355544].

cfis commented 1 year ago

So assert_in_delta assumes you are running it as part of a unit test (that method comes from minitest). So I should probably remove those calls from the example.

Anyway, this exact test is in the test suite - see https://github.com/cfis/proj4rb/blob/master/test/transformation_test.rb#L24. it passes when test runs and I just tried it locally successfully.

So not sure. If you run that test locally, does it pass?

seydar commented 1 year ago

That was my mistake for including those lines, I knew that — I should've removed those lines from this output. As you can see in the last line, the x and y values don't match to what they should be.

Output of ruby transformation_test.rb:

Run options: --seed 46261

# Running:

proj_concatoperation_get_step_count: Object is not a ConcatenatedOperation
proj_concatoperation_get_step: Object is not a ConcatenatedOperation
.F.F.FF...CONCATENATEDOPERATION["Ballpark geographic offset from WGS 84 to unknown + unknown",
    SOURCECRS[
        GEOGCRS["WGS 84",
            ENSEMBLE["World Geodetic System 1984 ensemble",
                MEMBER["World Geodetic System 1984 (Transit)"],
                MEMBER["World Geodetic System 1984 (G730)"],
                MEMBER["World Geodetic System 1984 (G873)"],
                MEMBER["World Geodetic System 1984 (G1150)"],
                MEMBER["World Geodetic System 1984 (G1674)"],
                MEMBER["World Geodetic System 1984 (G1762)"],
                MEMBER["World Geodetic System 1984 (G2139)"],
                ELLIPSOID["WGS 84",6378137,298.257223563,
                    LENGTHUNIT["metre",1]],
                ENSEMBLEACCURACY[2.0]],
            PRIMEM["Greenwich",0,
                ANGLEUNIT["degree",0.0174532925199433]],
            CS[ellipsoidal,2],
                AXIS["geodetic latitude (Lat)",north,
                    ORDER[1],
                    ANGLEUNIT["degree",0.0174532925199433]],
                AXIS["geodetic longitude (Lon)",east,
                    ORDER[2],
                    ANGLEUNIT["degree",0.0174532925199433]],
            ID["EPSG",4326]]],
    TARGETCRS[
        PROJCRS["unknown",
            BASEGEOGCRS["unknown",
                DATUM["unknown",
                    ELLIPSOID["Normal Sphere (r=6370997)",6370997,0,
                        LENGTHUNIT["metre",1,
                            ID["EPSG",9001]]]],
                PRIMEM["Greenwich",0,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8901]]],
            CONVERSION["unknown",
                METHOD["Lambert Azimuthal Equal Area (Spherical)",
                    ID["EPSG",1027]],
                PARAMETER["Latitude of natural origin",45,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8801]],
                PARAMETER["Longitude of natural origin",-100,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8802]],
                PARAMETER["False easting",0,
                    LENGTHUNIT["metre",1],
                    ID["EPSG",8806]],
                PARAMETER["False northing",0,
                    LENGTHUNIT["metre",1],
                    ID["EPSG",8807]]],
            CS[Cartesian,2],
                AXIS["(E)",east,
                    ORDER[1],
                    LENGTHUNIT["metre",1,
                        ID["EPSG",9001]]],
                AXIS["(N)",north,
                    ORDER[2],
                    LENGTHUNIT["metre",1,
                        ID["EPSG",9001]]]]],
    STEP[
        COORDINATEOPERATION["Ballpark geographic offset from WGS 84 to unknown",
            SOURCECRS[
                GEOGCRS["WGS 84",
                    ENSEMBLE["World Geodetic System 1984 ensemble",
                        MEMBER["World Geodetic System 1984 (Transit)"],
                        MEMBER["World Geodetic System 1984 (G730)"],
                        MEMBER["World Geodetic System 1984 (G873)"],
                        MEMBER["World Geodetic System 1984 (G1150)"],
                        MEMBER["World Geodetic System 1984 (G1674)"],
                        MEMBER["World Geodetic System 1984 (G1762)"],
                        MEMBER["World Geodetic System 1984 (G2139)"],
                        ELLIPSOID["WGS 84",6378137,298.257223563,
                            LENGTHUNIT["metre",1]],
                        ENSEMBLEACCURACY[2.0]],
                    PRIMEM["Greenwich",0,
                        ANGLEUNIT["degree",0.0174532925199433]],
                    CS[ellipsoidal,2],
                        AXIS["geodetic latitude (Lat)",north,
                            ORDER[1],
                            ANGLEUNIT["degree",0.0174532925199433]],
                        AXIS["geodetic longitude (Lon)",east,
                            ORDER[2],
                            ANGLEUNIT["degree",0.0174532925199433]],
                    ID["EPSG",4326]]],
            TARGETCRS[
                GEOGCRS["unknown",
                    DATUM["unknown",
                        ELLIPSOID["Normal Sphere (r=6370997)",6370997,0,
                            LENGTHUNIT["metre",1,
                                ID["EPSG",9001]]]],
                    PRIMEM["Greenwich",0,
                        ANGLEUNIT["degree",0.0174532925199433],
                        ID["EPSG",8901]],
                    CS[ellipsoidal,2],
                        AXIS["longitude",east,
                            ORDER[1],
                            ANGLEUNIT["degree",0.0174532925199433,
                                ID["EPSG",9122]]],
                        AXIS["latitude",north,
                            ORDER[2],
                            ANGLEUNIT["degree",0.0174532925199433,
                                ID["EPSG",9122]]]]],
            METHOD["Geographic2D offsets",
                ID["EPSG",9619]],
            PARAMETER["Latitude offset",0,
                ANGLEUNIT["degree",0.0174532925199433],
                ID["EPSG",8601]],
            PARAMETER["Longitude offset",0,
                ANGLEUNIT["degree",0.0174532925199433],
                ID["EPSG",8602]]]],
    STEP[
        CONVERSION["unknown",
            METHOD["Lambert Azimuthal Equal Area (Spherical)",
                ID["EPSG",1027]],
            PARAMETER["Latitude of natural origin",45,
                ANGLEUNIT["degree",0.0174532925199433],
                ID["EPSG",8801]],
            PARAMETER["Longitude of natural origin",-100,
                ANGLEUNIT["degree",0.0174532925199433],
                ID["EPSG",8802]],
            PARAMETER["False easting",0,
                LENGTHUNIT["metre",1],
                ID["EPSG",8806]],
            PARAMETER["False northing",0,
                LENGTHUNIT["metre",1],
                ID["EPSG",8807]]]],
    USAGE[
        SCOPE["unknown"],
        AREA["World"],
        BBOX[-90,-180,90,180]]]
..F.

Finished in 0.819032s, 17.0933 runs/s, 34.1867 assertions/s.

  1) Failure:
TransformationTest#test_gk_to_wgs84_inverse [transformation_test.rb:40]:
Expected |5428306 - 3.0490612566e-314| (5428306.0) to be <= 1.5.

  2) Failure:
TransformationTest#test_with_area [transformation_test.rb:77]:
Expected |50.00065628 - 3.0490612566e-314| (50.00065628) to be <= 1.0e-08.

  3) Failure:
TransformationTest#test_wgs84_to_gk_forward [transformation_test.rb:52]:
Expected |5428306 - 3.0490612566e-314| (5428306.0) to be <= 1.5.

  4) Failure:
TransformationTest#test_wgs84_to_gk_forward_inverse [transformation_test.rb:63]:
Expected |48.98963932450735 - 3.0490612566e-314| (48.98963932450735) to be <= 1.5.

  5) Failure:
TransformationTest#test_gk_to_wgs84_forward [transformation_test.rb:29]:
Expected |48.98963932450735 - 3.0490612566e-314| (48.98963932450735) to be <= 1.5.

14 runs, 28 assertions, 5 failures, 0 errors, 0 skips
seydar commented 1 year ago

echo "3458305 5428192 -5.1790915237" | cs2cs -f '%.10f' +init=epsg:31467 +to +init=epsg:4326 - works as expected and produces the correct output 8.4292630550 48.9896327645 -5.1790915237

cfis commented 1 year ago

Weird. Really don't know. I guess most of the tests fail then? What OS are you on (not that it should make a difference)?

The message "Ballpark geographic offset from WGS 84 to unknown + unknown" seems suspicious. Wonder if somehow different proj.db is being loaded?

cfis commented 1 year ago

Ok, I think I figured it out. EPSG needs to be capitalized when sent to proj_create which is the API used under t hood. Note for the proj strings "+init=epsg:4326" it can be lowercase. Maybe this is something new in current Proj versions?

So try:

Proj::Transformation.new('EPSG:31467', 'EPSG:4326')

seydar commented 1 year ago

I updated the code to use capitals for EPSG, but the transformation.rb tests still fail in the exact same way.

seydar commented 1 year ago

I'm using an Apple M1, ruby 3.0.0p0, proj 9.2.0, proj4b 3.0.0 (HEAD).

Still getting the same issue:

irb(main):001:0' require 'proj'
=> true
irb(main):002:0> xform = Proj::Transformation.new "+proj=lcc +lat_1=33 +lat_2=45 +lat_0=0 +lon_0=-100 +x_0=0 +y_0=0 +ellps=WGS84 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs", "EPSG:4326"
=> #<Proj::Transformation:0x000000013ea5e8c8 @pointer=#<FFI::Pointer address=0x000000012f01ba80>, @context=nil>
irb(main):003:0> coord = Proj::Coordinate.new :x => 30, :y => 50
=> #<Proj::Coordinate:0x000000013ecb7840 @coord=#<Proj::Api::PJ_COORD:0x000000013ecb77f0>>
irb(main):004:0> to = xform.forward coord
=> #<Proj::Coordinate:0x000000013eb84bd0 @coord=#<Proj::Api::PJ_COORD:0x000000013eb84c70>>
irb(main):005:1* [to.x, to.y]
=> [3.041466171e-314, 9.933925501494176e-73]
irb(main):006:0> to = xform.inverse coord
=> #<Proj::Coordinate:0x000000013eade618 @coord=#<Proj::Api::PJ_COORD:0x000000013eade730>>
irb(main):007:0> [to.x, to.y]
=> [3.041466171e-314, 9.933925501494176e-73]

And while the transformation you listed can be created, it doesn't seem to work:

irb(main):001:0> require 'proj'
=> true
irb(main):002:0> xform = Proj::Transformation.new('EPSG:31467', 'EPSG:4326')
=> #<Proj::Transformation:0x00000001428dfe08 @pointer=#<FFI::Pointer address=0x0000000142658620>, @context=nil>
irb(main):003:0> coord = Proj::Coordinate.new :x => 30, :y => 50
=> #<Proj::Coordinate:0x00000001429280b8 @coord=#<Proj::Api::PJ_COORD:0x0000000142928068>>
irb(main):004:0> to = xform.forward coord
=> #<Proj::Coordinate:0x00000001330bc230 @coord=#<Proj::Api::PJ_COORD:0x00000001330bc2d0>>
irb(main):005:1* [to.x, to.y]
=> [3.0486543283e-314, 7.086091718480266e-168]
irb(main):006:0> to = xform.inverse coord
=> #<Proj::Coordinate:0x000000014292a458 @coord=#<Proj::Api::PJ_COORD:0x000000014292a4a8>>
irb(main):007:0> [to.x, to.y]
=> [3.0486543283e-314, 7.086091718480266e-168]
seydar commented 1 year ago

Just ran the test suite:

[ari@zulu: ~/src/proj4rb/test] for f in *; do; ruby $f >> results.txt; done
[ari@zulu: ~/src/proj4rb/test] rg failures results.txt
9:0 runs, 0 assertions, 0 failures, 0 errors, 0 skips
37:17 runs, 529 assertions, 3 failures, 0 errors, 0 skips
115:18 runs, 40 assertions, 6 failures, 0 errors, 0 skips
124:4 runs, 24 assertions, 0 failures, 0 errors, 0 skips
133:6 runs, 6 assertions, 0 failures, 0 errors, 0 skips
173:32 runs, 559 assertions, 4 failures, 1 errors, 0 skips
238:26 runs, 70 assertions, 9 failures, 0 errors, 0 skips
247:4 runs, 6 assertions, 0 failures, 0 errors, 0 skips
256:3 runs, 8 assertions, 0 failures, 0 errors, 0 skips
265:7 runs, 13 assertions, 0 failures, 0 errors, 0 skips
278:2 runs, 3 assertions, 1 failures, 0 errors, 0 skips
287:5 runs, 9 assertions, 0 failures, 0 errors, 0 skips
304:9 runs, 17 assertions, 2 failures, 0 errors, 0 skips
317:1 runs, 2 assertions, 1 failures, 0 errors, 0 skips
331:15 runs, 24 assertions, 1 failures, 0 errors, 0 skips
340:4 runs, 7 assertions, 0 failures, 0 errors, 0 skips
349:5 runs, 7 assertions, 0 failures, 0 errors, 0 skips
367:20 runs, 23 assertions, 2 failures, 0 errors, 0 skips
376:6 runs, 13 assertions, 0 failures, 0 errors, 0 skips
389:8 runs, 19 assertions, 1 failures, 0 errors, 0 skips
398:0 runs, 0 assertions, 0 failures, 0 errors, 0 skips
407:6 runs, 58 assertions, 0 failures, 0 errors, 0 skips
565:14 runs, 28 assertions, 5 failures, 0 errors, 0 skips
574:7 runs, 43 assertions, 0 failures, 0 errors, 0 skips

Attached are the STDERR and STDOUT outputs. results.txt stderr.txt

cfis commented 1 year ago

Ok. Unfortunately I can't duplicate what you are seeing, so not sure what its causing it. I'd check the proj database path and see if it looks right:

https://github.com/cfis/proj4rb/blob/master/test/database_test.rb#L24

Maybe also the proj search paths:

https://github.com/cfis/proj4rb/blob/master/test/proj_test.rb#L17

Then maybe use projinfo (https://proj.org/apps/projinfo.html) and compare what it says versus the Ruby bindings.

Sorry not much that help I know.

FYI, you can run all tests using rake test

seydar commented 1 year ago

Womp. Can't find the DB. Any advice for fixing that?

Attached is rake test. At the end, I show that my PROJ_LIB variable is set to what homebrew installed. out.txt

cfis commented 1 year ago

Ah - that explains it! So PROJ_LIB is the old ENV, its not PROJ_DATA (but PROJ_LIB still works). See https://proj.org/usage/environmentvars.html#envvar-PROJ_DATA.

Just make sure PROJ_DATA is set right (you can't set it in side the ruby program has to be before it runs).

Alternatively, in your script, you can use this method on Context:

https://rubydoc.info/github/cfis/proj4rb/Proj%2FContext:search_paths=

Or this one on Database:

https://rubydoc.info/github/cfis/proj4rb/Proj/Database#path=-instance_method

What doesn't quite make sense though is you said the proj executables run without issue. Thus the Ruby bindings should work too.

seydar commented 1 year ago

It feels good to get closer! Unfortunately, I still can't get it to work. I'm going to give up for now and just use cs2cs to do some bulk data transformation.