GeoTools
  1. GeoTools
  2. GEOT-1747

GridCoverageRenderer fails to display coverages whose envelope touches the poles when reprojection to 900913 is required

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.1, 2.5-M0
    • Fix Version/s: 2.4.2, 2.5-M1
    • Component/s: render
    • Labels:
      None

      Description

      Situation:

      • coverage whose envelope spans the whole globe (exactly, -180/180, -90/90)
      • coverage is in 4326
      • reprojection is requested to 900913

      The result is the following exception:

      20 mar 16:21:01 WARN [geotools.rendering] - Latitude 9000.0'S is too close to a pole.
      org.geotools.referencing.operation.projection.ProjectionException: Latitude 9000.0'S is too close to a pole.
      	at org.geotools.referencing.operation.projection.Mercator$Spherical.transformNormalized(Mercator.java:212)
      	at org.geotools.referencing.operation.projection.MapProjection.transform(MapProjection.java:784)
      	at org.geotools.referencing.operation.projection.MapProjection.transform(MapProjection.java:825)
      	at org.geotools.referencing.operation.transform.AbstractMathTransform.transform(AbstractMathTransform.java:217)
      	at org.geotools.referencing.CRS.transform(CRS.java:983)
      	at org.geotools.referencing.CRS.transform(CRS.java:929)
      	at org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer.paint(GridCoverageRenderer.java:354)
      	at org.geotools.renderer.lite.StreamingRenderer.renderRaster(StreamingRenderer.java:1850)
      	at org.geotools.renderer.lite.StreamingRenderer.processSymbolizers(StreamingRenderer.java:1709)
      ...
      

      The issue is that the code is trying to reproject the whole native envelope to 900913, but rendering over
      google maps does not require that (the map is actually cut at 85 or something like that).

        Issue Links

          Activity

          Hide
          Simone Giannecchini added a comment -
          aaime, I have asked daniele to spent a couple of hours to backport to 2.4.x.
          Show
          Simone Giannecchini added a comment - aaime, I have asked daniele to spent a couple of hours to backport to 2.4.x.
          Hide
          Martin Desruisseaux added a comment -
          Oups! Missed the last discussion on this topic.

          Yes relaxing the exception throw when too close to a pole whould means producing envelope with miny = Double.NEGATIVE_INFINITY and maxy = Double.NEGATIVE_INFINITY (or being close to that)...

          I agree with Andrea's remark, that hidding an error occuring soon may just push the error futher in the code, making the bug harder to diagnotic. I'm usually a strong supporter of "check early, thrown an exception early" in case of error. Yet this particular case is a gray corner, because on a mathematic point of view an infinite value is not really an error if projected values near a pole really tend toward infinities...

          I have not yet taken any action on this issue. I'm still unsure about which action would be best.
          Show
          Martin Desruisseaux added a comment - Oups! Missed the last discussion on this topic. Yes relaxing the exception throw when too close to a pole whould means producing envelope with miny = Double.NEGATIVE_INFINITY and maxy = Double.NEGATIVE_INFINITY (or being close to that)... I agree with Andrea's remark, that hidding an error occuring soon may just push the error futher in the code, making the bug harder to diagnotic. I'm usually a strong supporter of "check early, thrown an exception early" in case of error. Yet this particular case is a gray corner, because on a mathematic point of view an infinite value is not really an error if projected values near a pole really tend toward infinities... I have not yet taken any action on this issue. I'm still unsure about which action would be best.
          Hide
          Andrea Aime added a comment -
          A pragmatic solution would be to use Double.MAX_VALUE, that is, work in a sort of saturation logic. Thought this approach would be unsatisfactory from a mathematical point of view...
          Show
          Andrea Aime added a comment - A pragmatic solution would be to use Double.MAX_VALUE, that is, work in a sort of saturation logic. Thought this approach would be unsatisfactory from a mathematical point of view...
          Hide
          Martin Desruisseaux added a comment -
          I have no example in mind right now where Double.MAX_VALUE and Double.POSITIVE_INFINITY would change much... The result of operations like comparaisons, divisions, etc. would be very similar in both case (divising by MAX_VALUE would produces a number very close to zero, while divising by POSITIVE_INFINITY would produces exactly zero, etc.)

          My concern was about use case like this one: a widget transforms a geographic envelope to Mercator, then blindly zoom out in order to get the whole envelope contained in the window. If the envelope tends toward infinity, most of the Earth surface would be crunshed in an tiny line in the middle, and pole would fill the whole remainding area.

          One possible fix on user side would be to make some defensive clipping of the envelope. But how the user would know which clip to apply? Looking at the "Domain of Validity" metadata attached to CRS may help, but I'm not sure that many user would do... (and this metadata is still missing when x,y axis are swapped, as you pointed out in an other JIRA task).

          In summary, throwing an exception in MapProjection protects some user from mistakes, but prevent other users to do their work when they know what they are doing (i.e. they clip the resulting envelope). Not throwing an exception would give more flexibility to power users, but requires more discipline for all users (keep in mind that you may needs to clip your resulting envelope).

          A possible intermediate approach would be to provide a method in CRS utility class, said transform(envelope, targetCRS), which applies automatically the clip specified in "Domain of Validity" metadata, if presents.
          Show
          Martin Desruisseaux added a comment - I have no example in mind right now where Double.MAX_VALUE and Double.POSITIVE_INFINITY would change much... The result of operations like comparaisons, divisions, etc. would be very similar in both case (divising by MAX_VALUE would produces a number very close to zero, while divising by POSITIVE_INFINITY would produces exactly zero, etc.) My concern was about use case like this one: a widget transforms a geographic envelope to Mercator, then blindly zoom out in order to get the whole envelope contained in the window. If the envelope tends toward infinity, most of the Earth surface would be crunshed in an tiny line in the middle, and pole would fill the whole remainding area. One possible fix on user side would be to make some defensive clipping of the envelope. But how the user would know which clip to apply? Looking at the "Domain of Validity" metadata attached to CRS may help, but I'm not sure that many user would do... (and this metadata is still missing when x,y axis are swapped, as you pointed out in an other JIRA task). In summary, throwing an exception in MapProjection protects some user from mistakes, but prevent other users to do their work when they know what they are doing (i.e. they clip the resulting envelope). Not throwing an exception would give more flexibility to power users, but requires more discipline for all users (keep in mind that you may needs to clip your resulting envelope). A possible intermediate approach would be to provide a method in CRS utility class, said transform(envelope, targetCRS), which applies automatically the clip specified in "Domain of Validity" metadata, if presents.
          Hide
          Andrea Aime added a comment -
          Mass closing all issues that have been in "resolved" state for 2 months or more without any feedback or update
          Show
          Andrea Aime added a comment - Mass closing all issues that have been in "resolved" state for 2 months or more without any feedback or update

            People

            • Assignee:
              Daniele Romagnoli
              Reporter:
              Andrea Aime
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: