public ProjectionHandler getHandler(
      ReferencedEnvelope renderingEnvelope,
      CoordinateReferenceSystem sourceCrs,
      boolean wrap,
      int maxWraps)
      throws FactoryException {
    MapProjection mapProjection =
        CRS.getMapProjection(renderingEnvelope.getCoordinateReferenceSystem());
    if (renderingEnvelope != null && mapProjection instanceof Mercator) {
      ProjectionHandler handler;
      double centralMeridian =
          mapProjection
              .getParameterValues()
              .parameter(AbstractProvider.CENTRAL_MERIDIAN.getName().getCode())
              .doubleValue();
      if (wrap && maxWraps > 0) {
        handler =
            new WrappingProjectionHandler(
                renderingEnvelope, VALID_AREA, sourceCrs, centralMeridian, maxWraps);
      } else {
        handler = new ProjectionHandler(sourceCrs, VALID_AREA, renderingEnvelope);
        handler.setCentralMeridian(centralMeridian);
      }
      return handler;
    }

    return null;
  }
  public ProjectionHandler getHandler(
      ReferencedEnvelope renderingEnvelope,
      CoordinateReferenceSystem sourceCrs,
      boolean wrap,
      int maxWraps)
      throws FactoryException {
    MapProjection mapProjection =
        CRS.getMapProjection(renderingEnvelope.getCoordinateReferenceSystem());
    if (renderingEnvelope != null && mapProjection instanceof PolarStereographic) {
      boolean north;
      // variant B uses standard_parallel
      ParameterValue<?> stdParallel = null;
      try {
        stdParallel =
            mapProjection
                .getParameterValues()
                .parameter(AbstractProvider.STANDARD_PARALLEL_1.getName().getCode());
      } catch (ParameterNotFoundException e) {
        // ignore
      }
      if (stdParallel != null) {
        north = stdParallel.doubleValue() > 0;
      } else {
        // variant A uses latitude of origin
        ParameterValue<?> latOrigin = null;
        try {
          latOrigin =
              mapProjection
                  .getParameterValues()
                  .parameter(AbstractProvider.LATITUDE_OF_ORIGIN.getName().getCode());
        } catch (ParameterNotFoundException e) {
          // ignore
        }
        if (latOrigin != null) {
          north = latOrigin.doubleValue() > 0;
        } else {
          return null;
        }
      }

      ReferencedEnvelope validArea;
      if (north) {
        validArea =
            new ReferencedEnvelope(
                -Double.MAX_VALUE, Double.MAX_VALUE, -0, 90, DefaultGeographicCRS.WGS84);
      } else {
        validArea =
            new ReferencedEnvelope(
                -Double.MAX_VALUE, Double.MAX_VALUE, -90, 0, DefaultGeographicCRS.WGS84);
      }

      return new ProjectionHandler(sourceCrs, validArea, renderingEnvelope) {
        @Override
        public List<ReferencedEnvelope> getQueryEnvelopes()
            throws TransformException, FactoryException {
          // check if we are crossing the antimeridian and are fully below the pole,
          // in this case we'd end up reading the full globe when we'd have to just
          // read two portions near the dateline
          if (renderingEnvelope.getMaxY() < 0
              && renderingEnvelope.getMinX() < 0
              && renderingEnvelope.getMaxX() > 0) {
            ReferencedEnvelope e1 =
                new ReferencedEnvelope(
                    renderingEnvelope.getMinX(),
                    -1e-6,
                    renderingEnvelope.getMinY(),
                    renderingEnvelope.getMaxY(),
                    renderingEnvelope.getCoordinateReferenceSystem());
            ReferencedEnvelope e2 =
                new ReferencedEnvelope(
                    1e-6,
                    renderingEnvelope.getMaxX(),
                    renderingEnvelope.getMinY(),
                    renderingEnvelope.getMaxY(),
                    renderingEnvelope.getCoordinateReferenceSystem());
            List<ReferencedEnvelope> envelopes = new ArrayList<ReferencedEnvelope>();
            envelopes.add(e1);
            envelopes.add(e2);
            reprojectEnvelopes(sourceCRS, envelopes);
            return envelopes;
          } else {
            return super.getQueryEnvelopes();
          }
        }
      };
    }

    return null;
  }