Changeset 337

Show
Ignore:
Timestamp:
08/21/08 04:03:40 (3 months ago)
Author:
arneke
Message:

This commit makes GeoWebCache nearly SRS agnostic and compatible with Ionic WMS servers (limited testing). The XML configuration still needs to be updated.

Location:
trunk/geowebcache/src
Files:
24 modified
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/geowebcache/src/main/java/org/geowebcache/GeoWebCacheDispatcher.java

    r323 r337  
    2121import java.io.InputStream; 
    2222import java.io.OutputStream; 
    23 import java.net.URL; 
    2423import java.util.HashMap; 
    2524import java.util.Iterator; 
     
    3938import org.geowebcache.service.Service; 
    4039import org.geowebcache.tile.Tile; 
    41 import org.springframework.core.io.Resource; 
    4240import org.springframework.web.context.WebApplicationContext; 
    4341import org.springframework.web.servlet.ModelAndView; 
  • trunk/geowebcache/src/main/java/org/geowebcache/demo/Demo.java

    r335 r337  
    99 
    1010import org.geowebcache.GeoWebCacheException; 
     11import org.geowebcache.layer.Grid; 
    1112import org.geowebcache.layer.SRS; 
    1213import org.geowebcache.layer.TileLayer; 
     
    3839            } 
    3940 
     41            SRS srs = null; 
    4042            if (srsStr != null) { 
    41                 if (!layer.supportsProjection(new SRS(srsStr))) { 
    42                     throw new GeoWebCacheException("Unsupported SRS " + srsStr); 
    43                 } 
     43                srs = SRS.getSRS(srsStr); 
    4444            } else { 
    45                 srsStr = SRS.getEPSG900913().toString(); 
     45                srs = SRS.getEPSG900913(); 
    4646            } 
    47             page = generateHTML(layer, srsStr, formatStr); 
     47            page = generateHTML(layer, srs, formatStr); 
    4848 
    4949        } else { 
     
    105105    } 
    106106     
    107     private static String generateHTML(TileLayer layer, String srsStr, String formatStr)  
     107    private static String generateHTML(TileLayer layer, SRS srs, String formatStr)  
    108108    throws GeoWebCacheException { 
    109109        String layerName = layer.getName(); 
    110110        String mime = layer.getDefaultMimeType().getFormat(); 
    111         int srsIdx = layer.getSRSIndex(new SRS(srsStr)); 
     111        //int srsIdx = layer.getSRSIndex(SRS.getSRS(srsStr)); 
    112112         
    113113        BBOX bbox = null; 
    114114        BBOX zoomBounds = null; 
    115115        String res = ""; 
    116         if(srsStr.equalsIgnoreCase("EPSG:900913")) { 
     116        Grid grid = layer.getGrid(srs); 
     117         
     118        if(srs.getNumber() == 900913) { 
    117119            //res = "resolutions: [156543.03,78271.52,39135.76,19567.88,9783.94,4891.97],\n"; 
    118120            res = "resolutions: " + getEPSG900913Resolutions() + ",\n"; 
    119121            bbox = new BBOX(-20037508.34,-20037508.34,20037508.34,20037508.34); 
    120         } else if(srsStr.equalsIgnoreCase("EPSG:4326")) { 
     122        } else if(srs.getNumber() == 4326) { 
    121123            res = "resolutions: " + getEPSG4326Resolutions() + ",\n"; 
    122124            bbox = new BBOX(-180.0,-90.0,180.0,90.0); 
     
    131133        //    zoomBounds = bbox; 
    132134        //} 
    133         zoomBounds = layer.getBounds(srsIdx); 
     135        zoomBounds = grid.getBounds(); 
    134136         
    135137         
     
    137139            "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>\n" 
    138140            +"<meta http-equiv=\"imagetoolbar\" content=\"no\">\n" 
    139             +"<title>"+layerName+" "+srsStr+" "+mime+"</tile>\n" 
     141            +"<title>"+layerName+" "+srs.toString()+" "+mime+"</tile>\n" 
    140142            +"<style type=\"text/css\">\n" 
    141143            +"body { font-family: sans-serif; font-weight: bold; font-size: .8em; }\n" 
     
    152154            +"var mapOptions = { \n" 
    153155            + res 
    154             +"projection: new OpenLayers.Projection('"+srsStr+"'),\n" 
     156            +"projection: new OpenLayers.Projection('"+srs.toString()+"'),\n" 
    155157            +"maxExtent: new OpenLayers.Bounds("+bbox.toString()+") \n};\n" 
    156158            +"map = new OpenLayers.Map('map', mapOptions );\n" 
  • trunk/geowebcache/src/main/java/org/geowebcache/layer/Grid.java

    r320 r337  
    1717package org.geowebcache.layer; 
    1818 
     19import java.util.List; 
     20 
     21import org.geowebcache.GeoWebCacheException; 
    1922import org.geowebcache.util.wms.BBOX; 
    2023 
    2124/** 
    2225 * Grid Class - Each TileLayer keeps a list of Grid Objects 
    23  *  
    24  *  
    2526 */ 
    2627 
    2728public class Grid { 
    28     private BBOX bounds = null; 
    29  
    30     private BBOX gridbounds = null; 
    31  
    32     private SRS projection = null; 
    33  
    34     public Grid(SRS projection, BBOX bounds, BBOX gridBounds) { 
    35         this.projection = projection; 
     29    private SRS gridSRS = null; 
     30     
     31    protected BBOX bounds = null; 
     32     
     33    protected BBOX gridBounds = null; 
     34     
     35    protected double[] resolutions = null; 
     36     
     37    private volatile transient GridCalculator gridCalculator; 
     38     
     39    private volatile int zoomStart = 0; 
     40     
     41    private volatile int zoomStop = 25; 
     42     
     43    public Grid(SRS srs, BBOX bounds, BBOX gridBounds, double[] resolutions) { 
     44        this.gridSRS = srs; 
    3645        this.bounds = bounds; 
    37         this.gridbounds = gridBounds; 
     46        this.gridBounds = gridBounds; 
     47        this.resolutions = resolutions; 
    3848    } 
    3949     
     
    5767     */ 
    5868    public void setGridBounds(BBOX gridbounds) { 
    59         this.gridbounds = gridbounds; 
     69        this.gridBounds = gridbounds; 
    6070    } 
    6171    /** 
     
    6575    public void setGridBounds(String gridbounds) { 
    6676 
    67         this.gridbounds = new BBOX(gridbounds); 
     77        this.gridBounds = new BBOX(gridbounds); 
    6878    } 
    6979    /** 
     
    7181     * @param projection - SRS 
    7282     */ 
    73     public void setProjection(SRS projection) { 
    74         this.projection = projection; 
     83    public void setSRS(SRS srs) { 
     84        this.gridSRS = srs; 
    7585    } 
    7686    /** 
     
    7888     * @return 
    7989     */ 
    80     public SRS getProjection() { 
    81         return this.projection; 
     90    public SRS getSRS() { 
     91        return this.gridSRS; 
    8292    } 
    8393    /** 
     
    93103     */ 
    94104    public BBOX getGridBounds() { 
    95         return this.gridbounds; 
     105        return this.gridBounds; 
     106    } 
     107     
     108    public int getZoomStart() { 
     109        return this.zoomStart; 
     110    } 
     111     
     112    public int getZoomStop() { 
     113        return this.zoomStop; 
     114    } 
     115     
     116    public void setResolutions(double[] resolutions) { 
     117        this.resolutions = resolutions; 
     118    } 
     119     
     120    public double[] getResolutions() throws GeoWebCacheException { 
     121        return getGridCalculator().getResolutions(); 
     122    } 
     123     
     124    public GridCalculator getGridCalculator() throws GeoWebCacheException { 
     125        GridCalculator ret = gridCalculator; 
     126        if (ret == null) { 
     127            synchronized (this) { 
     128                ret = gridCalculator; 
     129                if (gridCalculator == null) { 
     130                    gridCalculator = ret = initGridCalculator(); 
     131                } 
     132            } 
     133        } 
     134        return ret; 
    96135    } 
    97136 
     137    private GridCalculator initGridCalculator() throws GeoWebCacheException { 
     138        return new GridCalculator(this); 
     139    } 
    98140} 
  • trunk/geowebcache/src/main/java/org/geowebcache/layer/GridCalculator.java

    r322 r337  
    1515 * @author Arne Kepp, The Open Planning Project, Copyright 2008 
    1616 */ 
    17 package org.geowebcache.util.wms; 
    18  
    19 import java.util.Arrays; 
     17package org.geowebcache.layer; 
    2018 
    2119import org.apache.commons.logging.Log; 
    2220import org.apache.commons.logging.LogFactory; 
    2321import org.geowebcache.GeoWebCacheException; 
    24 import org.geowebcache.layer.BadTileException; 
    25 import org.geowebcache.layer.OutOfBoundsException; 
    26 import org.geowebcache.service.ServiceException; 
     22import org.geowebcache.util.wms.BBOX; 
    2723 
    2824public class GridCalculator { 
    29     private static Log log = LogFactory 
    30             .getLog(org.geowebcache.util.wms.GridCalculator.class); 
    31  
    32     private BBOX gridBounds = null; 
    33  
     25    private static Log log = LogFactory.getLog(org.geowebcache.layer.GridCalculator.class); 
     26 
     27    // We may want to change this later 
     28    private static final int TILEPIXELS = 256; 
     29     
     30    //private BBOX gridBounds = null; 
     31    private Grid grid; 
     32     
     33    public final static double[] RESOLUTIONS4326 =  
     34        GridCalculator.getResolutionArray(180.0, TILEPIXELS, 26); 
     35     
     36    public final static double[] RESOLUTIONS900913 =  
     37        GridCalculator.getResolutionArray(20037508.34*2,TILEPIXELS, 26); 
     38     
    3439    // The following are the width of the actual layer 
    3540    private double gridWidth; 
    3641 
    3742    private double gridHeight; 
    38  
     43     
     44    // This is what the grid looks like at zoomlevel 0 
     45    private int gridX = -1; 
     46     
     47    private int gridY = -1; 
     48     
     49    private double[] resolutions; 
     50     
    3951    // The following are for a tile, zoomed out all the way 
    40     private double maxTileWidth; 
    41  
    42     private double maxTileHeight; 
     52    //private double maxTileWidth; 
     53 
     54    //private double maxTileHeight; 
    4355 
    4456    private int zoomStart; 
    4557 
    4658    private int zoomStop; 
    47  
    48     //private int metaWidth; 
    49  
    50     //private int metaHeight; 
    51  
    52     // Used for unprojected profiles 
    53     private int gridConstant; 
    5459     
    5560    // Special treatment of "zoomed out tile" for EPSG 4326 
    56     private boolean worldBoundsCoverTwoTiles = false; 
     61    //private boolean worldBoundsCoverTwoTiles = false; 
    5762 
    5863    private int[] zoomedOutGridLoc = null; 
     
    6065    private int[][] boundsGridLevels = null; 
    6166 
    62     // TODO this code does not handle coordinate systems where the base 
    63     // height 
    64     // is bigger than the width 
    65     // private double layerHeight; 
    66  
    67     public GridCalculator(BBOX gridBounds, BBOX layerBounds, int zoomStart, 
    68             int zoomStop, int metaWidth, int metaHeight, double maxTileWidth, 
    69             double maxTileHeight) { 
    70  
    71         this.gridBounds = gridBounds; 
    72         this.zoomStart = zoomStart; 
    73         this.zoomStop = zoomStop; 
     67    public GridCalculator(Grid grid) throws GeoWebCacheException { 
     68 
     69        this.grid = grid; 
     70        this.zoomStart = 0; 
     71        this.zoomStop = 25; 
    7472        //this.metaWidth = metaWidth; 
    7573        //this.metaHeight = metaHeight; 
    7674 
     75        this.resolutions = grid.resolutions; 
     76         
     77        //BBOX layerBounds = grid.bounds; 
     78        BBOX gridBounds = grid.gridBounds; 
     79         
    7780        // Calculate 
    7881        gridWidth = gridBounds.coords[2] - gridBounds.coords[0]; 
    7982        gridHeight = gridBounds.coords[3] - gridBounds.coords[1]; 
    8083 
    81         this.maxTileWidth = maxTileWidth; 
    82         this.maxTileHeight = maxTileHeight; 
    83         this.gridConstant = (int) Math.round(gridWidth / gridHeight - 1.0); 
    84  
    85         boundsGridLevels = calculateGridBounds(layerBounds); 
    86          
    87         if(     this.gridConstant > 0  
    88                 && layerBounds.coords[0] < 0.0  
    89                 && layerBounds.coords[2] > 0.0) { 
    90             worldBoundsCoverTwoTiles = true; 
     84        // Figure out the rest 
     85        determineGrid(); 
     86         
     87        boundsGridLevels = calculateGridBounds(grid.bounds); 
     88    } 
     89     
     90    private void determineGrid() throws GeoWebCacheException { 
     91        if(grid.resolutions == null) { 
     92            // Figure out the approriate resolutions 
     93             
     94            double ratio = gridWidth / gridHeight; 
     95             
     96            // Allow 2.5% slack 
     97            if(Math.abs(ratio - 1.0) < 0.025) { 
     98                gridX = 1; 
     99                gridY = 1; 
     100            } 
     101             
     102            // Otherwise we'll try to expand it to an integer grid, 
     103            // failing that we'll just increase the smaller bounds 
     104            // to make the box square 
     105            if(ratio > 1.0) { 
     106                // Wider than tall 
     107                if(Math.abs(ratio - Math.round(ratio)) < 0.025) { 
     108                    gridY = 1; 
     109                    gridX = (int) Math.round(ratio); 
     110                } else { 
     111                    // I give up, expanding Y bounds 
     112                    gridX = gridY = 1; 
     113                    gridHeight = gridWidth; 
     114                } 
     115                determineResolutions(); 
     116            } else { 
     117                // Taller than wide 
     118                ratio = gridHeight / gridWidth; 
     119                if(Math.abs(ratio - Math.round(ratio)) < 0.025) { 
     120                    gridY = (int) Math.round(ratio); 
     121                    gridX = 1; 
     122                } else { 
     123                    // I give up, expanding X bounds 
     124                    gridX = gridY = 1; 
     125                    gridWidth = gridHeight; 
     126                } 
     127                determineResolutions(); 
     128            } 
     129        } else { 
     130            double denominator = grid.resolutions[0]* GridCalculator.TILEPIXELS; 
     131            this.gridX = (int) Math.round(gridWidth / denominator); 
     132            this.gridY = (int) Math.round(gridHeight / denominator); 
     133        } 
     134    } 
     135     
     136    private void determineResolutions() throws GeoWebCacheException { 
     137        double baseResolution; 
     138         
     139        // We use the smaller one  
     140        if(gridY == 1) { 
     141            baseResolution = gridHeight / GridCalculator.TILEPIXELS; 
     142        } else if (gridX == 1) { 
     143            baseResolution = gridWidth / GridCalculator.TILEPIXELS; 
     144        } else { 
     145            throw new GeoWebCacheException("Unable to find height or width to calculate resolution array."); 
     146        } 
     147         
     148        this.resolutions = new double[this.zoomStop - this.zoomStart + 1]; 
     149        for(int i=this.zoomStart; i<= this.zoomStop; i++) { 
     150            this.resolutions[i] = baseResolution; 
     151            baseResolution = baseResolution / 2; 
    91152        } 
    92153    } 
    93154 
    94155    private int[][] calculateGridBounds(BBOX layerBounds) { 
     156        BBOX gridBounds = grid.gridBounds; 
     157         
    95158        // We'll just waste a few bytes, for cheap lookups 
    96159        int[][] gridLevels = new int[zoomStop + 1][4]; 
    97160 
    98         double tileWidth = maxTileWidth; 
    99         double tileHeight = maxTileHeight; 
    100  
    101         int tileCountX = (int) Math.round(gridWidth / maxTileWidth); 
    102         int tileCountY = (int) Math.round(gridHeight / maxTileHeight); 
     161        //int tileCountX = (int) Math.round(gridWidth / resolutions[0]); 
     162        //int tileCountY = (int) Math.round(gridHeight / resolutions[0]); 
    103163 
    104164        //int metaLarger = (metaHeight > metaWidth) ? metaHeight : metaWidth; 
     
    111171        for (int level = 0; level <= zoomStop; level++) { 
    112172            //System.out.println("--- Level "+level+"----"); 
    113              
     173            double tileDelta = resolutions[level] * GridCalculator.TILEPIXELS; 
    114174             
    115175            // Min X 
    116             rawNumber[0] = (layerBounds.coords[0] - gridBounds.coords[0]) / tileWidth; 
     176            rawNumber[0] = (layerBounds.coords[0] - gridBounds.coords[0]) / tileDelta; 
    117177            gridLevels[level][0] = (int) Math.floor(rawNumber[0]); 
    118178             
    119179            // Min Y 
    120             rawNumber[1] = (layerBounds.coords[1] - gridBounds.coords[1]) / tileHeight; 
     180            rawNumber[1] = (layerBounds.coords[1] - gridBounds.coords[1]) / tileDelta; 
    121181            gridLevels[level][1] = (int) Math.floor(rawNumber[1]); 
    122182             
     
    125185             
    126186            // Max X 
    127             rawNumber[2] = (layerBounds.coords[2] - gridBounds.coords[0] - 0.0001) / tileWidth; 
     187            rawNumber[2] = (layerBounds.coords[2] - gridBounds.coords[0] - 0.00001) / tileDelta; 
    128188            gridLevels[level][2] = (int) Math.floor(rawNumber[2]); 
    129189             
    130190            // Max Y 
    131             rawNumber[3] = (layerBounds.coords[3] - gridBounds.coords[1] - 0.0001) / tileHeight; 
     191            rawNumber[3] = (layerBounds.coords[3] - gridBounds.coords[1] - 0.00001) / tileDelta; 
    132192            gridLevels[level][3] = (int) Math.floor(rawNumber[3]); 
    133193 
     
    139199            // + metaLarger); 
    140200 
    141             // Adjust for metatiling if appropriate 
    142 //            if (tileCountX > metaLarger || tileCountY > metaLarger) { 
    143 //                // Round down 
    144 //                gridLevels[level][0] = gridLevels[level][0] 
    145 //                        - (gridLevels[level][0] % metaWidth); 
    146 //                // Round down 
    147 //                gridLevels[level][1] = gridLevels[level][1] 
    148 //                        - (gridLevels[level][1] % metaHeight); 
    149 //                // Naive round up 
    150 //                gridLevels[level][2] = gridLevels[level][2] 
    151 //                        - (gridLevels[level][2] % metaWidth) + (metaWidth - 1); 
    152 //                // Naive round up 
    153 //                gridLevels[level][3] = gridLevels[level][3] 
    154 //                        - (gridLevels[level][3] % metaHeight) 
    155 //                        + (metaHeight - 1); 
    156 // 
    157 //                //System.out.println("postAdjust: " + 
    158 //                // Arrays.toString(gridLevels[level])); 
    159 // 
    160 //                // Fix for naive round ups, imagine applying a 3x3 metatile to a 
    161 //                // 4x4 grid 
    162 //                if (gridLevels[level][2] >= tileCountX) { 
    163 //                    gridLevels[level][2] = tileCountX - 1; 
    164 //                } 
    165 //                if (gridLevels[level][3] >= tileCountY) { 
    166 //                    gridLevels[level][3] = tileCountY - 1; 
    167 //                } 
    168 //                //System.out.println("postFix: " + 
    169 //                // Arrays.toString(gridLevels[level])); 
    170 //            } 
    171  
    172             // For the next round 
    173             tileWidth = tileWidth / 2; 
    174             tileHeight = tileHeight / 2; 
    175  
    176             tileCountX = tileCountX * 2; 
    177             tileCountY = tileCountY * 2; 
     201            //tileCountX = tileCountX * 2; 
     202            //tileCountY = tileCountY * 2; 
    178203        } 
    179204        return gridLevels; 
     
    210235        double reqTileWidth = tileBounds.coords[2] - tileBounds.coords[0]; 
    211236 
    212         double zoomLevel = Math.log(gridWidth / reqTileWidth) / Math.log(2); 
    213          
    214         long roundedZoomLevel = Math.round(zoomLevel); 
    215         if(Math.abs(zoomLevel - (double) roundedZoomLevel) > 0.05) { 
    216             throw new BadTileException("The bounds result in a zoom level of "+zoomLevel+ 
    217                         ", expected something within 0.05 of an integer, check " + tileBounds.toString()); 
    218         } 
     237        //Arrays.binarySearch(a, key) 
     238        //double zoomLevel = Math.log(gridWidth / reqTileWidth) / Math.log(2); 
     239         
     240        //long roundedZoomLevel = Math.round(zoomLevel); 
     241 
    219242         
    220243        // (Z) Zoom level 
    221244        // For EPSG 4326, reqTileWidth = 0.087 log(4096) / log(2) - 1; -> 11 
    222         retVals[2] = (int) roundedZoomLevel 
    223                 - gridConstant; 
    224  
    225         double tileWidth = gridWidth / (Math.pow(2, retVals[2] + gridConstant)); 
    226  
     245        retVals[2] = this.binarySearchForResolution(reqTileWidth / GridCalculator.TILEPIXELS); 
     246 
     247        double tileWidth = resolutions[retVals[2]] * GridCalculator.TILEPIXELS; 
     248 
     249        // Get the bounds 
     250        BBOX layerBounds = grid.bounds; 
     251        BBOX gridBounds = grid.gridBounds; 
     252         
    227253        // X 
    228254        double xdiff = tileBounds.coords[0] - gridBounds.coords[0]; 
     
    290316     */ 
    291317    public BBOX bboxFromGridLocation(int[] gridLoc) { 
    292         double tileWidth = gridWidth / Math.pow(2, gridLoc[2] + gridConstant); 
    293  
     318        //double tileWidth = gridWidth / Math.pow(2, gridLoc[2] + gridConstant); 
     319        double tileWidth = resolutions[gridLoc[2]] * GridCalculator.TILEPIXELS; 
     320         
     321        BBOX gridBounds = grid.gridBounds; 
     322         
    294323        return new BBOX(gridBounds.coords[0] + tileWidth * gridLoc[0], 
    295324                gridBounds.coords[1] + tileWidth * gridLoc[1], 
     
    309338 
    310339    public BBOX bboxFromGridBounds(int[] gridLocBounds) { 
    311         double tileWidth = gridWidth 
    312                 / Math.pow(2, gridLocBounds[4] + gridConstant); 
    313  
     340        //double tileWidth = gridWidth 
     341        //        / Math.pow(2, gridLocBounds[4] + gridConstant); 
     342         
     343        double tileWidth = GridCalculator.TILEPIXELS * resolutions[gridLocBounds[4]]; 
     344         
     345        BBOX gridBounds = grid.gridBounds; 
     346         
    314347        return new BBOX(gridBounds.coords[0] + tileWidth * gridLocBounds[0], 
    315348                gridBounds.coords[1] + tileWidth * gridLocBounds[1], 
     
    388421            return zoomedOutGridLoc; 
    389422        } 
    390  
     423         
     424        //TODO fix negative number to return more than one top tile 
     425         
    391426        // Exception for EPSG:4326, which can zoom out to two tiles 
    392         if (worldBoundsCoverTwoTiles) { 
     427        if (gridX == 2 && gridY == 1) { 
    393428            zoomedOutGridLoc = new int[3]; 
    394429            zoomedOutGridLoc[0] = -1; 
     
    416451    } 
    417452     
    418     public double[] getResolutions(int widthPixels) { 
    419         double[] ret = new double[zoomStop - zoomStart + 1]; 
    420         double tileWidth = maxTileWidth / widthPixels; 
    421          
    422         for(int i=0; i<ret.length; i++) { 
    423             ret[i] = tileWidth; 
    424             tileWidth = tileWidth / 2; 
    425         } 
    426          
    427         return ret; 
    428     } 
     453    public double[] getResolutions() { 
     454