Project

General

Profile

1
/*
2
Author:       Mike Adair mike.adairATccrs.nrcan.gc.ca
3
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
4
$Id$
5
*/
6

    
7

    
8
var Rearth = 6378137.0;                 // Radius of the earth (sphere); different from Proj value?
9
var degToMeter = Rearth*2*Math.PI/360;
10
//var mbScaleFactor = 72 * 39.3701;   //PixelsPerInch*InchesPerMapUnit; magic numbers 
11
                                    //need to determine magic number for lat/lon
12
var mbScaleFactor = 3571.428   //magic number, for Geoserver SLD compatibility
13
                               // 1/0.00028 (0.28 mm "is a common actual size for
14
                               // contemporary display" as written in the SLD specification ...
15

    
16
/*
17
 * FD 2005/03/04 : minScale et maxScale
18
 * DGR : should be in config ?
19
 */
20
var minScale = 1000;
21
var maxScale = 200000;
22

    
23
/**
24
 * A tool designed to handle geography calculations for widgets which render
25
 * the model in 2D.
26
 * Use of this tool requires that it's model implements get/setWindowHeight/Width
27
 * methods.
28
 * Encapsulates all geography and image size aspects of a geographic object 
29
 * displayed in a rectangular area on the screen.
30
 * All coordinates are handled as points which is a 2 element array, where x is 
31
 * the first element and y is the second. Coordinates are either pixel and lixel
32
 * (pl) relative to the top left of the extent or projection XY values (xy). 
33
 *
34
 * @constructor
35
 * @param model       the model document that this extent represents
36
 * @param initialRes  (optional) if supplied the extent resolution will be set to this value
37
 */
38
function Extent( model, initialRes ) {
39
  this.model = model;
40
  this.size = new Array();
41
  this.res = new Array();
42
  this.zoomBy = 4;
43
  this.id = model.id + "_MbExtent" + mbIds.getId();
44

    
45
  /**
46
   * Returns the XY center of this extent
47
   * @return  array of XY for th center of the extent
48
   */
49
  this.getCenter = function() {
50
    return new Array((this.ul[0]+this.lr[0])/2, (this.ul[1]+this.lr[1])/2);
51
  }
52

    
53
  /**
54
   * Returns XY coordinates for given pixel line coords w.r.t. top left corner
55
   * @param pl   pixel line in extent to calculate
56
   * @return     point array of XY coordinates
57
   */
58
  this.getXY = function(pl) {
59
    var x = this.ul[0]+pl[0]*this.res[0];
60
    var y = this.ul[1]- pl[1]*this.res[1];
61
    return new Array(x,y);
62
  }
63

    
64
  /**
65
   * Returns pixel/line coordinates for given XY projection coords
66
   * @param xy   projection XY coordinate to calculate
67
   * @return     point array of pxiel/line coordinates w.r.t. top left corner
68
   */
69
  this.getPL = function(xy) {
70
    var p = Math.floor( (xy[0]-this.ul[0])/this.res[0] );
71
    var l = Math.floor( (this.ul[1]-xy[1])/this.res[1] );
72
    return new Array(p,l);
73
  }
74

    
75
  /**
76
   * Adjust the extent so that it is centered at given XY coordinate with given
77
   * resolution.  Extent width and height remain fixed.  Optionally check to 
78
   * ensure that it doesn't go beyond available extent.
79
   *
80
   * @param center      projection XY coordinate to center at
81
   * @param newres      resolution to display at
82
   * @param limitExtent ensure that the extent doesn't go beyond available bbox (TBD: not complete/tested)
83
   * @return            none
84
   */
85
  this.centerAt = function(center, newres, limitExtent) {
86
    var half = new Array(this.size[0]/2, this.size[1]/2);
87
/*
88
 * FD 2005/03/04 : respect de minScale et maxScale
89
 * DGR : scale constraints
90
    var nRmin= minScale/mbScaleFactor;
91
    var nRmax= maxScale/mbScaleFactor;
92
    if (newres < nRmin) {
93
      newres= nRmin ;
94
    }
95
    if (newres > nRmax) {
96
      newres= nRmax ;
97
    }
98
 */
99
    this.lr = new Array(center[0]+half[0]*newres, center[1]-half[1]*newres);
100
    this.ul = new Array(center[0]-half[0]*newres, center[1]+half[1]*newres);
101

    
102
    //make sure the request doesn't extend beyond the available model
103
    //TBD this block not tested
104
    if ( limitExtent ) {
105
      var xShift = 0;
106
      if ( this.lr[0] > ContextExtent.lr[0] ) xShift = ContextExtent.lr[0] - this.lr[0];
107
      if ( this.ul[0] < ContextExtent.ul[0] ) xShift = ContextExtent.ul[0] - this.ul[0];
108
      this.lr[0] += xShift;
109
      this.ul[0] += xShift;
110

    
111
      var yShift = 0;
112
      if ( this.lr[1] < ContextExtent.lr[1] ) yShift = ContextExtent.lr[1] - this.lr[1];
113
      if ( this.ul[1] > ContextExtent.ul[1] ) yShift = ContextExtent.ul[1] - this.ul[1];
114
      this.lr[1] += yShift;
115
      this.ul[1] += yShift;
116
    }
117

    
118
    this.model.setBoundingBox( new Array(this.ul[0], this.lr[1], this.lr[0], this.ul[1]) );
119
    //this.setResolution(size);
120
    this.setSize(newres);
121
  }
122

    
123
  /**
124
   * Adjust the extent to the given bbox.  Resolution is recalculated. 
125
   * Extent width and height remain fixed.  
126
   * @param ul      upper left coordinate of bbox in XY projection coords
127
   * @param lr      lower right coordinate of bbox in XY projection coords
128
   */
129
  this.zoomToBox = function(ul, lr) {    //pass in xy
130
    var center = new Array((ul[0]+lr[0])/2, (ul[1]+lr[1])/2);
131
    newres = Math.max((lr[0] - ul[0])/this.size[0], (ul[1] - lr[1])/this.size[1]);
132
    this.centerAt( center, newres );
133
  } 
134

    
135
/**
136
   * Adjust the width and height to that bbox is displayed at specified resolution
137
   * @param res   the resolution to be set
138
   */
139
  //TBD update the model doc
140
  this.setSize = function(res) {     //pass in a resolution and width, height are recalculated
141
    this.res[0] = this.res[1] = res;
142
    this.size[0] = (this.lr[0] - this.ul[0])/this.res[0];
143
    this.size[1] = (this.ul[1] - this.lr[1])/this.res[1];
144
    this.width = Math.ceil(this.size[0]);
145
    this.height = Math.ceil(this.size[1]);
146
  }
147

    
148
  /**
149
   * Adjust the resolution so the bbox fits in the specified width and height
150
   * @param size   width, height array passed in
151
   */
152
  //TBD update the model doc
153
  this.setResolution = function(size) {    //pass in a width, height and res is recalculated
154
    this.size[0] = size[0];
155
    this.size[1] = size[1];
156
    this.res[0] = (this.lr[0] - this.ul[0])/this.size[0];
157
    this.res[1] = (this.ul[1] - this.lr[1])/this.size[1];
158
    this.width = Math.ceil(this.size[0]);
159
    this.height = Math.ceil(this.size[1]);
160
  }
161

    
162
  /**
163
   * Returns the map scale denominator for the current extent resolution
164
   * @return map scale denominator
165
   */
166
  this.getScale = function() {
167
    var pixRes = null;
168
    switch(this.model.getSRS()) {
169
      case "EPSG:4326":				//all projection codes in degrees
170
      case "EPSG:4269":				
171
        pixRes = this.res[0]*degToMeter;
172
        break;
173
      default:                //all projection codes in meters
174
        pixRes = this.res[0];
175
        break;
176
    }
177
    return mbScaleFactor*pixRes;
178
  }
179

    
180
  /**
181
   * Sets the model's resolution from mapScale input value.  The map center 
182
   * remains fixed.
183
   * @param scale   map scale denominator value
184
   */
185
  this.setScale = function(scale) {
186
    var newRes = null;
187
/*
188
 * FD 2005/03/04
189
 * On contraint l'echelle min et max de l'application.
190
 * A externaliser dans le fichier de config de l'application ;-)
191
 * DGR : should be in the config
192
    if (scale < minScale) {
193
      scale= minScale ;
194
    }
195
    if (scale > maxScale) {
196
      scale= maxScale ;
197
    }
198
 */
199
    switch(this.model.getSRS()) {
200
      case "EPSG:4326":				//all projection codes in degrees
201
      case "EPSG:4269":				
202
        //convert to resolution in degrees
203
        newRes = scale/(mbScaleFactor*degToMeter);
204
        break;
205
      default:                //all projection codes in meters
206
        newRes = scale/mbScaleFactor;
207
        break;
208
    }
209
    this.centerAt(this.getCenter(), newRes );
210
  }
211

    
212

    
213
  /**
214
   * Initialization of the Extent tool, called as a loadModel event listener.
215
   * @param extent      the object being initialized
216
   * @param initialRes  (optional) if supplied the extent resolution will be set to this value
217
   */
218
  this.init = function(extent, initialRes) {
219
    var bbox = extent.model.getBoundingBox();
220
    extent.ul = new Array(bbox[0],bbox[3]);
221
    extent.lr = new Array(bbox[2],bbox[1]);
222
/*
223
TBD: when called as a listener this gets a bbox array passed in, not initialRes value
224
    if ( initialRes ) {
225
      extent.setSize( initialRes );
226
    } else {
227
      extent.setResolution( new Array(extent.model.getWindowWidth(), extent.model.getWindowHeight() ) );
228
    }
229
*/
230
    extent.setResolution( new Array(extent.model.getWindowWidth(), extent.model.getWindowHeight() ) );
231
  }
232
  if ( initialRes ) this.init(this, initialRes);
233

    
234

    
235
  this.firstInit = function(extent, initialRes) {
236
  	extent.init(extent, initialRes);
237
    //TBD: this causes 2 paint() calls on initial load, not sure why it's here - MA
238
	  //extent.zoomToBox(extent.ul,extent.lr);
239
  }
240

    
241
}
242

    
243
  
244
  
(5-5/12)