public static void main(String[] args) {
    String testDataLocation = "testData/HighResolutionTerrain/";
    HashMap<String, Sector> sectors = new HashMap<String, Sector>();
    sectors.put(
        testDataLocation + "HRTOutputTest01.txt", Sector.fromDegrees(37.8, 38.3, -120, -119.3));
    sectors.put(
        testDataLocation + "HRTOutputTest02.txt",
        Sector.fromDegrees(32.34767, 32.77991, 70.88239, 71.47658));
    sectors.put(
        testDataLocation + "HRTOutputTest03.txt",
        Sector.fromDegrees(32.37825, 71.21130, 32.50050, 71.37926));

    try {
      if (args.length > 0 && args[0].equals("-generateTestData")) {
        for (Map.Entry<String, Sector> sector : sectors.entrySet()) {
          String filePath = sector.getKey();

          generateReferenceValues(filePath, sector.getValue());
        }
      }

      for (Map.Entry<String, Sector> sector : sectors.entrySet()) {
        String filePath = sector.getKey();

        ArrayList<Position> referencePositions = readReferencePositions(filePath);
        ArrayList<Position> computedPositions = computeElevations(referencePositions);
        testPositions(filePath, referencePositions, computedPositions);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }
  public static Sector[] splitBoundingSectors(Iterable<? extends LatLon> locations) {
    if (locations == null) {
      throw new IllegalArgumentException("Location In List Is Null");
    }

    if (!locations.iterator().hasNext()) {
      return null;
    }

    double minLat = Angle.POS90.getDegrees();
    double minLon = Angle.POS180.getDegrees();
    double maxLat = Angle.NEG90.getDegrees();
    double maxLon = Angle.NEG180.getDegrees();

    LatLon lastLocation = null;

    for (LatLon ll : locations) {
      double lat = ll.getLatitude().getDegrees();
      if (lat < minLat) {
        minLat = lat;
      }
      if (lat > maxLat) {
        maxLat = lat;
      }

      double lon = ll.getLongitude().getDegrees();
      if (lon >= 0 && lon < minLon) {
        minLon = lon;
      }
      if (lon <= 0 && lon > maxLon) {
        maxLon = lon;
      }

      if (lastLocation != null) {
        double lastLon = lastLocation.getLongitude().getDegrees();
        if (Math.signum(lon) != Math.signum(lastLon)) {
          if (Math.abs(lon - lastLon) < 180) {
            // Crossing the zero longitude line too
            maxLon = 0;
            minLon = 0;
          }
        }
      }
      lastLocation = ll;
    }

    if (minLat == maxLat && minLon == maxLon) {
      return null;
    }

    return new Sector[] {
      Sector.fromDegrees(minLat, maxLat, minLon, 180), // Sector on eastern hemisphere.
      Sector.fromDegrees(minLat, maxLat, -180, maxLon) // Sector on western hemisphere.
    };
  }
Пример #3
0
    private Info[] buildSurfaceShapes() {
      LatLon position = new LatLon(Angle.fromDegrees(38), Angle.fromDegrees(-105));

      ArrayList<LatLon> surfaceLinePositions = new ArrayList<LatLon>();
      //            surfaceLinePositions.add(LatLon.fromDegrees(37.8484, -119.9754));
      //            surfaceLinePositions.add(LatLon.fromDegrees(38.3540, -119.1526));

      //            surfaceLinePositions.add(new LatLon(Angle.fromDegrees(0),
      // Angle.fromDegrees(-150)));
      //            surfaceLinePositions.add(new LatLon(Angle.fromDegrees(60),
      // Angle.fromDegrees(0)));

      surfaceLinePositions.add(position);
      surfaceLinePositions.add(LatLon.fromDegrees(39, -104));
      surfaceLinePositions.add(LatLon.fromDegrees(39, -105));
      surfaceLinePositions.add(position);

      return new Info[] {
        new Info("Circle", new SurfaceCircle(position, 100e3)),
        new Info("Ellipse", new SurfaceEllipse(position, 100e3, 90e3, Angle.ZERO)),
        new Info("Square", new SurfaceSquare(position, 100e3)),
        new Info("Quad", new SurfaceQuad(position, 100e3, 60e3, Angle.ZERO)),
        new Info("Sector", new SurfaceSector(Sector.fromDegrees(38, 40, -105, -103))),
        new Info("Polygon", new SurfacePolygon(surfaceLinePositions)),
      };
    }
  public static Sector boundingSector(Iterable<? extends LatLon> locations) {
    if (locations == null) {
      throw new IllegalArgumentException("Positions List Is Null");
    }

    if (!locations.iterator().hasNext()) {
      return EMPTY_SECTOR; // TODO: should be returning null
    }
    double minLat = Angle.POS90.getDegrees();
    double minLon = Angle.POS180.getDegrees();
    double maxLat = Angle.NEG90.getDegrees();
    double maxLon = Angle.NEG180.getDegrees();

    for (LatLon p : locations) {
      double lat = p.getLatitude().getDegrees();
      if (lat < minLat) {
        minLat = lat;
      }
      if (lat > maxLat) {
        maxLat = lat;
      }

      double lon = p.getLongitude().getDegrees();
      if (lon < minLon) {
        minLon = lon;
      }
      if (lon > maxLon) {
        maxLon = lon;
      }
    }

    return Sector.fromDegrees(minLat, maxLat, minLon, maxLon);
  }
Пример #5
0
    /**
     * Loads the image at imageuri into the mapMapPanel
     *
     * @param imageuri URI to .jpg file
     * @return If loading was successful
     */
    private boolean loadNewImage(String imageuri) {
      if (mapSurfaceImage != null) {
        mapRenderLayer.removeAllRenderables();
      }

      try {
        mapBufferedImage = ImageIO.read(new URL(imageuri));
      } catch (IOException e) {
        return false;
      }

      double max =
          (mapBufferedImage.getHeight() > mapBufferedImage.getWidth())
              ? mapBufferedImage.getHeight()
              : mapBufferedImage.getWidth();
      mapImageGeoHeight = BASE_MAX_IMAGE_SIZE * mapBufferedImage.getWidth() / max;
      mapImageGeoWidth = BASE_MAX_IMAGE_SIZE * mapBufferedImage.getHeight() / max;

      mapSurfaceImage =
          new SurfaceImage(
              mapBufferedImage, Sector.fromDegrees(0, mapImageGeoWidth, 0, mapImageGeoHeight));
      Polyline boundary = new Polyline(mapSurfaceImage.getCorners(), 0);
      boundary.setFollowTerrain(true);
      boundary.setClosed(true);
      boundary.setPathType(Polyline.RHUMB_LINE);
      boundary.setColor(new Color(0, 255, 0));

      mapRenderLayer.addRenderable(mapSurfaceImage);
      mapRenderLayer.addRenderable(boundary);
      mapMapPanel.wwd.redraw();
      return true;
    }
 protected void createRectangularArray() {
   this.arraySector = Sector.fromDegrees(20, 30, -110, -100);
   this.arrayWidth = 60;
   this.arrayHeight = 60;
   this.arrayValues =
       ExampleUtil.readCommaDelimitedNumbers(
           "gov/nasa/worldwindx/examples/data/GridValues01_60x60.csv");
 }
    protected void performIntersectionTests(final Position curPos) throws InterruptedException {
      // Clear the results lists when the user selects a new location.
      this.firstIntersectionPositions.clear();
      this.sightLines.clear();

      // Raise the selected location and the grid points a little above ground just to show we can.
      final double height = 5; // meters

      // Form the grid.
      double gridRadius = GRID_RADIUS.degrees;
      Sector sector =
          Sector.fromDegrees(
              curPos.getLatitude().degrees - gridRadius, curPos.getLatitude().degrees + gridRadius,
              curPos.getLongitude().degrees - gridRadius,
                  curPos.getLongitude().degrees + gridRadius);

      this.grid = buildGrid(sector, height, GRID_DIMENSION, GRID_DIMENSION);
      this.numGridPoints = grid.size();

      // Compute the position of the selected location (incorporate its height).
      this.referencePosition = new Position(curPos.getLatitude(), curPos.getLongitude(), height);
      this.referencePoint =
          terrain.getSurfacePoint(curPos.getLatitude(), curPos.getLongitude(), height);

      //            // Pre-caching is unnecessary and is useful only when it occurs before the
      // intersection
      //            // calculations. It will incur extra overhead otherwise. The normal intersection
      // calculations
      //            // cause the same caching, making subsequent calculations on the same area
      // faster.
      //            this.preCache(grid, this.referencePosition);

      // On the EDT, show the grid.
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              progressBar.setValue(0);
              progressBar.setString(null);
              clearLayers();
              showGrid(grid, referencePosition);
              getWwd().redraw();
            }
          });

      // Perform the intersection calculations.
      this.startTime = System.currentTimeMillis();
      for (Position gridPos : this.grid) // for each grid point.
      {
        //noinspection ConstantConditions
        if (NUM_THREADS > 0) this.threadPool.execute(new Intersector(gridPos));
        else performIntersection(gridPos);
      }
    }
/**
 * Illustrates rotating a {@link gov.nasa.worldwind.geom.Sector} from standard position. A <code>
 * Sector</code> is created, its width and height computed, and a {@link
 * gov.nasa.worldwind.render.SurfaceQuad} created from the <code>sector's</code> centroid and the
 * computed width and height. The <code>SurfaceQuad's</code> heading is then set to the desired
 * rotation angle.
 *
 * @author tag
 * @version $Id$
 */
public class RotatedSector extends ApplicationTemplate {
  private static final Sector sector = Sector.fromDegrees(45, 47, -123, -122);

  public static class AppFrame extends ApplicationTemplate.AppFrame {
    public AppFrame() {
      super(true, true, false);

      try {
        // Create the Quad from a Sector
        Globe globe = this.getWwd().getModel().getGlobe();
        double radius = globe.getRadiusAt(sector.getCentroid());
        double quadWidth = sector.getDeltaLonRadians() * radius;
        double quadHeight = sector.getDeltaLatRadians() * radius;
        final SurfaceQuad quad =
            new SurfaceQuad(sector.getCentroid(), quadWidth, quadHeight, Angle.ZERO);

        // Create the layer to hold it
        final RenderableLayer layer = new RenderableLayer();
        layer.setName("Rotating Sector");
        layer.addRenderable(quad);

        // Add the layer to the model and update the ApplicationTemplate's layer manager
        insertBeforeCompass(this.getWwd(), layer);
        this.getLayerPanel().update(this.getWwd());

        // Rotate the quad continuously
        Timer timer =
            new Timer(
                50,
                new ActionListener() {
                  public void actionPerformed(ActionEvent actionEvent) {
                    // Increment the current heading if the layer is visible
                    if (layer.isEnabled()) {
                      quad.setHeading(
                          Angle.fromDegrees((quad.getHeading().getDegrees() + 1) % 360));
                      getWwd().redraw();
                    }
                  }
                });
        timer.start();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public static void main(String[] args) {
    ApplicationTemplate.start("Rotated Sector", AppFrame.class);
  }
}
Пример #9
0
 /**
  * Adds or substitutes a named lat lon range (sector) surface shape.
  *
  * @param minlat minimum latitude in decimal degrees
  * @param minlon minimum longitude in decimal degrees
  * @param maxlat maximum latitude in decimal degrees
  * @param maxlon maximum longitude in decimal degrees
  * @param id the shape identifier
  */
 public void addSurfSect(double minlat, double minlon, double maxlat, double maxlon, String id) {
   SurfaceSector shape =
       new SurfaceSector(attr, Sector.fromDegrees(minlat, maxlat, minlon, maxlon));
   shape.setPathType(AVKey.LINEAR);
   shape.setHighlightAttributes(attrHigh);
   if (id != null) {
     shape.setValue(AVKey.HOVER_TEXT, id);
   }
   // set this layer as custom property of the shape
   shape.setValue(AVKey.LAYER, this);
   SurfaceShape old = shapesById.put(id, shape);
   if (old != null) {
     removeRenderable(old);
   }
   addRenderable(shape);
 }
Пример #10
0
    private Info[] buildFreeShapes() {
      double elevation = 10e3;
      ArrayList<Position> positions = new ArrayList<Position>();
      positions.add(
          new Position(Angle.fromDegrees(37.8484), Angle.fromDegrees(-119.9754), elevation));
      positions.add(
          new Position(Angle.fromDegrees(39.3540), Angle.fromDegrees(-110.1526), elevation));
      positions.add(
          new Position(Angle.fromDegrees(38.3540), Angle.fromDegrees(-100.1526), elevation));

      ArrayList<Position> positions2 = new ArrayList<Position>();
      positions2.add(new Position(Angle.fromDegrees(0), Angle.fromDegrees(-150), elevation));
      positions2.add(new Position(Angle.fromDegrees(25), Angle.fromDegrees(-75), elevation));
      positions2.add(new Position(Angle.fromDegrees(50), Angle.fromDegrees(0), elevation));

      ArrayList<Position> positions3 = new ArrayList<Position>();
      for (double lat = 42, lon = -100; lat <= 45; lat += .1, lon += .1) {
        positions3.add(new Position(Angle.fromDegrees(lat), Angle.fromDegrees(lon), elevation));
      }

      ArrayList<Position> positions4 = new ArrayList<Position>();
      positions4.add(new Position(Angle.fromDegrees(90), Angle.fromDegrees(-110), elevation));
      positions4.add(new Position(Angle.fromDegrees(-90), Angle.fromDegrees(-110), elevation));

      ArrayList<Position> positions5 = new ArrayList<Position>();
      for (int i = 0; i < 100; i++) {
        positions5.add(
            Position.fromDegrees(38.0 + i * 0.0001, 30.0 + i * 0.0001, 1000.0 + i * 5.0));
      }

      @SuppressWarnings({"UnnecessaryLocalVariable"})
      Info[] infos =
          new Info[] {
            new Info("Short Path", new Polyline(positions)),
            new Info("Long Path", new Polyline(positions2)),
            new Info("Incremental Path", new Polyline(positions3)),
            new Info("Vertical Path", new Polyline(positions4)),
            new Info("Small-segment Path", new Polyline(positions5)),
            new Info("Quad", new Quadrilateral(Sector.fromDegrees(38, 40, -104, -105), elevation)),
            new Info("None", null)
          };

      return infos;
    }
  protected static void legacyWmsRestoreStateToParams(
      RestorableSupport rs, RestorableSupport.StateObject context, AVList params) {
    // WMSTiledImageLayer has historically used a different format for storing LatLon and Sector
    // properties
    // in the restorable state XML documents. Although WMSTiledImageLayer no longer writes these
    // properties,
    // we must provide support for reading them here.
    Double lat = rs.getStateValueAsDouble(context, AVKey.LEVEL_ZERO_TILE_DELTA + ".Latitude");
    Double lon = rs.getStateValueAsDouble(context, AVKey.LEVEL_ZERO_TILE_DELTA + ".Longitude");
    if (lat != null && lon != null)
      params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, LatLon.fromDegrees(lat, lon));

    Double minLat = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MinLatitude");
    Double minLon = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MinLongitude");
    Double maxLat = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MaxLatitude");
    Double maxLon = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MaxLongitude");
    if (minLat != null && minLon != null && maxLat != null && maxLon != null)
      params.setValue(AVKey.SECTOR, Sector.fromDegrees(minLat, maxLat, minLon, maxLon));
  }
  public Sector[] subdivide(int div) {
    double dLat = this.deltaLat.degrees / div;
    double dLon = this.deltaLon.degrees / div;

    Sector[] sectors = new Sector[div * div];
    int idx = 0;
    for (int row = 0; row < div; row++) {
      for (int col = 0; col < div; col++) {
        sectors[idx++] =
            Sector.fromDegrees(
                this.minLatitude.degrees + dLat * row,
                this.minLatitude.degrees + dLat * row + dLat,
                this.minLongitude.degrees + dLon * col,
                this.minLongitude.degrees + dLon * col + dLon);
      }
    }

    return sectors;
  }
    public void doActionOnButton2() {
      ArrayList<LatLon> latlons = new ArrayList<LatLon>();

      latlons.add(LatLon.fromDegrees(45.50d, -123.3d));
      //            latlons.add( LatLon.fromDegrees( 45.51d, -123.3d ) );
      latlons.add(LatLon.fromDegrees(45.52d, -123.3d));
      //            latlons.add( LatLon.fromDegrees( 45.53d, -123.3d ) );
      latlons.add(LatLon.fromDegrees(45.54d, -123.3d));
      //            latlons.add( LatLon.fromDegrees( 45.55d, -123.3d ) );
      latlons.add(LatLon.fromDegrees(45.56d, -123.3d));
      //            latlons.add( LatLon.fromDegrees( 45.57d, -123.3d ) );
      latlons.add(LatLon.fromDegrees(45.58d, -123.3d));
      //            latlons.add( LatLon.fromDegrees( 45.59d, -123.3d ) );
      latlons.add(LatLon.fromDegrees(45.60d, -123.3d));

      Sector sector = Sector.fromDegrees(44d, 46d, -123d, -121d);
      //            Sector sector = Sector.boundingSector( latlons );

      double[] elevations = new double[latlons.size()];

      // request resolution of DTED2 (1degree / 3600 )
      double targetResolution = Angle.fromDegrees(1d).radians / 3600;

      double resolutionAchieved =
          this.wwd
              .getModel()
              .getGlobe()
              .getElevationModel()
              .getElevations(sector, latlons, targetResolution, elevations);

      StringBuffer sb = new StringBuffer();
      for (double e : elevations) {
        sb.append("\n").append(e);
      }
      sb.append("\nresolutionAchieved = ").append(resolutionAchieved);
      sb.append(", requested resolution = ").append(targetResolution);

      Logging.logger().info(sb.toString());
    }
  public static Sector boundingSector(LatLon pA, LatLon pB) {
    if (pA == null || pB == null) {
      throw new IllegalArgumentException("Positions List Is Null");
    }

    double minLat = pA.getLatitude().degrees;
    double minLon = pA.getLongitude().degrees;
    double maxLat = pA.getLatitude().degrees;
    double maxLon = pA.getLongitude().degrees;

    if (pB.getLatitude().degrees < minLat) {
      minLat = pB.getLatitude().degrees;
    } else if (pB.getLatitude().degrees > maxLat) {
      maxLat = pB.getLatitude().degrees;
    }

    if (pB.getLongitude().degrees < minLon) {
      minLon = pB.getLongitude().degrees;
    } else if (pB.getLongitude().degrees > maxLon) {
      maxLon = pB.getLongitude().degrees;
    }

    return Sector.fromDegrees(minLat, maxLat, minLon, maxLon);
  }
  /** Create the graticule grid elements */
  private void createUTMRenderables() {
    this.gridElements = new ArrayList<GridElement>();

    ArrayList<Position> positions = new ArrayList<Position>();

    // Generate meridians and zone labels
    int lon = -180;
    int zoneNumber = 1;
    int maxLat;
    for (int i = 0; i < 60; i++) {
      Angle longitude = Angle.fromDegrees(lon);
      // Meridian
      positions.clear();
      positions.add(new Position(Angle.fromDegrees(-80), longitude, 10e3));
      positions.add(new Position(Angle.fromDegrees(-60), longitude, 10e3));
      positions.add(new Position(Angle.fromDegrees(-30), longitude, 10e3));
      positions.add(new Position(Angle.ZERO, longitude, 10e3));
      positions.add(new Position(Angle.fromDegrees(30), longitude, 10e3));
      if (lon < 6 || lon > 36) {
        // 'regular' UTM meridians
        maxLat = 84;
        positions.add(new Position(Angle.fromDegrees(60), longitude, 10e3));
        positions.add(new Position(Angle.fromDegrees(maxLat), longitude, 10e3));
      } else {
        // Exceptions: shorter meridians around and north-east of Norway
        if (lon == 6) {
          maxLat = 56;
          positions.add(new Position(Angle.fromDegrees(maxLat), longitude, 10e3));
        } else {
          maxLat = 72;
          positions.add(new Position(Angle.fromDegrees(60), longitude, 10e3));
          positions.add(new Position(Angle.fromDegrees(maxLat), longitude, 10e3));
        }
      }
      Object polyline = createLineRenderable(positions, Polyline.GREAT_CIRCLE);
      Sector sector = Sector.fromDegrees(-80, maxLat, lon, lon);
      this.gridElements.add(new GridElement(sector, polyline, GridElement.TYPE_LINE));

      // Zone label
      GeographicText text =
          new UserFacingText(zoneNumber + "", Position.fromDegrees(0, lon + 3, 0));
      sector = Sector.fromDegrees(-90, 90, lon + 3, lon + 3);
      this.gridElements.add(new GridElement(sector, text, GridElement.TYPE_LONGITUDE_LABEL));

      // Increase longitude and zone number
      lon += 6;
      zoneNumber++;
    }

    // Generate special meridian segments for exceptions around and north-east of Norway
    for (int i = 0; i < 5; i++) {
      positions.clear();
      lon = specialMeridians[i][0];
      positions.add(
          new Position(Angle.fromDegrees(specialMeridians[i][1]), Angle.fromDegrees(lon), 10e3));
      positions.add(
          new Position(Angle.fromDegrees(specialMeridians[i][2]), Angle.fromDegrees(lon), 10e3));
      Object polyline = createLineRenderable(positions, Polyline.GREAT_CIRCLE);
      Sector sector = Sector.fromDegrees(specialMeridians[i][1], specialMeridians[i][2], lon, lon);
      this.gridElements.add(new GridElement(sector, polyline, GridElement.TYPE_LINE));
    }

    // Generate parallels - no exceptions
    int lat = -80;
    for (int i = 0; i < 21; i++) {
      Angle latitude = Angle.fromDegrees(lat);
      for (int j = 0; j < 4; j++) {
        // Each prallel is divided into four 90 degrees segments
        positions.clear();
        lon = -180 + j * 90;
        positions.add(new Position(latitude, Angle.fromDegrees(lon), 10e3));
        positions.add(new Position(latitude, Angle.fromDegrees(lon + 30), 10e3));
        positions.add(new Position(latitude, Angle.fromDegrees(lon + 60), 10e3));
        positions.add(new Position(latitude, Angle.fromDegrees(lon + 90), 10e3));
        Object polyline = createLineRenderable(positions, Polyline.LINEAR);
        Sector sector = Sector.fromDegrees(lat, lat, lon, lon + 90);
        this.gridElements.add(new GridElement(sector, polyline, GridElement.TYPE_LINE));
      }
      // Latitude band label
      if (i < 20) {
        GeographicText text =
            new UserFacingText(latBands.charAt(i) + "", Position.fromDegrees(lat + 4, 0, 0));
        Sector sector = Sector.fromDegrees(lat + 4, lat + 4, -180, 180);
        this.gridElements.add(new GridElement(sector, text, GridElement.TYPE_LATITUDE_LABEL));
      }

      // Increase latitude
      lat += lat < 72 ? 8 : 12;
    }
  }
    public ImageFormatter serviceRequest(IMapRequest req) throws IOException, WMSServiceException {
      int reqWidth = 512;
      int reqHeight = 512;

      this.threadId = Thread.currentThread().getId();

      MapSource myMapSource = CompoundImageryGenerator.this.mapSource;
      Logging.logger()
          .info("START CompoundServiceInstance :: serviceRequest( " + myMapSource.getName() + ")");
      try {
        Integer bgColor = CompoundImageryGenerator.DEFAULT_MISSING_DATA_COLOR;
        String bgColorStr = req.getBGColor();
        if (bgColorStr != null && 0 < bgColorStr.length()) {
          try {
            bgColor = Integer.parseInt(bgColorStr, 16);
          } catch (NumberFormatException ex) {
            Logging.logger()
                .severe("Unable to parse BGCOLOR in get imagery request: " + ex.getMessage());
            bgColor = CompoundImageryGenerator.DEFAULT_MISSING_DATA_COLOR;
          }
        } else
          Logging.logger()
              .severe(
                  "BGCOLOR was not specified in the getImagery request: using default " + bgColor);

        req.setBGColor(bgColor.toString());

        reqWidth = (req.getWidth() > 0) ? req.getWidth() : 512;
        req.setWidth(reqWidth);

        reqHeight = (req.getHeight() > 0) ? req.getHeight() : 512;
        req.setHeight(reqHeight);

        Sector reqSector =
            Sector.fromDegrees(
                req.getBBoxYMin(), req.getBBoxYMax(), req.getBBoxXMin(), req.getBBoxXMax());

        double reqPixelSize = reqSector.getDeltaLatDegrees() / reqHeight;
        MapSource reqMapSource = null;

        for (Iterator<MapSource> iterator = myMapSource.getChildren(); iterator.hasNext(); ) {
          MapSource ms = iterator.next();
          MapGenerator gen = (null != ms) ? ms.getMapGenerator() : null;
          if (null == gen) {
            Logging.logger()
                .severe("child mapSource `" + ms.getName() + "` has no associated map generator!");
            continue;
          }
          Sector bbox = gen.getBBox();
          Logging.logger()
              .info(
                  "found child mapSource `" + ms.getName() + "` with generator: " + gen.toString());
          if (!reqSector.intersects(bbox)) {
            Logging.logger()
                .info(
                    "child mapSource`"
                        + ms.getName()
                        + "`: out of coverage, skipping"
                        + bbox.toString());
            continue;
          }

          double genPixelSize = gen.getPixelSize();
          reqMapSource =
              ms; // assumes layers are configured in order according to resolutions from low to
          // high
          Logging.logger()
              .info(
                  "Comparing texel sizes: req = "
                      + reqPixelSize
                      + " , layer's = "
                      + gen.getPixelSize());
          if (reqPixelSize >= genPixelSize) {
            // satisfactory generator found
            break;
          }
        }

        ImageFormatter fmt = null;
        if (null != reqMapSource) {
          try {
            MapGenerator gen = reqMapSource.getMapGenerator();
            Logging.logger()
                .info(
                    "`"
                        + reqMapSource.getName()
                        + "` is executing request; req texel size = "
                        + reqPixelSize
                        + " where layer's texel size = "
                        + gen.getPixelSize());
            fmt = gen.getServiceInstance().serviceRequest(req);
          } catch (Exception ex) {
            Logging.logger().severe("Error while accessing a child mapSource: " + ex.getMessage());
          }
        }

        if (null == fmt) {
          Logging.logger().info("CompoundImageryGenerator will return an empty transparent image");
          fmt = createEmptyImage(req.getWidth(), req.getHeight(), new Color(bgColor));
        }
        return fmt;
      } catch (Exception ex) {
        String msg = Logging.getMessage("WMS.RequestFailed", ex.getMessage());
        Logging.logger().log(java.util.logging.Level.SEVERE, msg, ex);
        throw new WMSServiceException(msg);
      }
    }