Statistics
| Revision:

svn-gvsig-desktop / branches / v05 / extensions / extWMS / src / com / iver / cit / gvsig / fmap / layers / TimeDimension.java @ 3855

History | View | Annotate | Download (15.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
*
44
* $Id: TimeDimension.java 3855 2006-01-31 16:25:24Z jaume $
45
* $Log$
46
* Revision 1.3.2.3  2006-01-31 16:25:24  jaume
47
* correcciones de bugs
48
*
49
* Revision 1.4  2006/01/26 16:07:14  jaume
50
* *** empty log message ***
51
*
52
* Revision 1.3.2.1  2006/01/26 12:59:32  jaume
53
* 0.5
54
*
55
* Revision 1.3  2006/01/24 18:01:17  jaume
56
* *** empty log message ***
57
*
58
* Revision 1.2  2006/01/24 14:36:33  jaume
59
* This is the new version
60
*
61
* Revision 1.1.2.11  2006/01/20 15:59:13  jaume
62
* *** empty log message ***
63
*
64
* Revision 1.1.2.10  2006/01/20 15:22:46  jaume
65
* *** empty log message ***
66
*
67
* Revision 1.1.2.9  2006/01/20 08:50:52  jaume
68
* handles time dimension for the NASA Jet Propulsion Laboratory WMS
69
*
70
* Revision 1.1.2.8  2006/01/19 16:09:30  jaume
71
* *** empty log message ***
72
*
73
* Revision 1.1.2.7  2006/01/11 12:20:30  jaume
74
* *** empty log message ***
75
*
76
* Revision 1.1.2.6  2006/01/10 11:33:31  jaume
77
* Time dimension working against Jet Propulsion Laboratory's WMS server
78
*
79
* Revision 1.1.2.5  2006/01/09 18:10:38  jaume
80
* casi con el time dimension
81
*
82
* Revision 1.1.2.4  2006/01/05 23:15:53  jaume
83
* *** empty log message ***
84
*
85
* Revision 1.1.2.3  2006/01/04 18:09:02  jaume
86
* Time dimension
87
*
88
* Revision 1.1.2.2  2006/01/04 16:49:44  jaume
89
* Time dimensios
90
*
91
* Revision 1.1.2.1  2006/01/03 18:08:40  jaume
92
* *** empty log message ***
93
*
94
*
95
*/
96
/**
97
 * 
98
 */
99
package com.iver.cit.gvsig.fmap.layers;
100

    
101
import java.util.GregorianCalendar;
102

    
103
/**
104
 * Class for WMS TIME dimension from a WMS. It allows you to handle the correct
105
 * values for this kind of dimension.
106
 * <br>
107
 * <p>
108
 * At the moment this class was written the WMS TIME dimension is defined as the
109
 * ISO8601 standard for expressing times.
110
 * </p>
111
 * <br>
112
 * <p>
113
 * As far as this class implements IFMapWMSDimension it uses the same interface
114
 * and documentation.
115
 * </p>
116
 * 
117
 * @author jaume dominguez faus - jaume.dominguez@iver.es
118
 */
119
public class TimeDimension implements IFMapWMSDimension {
120
    static private final long millisXsec    = 1000;
121
    static private final long millisXminute = 60 * millisXsec;
122
    static private final long millisXhour   = 60 * millisXminute;
123
    static private final long millisXday    = 24 * millisXhour;
124
    static private final long millisXmonth  = 30 * millisXday;
125
    // according on the Wikipedia (1 year = 365 days 6 hours 9 minutes 9,7 seconds)
126
    static private final long millisXyear   = (365*millisXday) + (6*millisXhour) + (9*millisXminute) + 9700; 
127
    
128
    static private final String digit = "[0-9]";
129
    static private final String nonZeroDigit = "[1-9]";
130
    static private final String letter = "[a-zA-Z]";
131
    static private final String seconds = "([0-5]"+digit+"((\\.|,)"+digit+digit+")?)";
132
    static private final String minutes = "([0-5]"+digit+")";
133
    static private final String hours = "(0"+digit+"|1"+digit+"|2[0-3])";
134
    static private final String time = hours+":"+minutes+"(:"+seconds+")?";
135
    static private final String days = "(0?"+nonZeroDigit+"|1"+digit+"|2"+digit+"|30|31)";
136
    static private final String months = "(0?"+nonZeroDigit+"|10|11|12)";
137
    static private final String year = "("+digit+digit+")";
138
    static private final String century = "("+digit+digit+")";
139
    
140
    static private final String geologicDatasets = "(K|M|G)";
141
    static private final String floatingPointNumber = "("+digit+"+(\\."+digit+"+)?)";
142
    
143
    
144
    static private final String regexDateExtendedForBCE1 = "B?"+century+year+"-";
145
    static private final String regexDateExtendedForBCE2 = "B?"+century+year+"-"+months;
146
    static private final String regexDateExtendedForBCE3 = "B?"+century+year+"-"+months+"-"+days;
147
    static private final String regexDateExtendedForBCE4 = "B?"+century+year+"-"+months+"-"+days+"(T| )"+time+"Z";
148
    // Note: in WMS 1.1.0 the suffix Z is optional
149
    // TODO truncated values not yet allowed
150
    
151
    static private final String regexDateExtendedForBCE = 
152
        "(" +  regexDateExtendedForBCE1  + "|"
153
            +  regexDateExtendedForBCE2  + "|"
154
            +  regexDateExtendedForBCE3  + "|"
155
            +  regexDateExtendedForBCE4  +      ")";
156
    
157
    static private final String regexDateForGeologicDatasets = geologicDatasets+floatingPointNumber;
158
    
159
    static private final String periodMagnitude = "(Y|M|D)";
160
    static private final String p1 = "(("+digit+")+"+periodMagnitude+")";
161
    
162
    static private final String timeMagnitude = "(H|M|S)";
163
    static private final String p2 = "("+floatingPointNumber+timeMagnitude+")";
164
    static private final String regexPeriod = "P(("+p1+"+"+"(T"+p2+")*)|("+p1+"*"+"(T"+p2+")+))"; 
165
    
166
    static private final String regexTimeDimension =
167
        "("+regexDateExtendedForBCE+"(,"+regexDateExtendedForBCE+")*|("+regexDateExtendedForBCE+")/("+regexDateExtendedForBCE+")/("+regexPeriod+"))";
168
    
169
    private String name = "TIME";
170
    private String unit;
171
    private String unitSymbol;
172
    private String expression;
173
    private Object minValue;
174
    private Object maxValue;
175
    private boolean isGeologic = false;
176
    private Integer valueCount;
177
    private String period;
178
    private long step; // Distance between two points in milliseconds.
179
    private int type;
180
    
181
    /**
182
     * Creates a new instance of TimeDimension.
183
     * @param units
184
     * @param unitSymbol
185
     * @param expression
186
     */
187
    public TimeDimension(String _units, String _unitSymbol, String _dimensionExpression) {
188
        this.unit = _units;
189
        this.unitSymbol = _unitSymbol;
190
        setExpression(_dimensionExpression);
191
    }
192

    
193
    public String getName() {
194
        return name;
195
    }
196
    
197
    public String getUnit() {
198
        return unit;
199
    }
200

    
201
    public String getUnitSymbol() {
202
        return unitSymbol;
203
    }
204

    
205

    
206
    public String getLowLimit() {
207
            String separator = (type == INTERVAL) ? "/" : ",";
208
        return expression.split(separator)[0];
209
    }
210

    
211
    public String getHighLimit() {
212
            if (type == INTERVAL) {
213
                    String[] s = expression.split("/");
214
                    return (s.length > 1) ? s[1] : s[0];
215
            } else if (type == MULTIPLE_VALUE) {
216
                    String[] s = expression.split(",");
217
                    return s[s.length-1];
218
            } else {
219
                    return expression;
220
            }
221
                    
222
    }
223

    
224
    public String getResolution() {
225
            if (type == INTERVAL) {
226
                    String[] s = expression.split("/");
227
                    return (s.length == 1) ? s[3] : null;
228
            } else return null;
229
    }
230

    
231
    public boolean isValidValue(String value) {
232
        return (value.matches(regexDateForGeologicDatasets) || value.matches(regexDateExtendedForBCE));
233
    }
234

    
235
    public Object valueOf(String value) throws IllegalArgumentException {
236
            // TODO Missing geological dates
237
        String myValue = value.toUpperCase();
238
        if (isValidValue(myValue)) {
239
            Object val = null;
240
            if (!isGeologic){
241
                // This is a normal date
242
                int myYear;
243
                int myMonth;
244
                int myDay;
245
                int myHour;
246
                int myMinute;
247
                float mySecond;
248
                String[] s = myValue.split("-");
249
                myYear = (s[0].charAt(0)=='B')? -Integer.parseInt(s[0].substring(1, 5)) : Integer.parseInt(s[0].substring(0, 4));
250
                myMonth = (s.length>1) ? Integer.parseInt(s[1])-1 : 0; 
251
                if (myValue.matches(regexDateExtendedForBCE4)){
252
                        if (s[2].endsWith("Z"))
253
                                s[2] = s[2].substring(0,s[2].length()-1);
254
                    s = (s[2].indexOf('T')!=-1) ? s[2].split("T") : s[2].split(" ");
255
                    myDay = Integer.parseInt(s[0]);
256
                    
257
                    // Go with the time
258
                    s = s[1].split(":");
259
                    myHour = Integer.parseInt(s[0]);
260
                    myMinute = (s.length>1) ? Integer.parseInt(s[1]) : 0;
261
                    mySecond = (s.length>2) ? Float.parseFloat(s[2]) : 0;
262
                } else {
263
                    myDay = (s.length>2) ? Integer.parseInt(s[2]) : 1;
264
                    
265
                    myHour = 0;
266
                    myMinute = 0;
267
                    mySecond = 0;
268
                }
269
                GregorianCalendar cal = new GregorianCalendar(myYear, myMonth, myDay, myHour, myMinute, (int)mySecond);
270
                val = cal;
271
            } else{
272
                // this is a geological date >:-(
273
            }
274
            return val;    
275
        } else throw new IllegalArgumentException(myValue);
276
        
277
    }
278
 
279
    public String valueAt(int pos) throws ArrayIndexOutOfBoundsException {
280
        if (pos<0 || pos>valueCount())
281
            throw new ArrayIndexOutOfBoundsException(pos+"(must be >= 0 and <="+valueCount()+")");
282
        
283
        if (type == SINGLE_VALUE)
284
                return expression;
285
        
286
        if (type == MULTIPLE_VALUE)
287
                return expression.split(",")[pos];
288
        
289
        if (!isGeologic){
290
            long newTime = ((GregorianCalendar) minValue).getTimeInMillis();
291
            newTime += (step*pos);
292
            GregorianCalendar cal = new GregorianCalendar();
293
            cal.setTimeInMillis(newTime);
294
            if (cal.after(maxValue))
295
                return toString((GregorianCalendar) maxValue);
296
            else if (cal.before(minValue))
297
                return toString((GregorianCalendar) minValue);
298
            else
299
                return toString(cal);
300
        }
301
        return null;
302
    }
303

    
304
    /**
305
     * Prints a GregorianCalendar value in WMS1.1.1 format.
306
     * @param cal
307
     * @return
308
     */
309
    private String toString(GregorianCalendar cal) {
310
        int iYear   = cal.get(cal.YEAR);
311
        int iMonth  = cal.get(cal.MONTH) + 1;
312
        int iDay    = cal.get(cal.DAY_OF_MONTH);
313
        int iHour   = cal.get(cal.HOUR_OF_DAY);
314
        int iMinute = cal.get(cal.MINUTE);
315
        int iSecond = cal.get(cal.SECOND);
316
        String myYear;
317
        if (iYear<10)
318
            myYear = "200"+iYear;
319
        else if (iYear<100)
320
            myYear = "20"+iYear;
321
        else if (iYear<1000)
322
            myYear = "2"+iYear;
323
        else
324
            myYear = ""+iYear;
325
        String myMonth       = (iMonth<10) ? "0"+iMonth  : ""+iMonth;
326
        String myDay         = (iDay<10)   ? "0"+iDay    : ""+iDay;
327
        String myHour        = (iHour<10)  ? "0"+iHour   : ""+iHour;
328
        String myMinute      = (iMinute<10)? "0"+iMinute : ""+iMinute;
329
        String mySecond      = (iSecond<10)? "0"+iSecond : ""+iSecond;
330
        int myMilliSecond = cal.get(cal.MILLISECOND);
331
        
332
        
333
        String s = myYear+"-"+myMonth+"-"+myDay+"T"+myHour+":"+myMinute+":"+mySecond+"."+(myMilliSecond/10)+"Z";
334
        if (iYear<0)
335
            s = "B"+s;
336
        return s;
337
    }
338

    
339
    public int valueCount() {
340
        if (valueCount==null){
341
                if (type == MULTIPLE_VALUE) {
342
                        return expression.split(",").length;
343
                } else if (type == INTERVAL) {
344
                        if (period == null) {
345
                                valueCount = new Integer(0);
346
                                return valueCount.intValue();
347
                        }
348
                        
349
                        if (!isGeologic){
350
                                
351
                                long x1 = ((GregorianCalendar) maxValue).getTimeInMillis();
352
                                long x0 = ((GregorianCalendar) minValue).getTimeInMillis();
353
                                long distance = x1-x0;
354
                                step = 0;
355
                                
356
                                boolean isTimeField = false;
357
                                String val = "";
358
                                
359
                                for (int i = 0; i < period.length(); i++) {
360
                                        if (period.charAt(i) == 'P')
361
                                                continue;
362
                                        if (period.charAt(i) == 'T'){
363
                                                isTimeField = true;
364
                                                continue;
365
                                        }
366
                                        switch (period.charAt(i)){
367
                                        case 'Y':
368
                                                step += Integer.parseInt(val) * millisXyear;
369
                                                val = "";
370
                                                break;
371
                                        case 'M':
372
                                                if (isTimeField)
373
                                                        step += Integer.parseInt(val) * millisXminute;
374
                                                else
375
                                                        step += Integer.parseInt(val) * millisXmonth;
376
                                                val = "";
377
                                                break;
378
                                        case 'D':
379
                                                step += Integer.parseInt(val) * millisXday;
380
                                                val = "";
381
                                                break;
382
                                        case 'H':
383
                                                step += Integer.parseInt(val) * millisXhour;
384
                                                val = "";
385
                                                break;
386
                                        case 'S':
387
                                                step += Integer.parseInt(val) * 1000;
388
                                                val = "";
389
                                                break;
390
                                        default:
391
                                                val += period.charAt(i);
392
                                        break;
393
                                        }                       
394
                                }
395
                                valueCount = new Integer((int)(distance/step) + 1); // + 1 for the initial point
396
                        }
397
            } else {
398
                    // this is a single value expression
399
                    valueCount = new Integer(1);
400
                    return valueCount.intValue();
401
            }
402
        }
403
        return valueCount.intValue();
404
    }
405

    
406
    public void setExpression(String expr) throws IllegalArgumentException {
407
        expression = expr.toUpperCase();
408
        long t1 = System.currentTimeMillis();
409
        if (expression.matches(regexTimeDimension)){
410
            isGeologic = false;
411
        } else if (expression.matches(regexDateExtendedForBCE)) {
412
            isGeologic = false;
413
        } else if (expression.matches(regexDateForGeologicDatasets)){
414
            isGeologic = true;
415
        } else  {
416
            throw new IllegalArgumentException();
417
        }
418
        long t2 = System.currentTimeMillis();
419
        String separator;
420
        if (expression.indexOf("/")!=-1) {
421
                separator = "/";
422
                type = INTERVAL;
423
        } else if (expression.indexOf(",")!=-1) {
424
                separator = ",";
425
                type = MULTIPLE_VALUE;
426
        } else {
427
                separator = ",";
428
                type = SINGLE_VALUE;
429
        }
430
                
431
                
432
        String[] s = expression.split(separator);
433
        minValue = valueOf(s[0]);
434
        if (type == INTERVAL) {
435
                maxValue = (s.length>1) ? valueOf(s[1]) : valueOf(s[0]);
436
                period = (s.length>2 && s[2].matches(regexPeriod)) ? s[2] : null;
437
        } else if (type == MULTIPLE_VALUE) {
438
                maxValue = valueOf(s[s.length-1]);
439
        } else {
440
                maxValue = valueOf(s[0]);
441
        }
442
                
443
        long t3 = System.currentTimeMillis();
444
//        System.err.println("TimeDimension>>> temps per a recon?ixer l'expressi?: "+(t2-t1));
445
//        System.err.println("TimeDimension>>> temps total (calculant valors extrems: "+(t3-t1));
446
    }
447

    
448
        public String getExpression() {
449
                return expression;
450
        }
451

    
452
        public int getType() {
453
                return type;
454
        }
455

    
456
}