Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extWMS / src / com / iver / cit / gvsig / fmap / layers / TimeDimension.java @ 3746

History | View | Annotate | Download (14.8 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 3746 2006-01-24 14:40:18Z jaume $
45
* $Log$
46
* Revision 1.2  2006-01-24 14:36:33  jaume
47
* This is the new version
48
*
49
* Revision 1.1.2.11  2006/01/20 15:59:13  jaume
50
* *** empty log message ***
51
*
52
* Revision 1.1.2.10  2006/01/20 15:22:46  jaume
53
* *** empty log message ***
54
*
55
* Revision 1.1.2.9  2006/01/20 08:50:52  jaume
56
* handles time dimension for the NASA Jet Propulsion Laboratory WMS
57
*
58
* Revision 1.1.2.8  2006/01/19 16:09:30  jaume
59
* *** empty log message ***
60
*
61
* Revision 1.1.2.7  2006/01/11 12:20:30  jaume
62
* *** empty log message ***
63
*
64
* Revision 1.1.2.6  2006/01/10 11:33:31  jaume
65
* Time dimension working against Jet Propulsion Laboratory's WMS server
66
*
67
* Revision 1.1.2.5  2006/01/09 18:10:38  jaume
68
* casi con el time dimension
69
*
70
* Revision 1.1.2.4  2006/01/05 23:15:53  jaume
71
* *** empty log message ***
72
*
73
* Revision 1.1.2.3  2006/01/04 18:09:02  jaume
74
* Time dimension
75
*
76
* Revision 1.1.2.2  2006/01/04 16:49:44  jaume
77
* Time dimensios
78
*
79
* Revision 1.1.2.1  2006/01/03 18:08:40  jaume
80
* *** empty log message ***
81
*
82
*
83
*/
84
/**
85
 * 
86
 */
87
package com.iver.cit.gvsig.fmap.layers;
88

    
89
import java.util.GregorianCalendar;
90

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

    
180
    public String getName() {
181
        return name;
182
    }
183
    
184
    public String getUnit() {
185
        return unit;
186
    }
187

    
188
    public String getUnitSymbol() {
189
        return unitSymbol;
190
    }
191

    
192

    
193
    public String getLowLimit() {
194
            String separator = (type == INTERVAL) ? "/" : ",";
195
        return expression.split(separator)[0];
196
    }
197

    
198
    public String getHighLimit() {
199
            if (type == INTERVAL) {
200
                    String[] s = expression.split("/");
201
                    return (s.length > 1) ? s[1] : s[0];
202
            } else if (type == MULTIPLE_VALUE) {
203
                    String[] s = expression.split(",");
204
                    return s[s.length-1];
205
            } else {
206
                    return expression;
207
            }
208
                    
209
    }
210

    
211
    public String getResolution() {
212
            if (type == INTERVAL) {
213
                    String[] s = expression.split("/");
214
                    return (s.length == 1) ? s[3] : null;
215
            } else return null;
216
    }
217

    
218
    public boolean isValidValue(String value) {
219
        return (value.matches(regexDateForGeologicDatasets) || value.matches(regexDateExtendedForBCE));
220
    }
221

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

    
291
    /**
292
     * Prints a GregorianCalendar value in WMS1.1.1 format.
293
     * @param cal
294
     * @return
295
     */
296
    private String toString(GregorianCalendar cal) {
297
        int iYear   = cal.get(cal.YEAR);
298
        int iMonth  = cal.get(cal.MONTH) + 1;
299
        int iDay    = cal.get(cal.DAY_OF_MONTH);
300
        int iHour   = cal.get(cal.HOUR_OF_DAY);
301
        int iMinute = cal.get(cal.MINUTE);
302
        int iSecond = cal.get(cal.SECOND);
303
        String myYear;
304
        if (iYear<10)
305
            myYear = "200"+iYear;
306
        else if (iYear<100)
307
            myYear = "20"+iYear;
308
        else if (iYear<1000)
309
            myYear = "2"+iYear;
310
        else
311
            myYear = ""+iYear;
312
        String myMonth       = (iMonth<10) ? "0"+iMonth  : ""+iMonth;
313
        String myDay         = (iDay<10)   ? "0"+iDay    : ""+iDay;
314
        String myHour        = (iHour<10)  ? "0"+iHour   : ""+iHour;
315
        String myMinute      = (iMinute<10)? "0"+iMinute : ""+iMinute;
316
        String mySecond      = (iSecond<10)? "0"+iSecond : ""+iSecond;
317
        int myMilliSecond = cal.get(cal.MILLISECOND);
318
        
319
        
320
        String s = myYear+"-"+myMonth+"-"+myDay+"T"+myHour+":"+myMinute+":"+mySecond+"."+(myMilliSecond/10)+"Z";
321
        if (iYear<0)
322
            s = "B"+s;
323
        return s;
324
    }
325

    
326
    public int valueCount() {
327
        if (valueCount==null){
328
                if (type == MULTIPLE_VALUE) {
329
                        return expression.split(",").length;
330
                } else if (type == INTERVAL) {
331
                        if (period == null) {
332
                                valueCount = new Integer(0);
333
                                return valueCount.intValue();
334
                        }
335
                        
336
                        if (!isGeologic){
337
                                
338
                                long x1 = ((GregorianCalendar) maxValue).getTimeInMillis();
339
                                long x0 = ((GregorianCalendar) minValue).getTimeInMillis();
340
                                long distance = x1-x0;
341
                                step = 0;
342
                                
343
                                boolean isTimeField = false;
344
                                String val = "";
345
                                
346
                                for (int i = 0; i < period.length(); i++) {
347
                                        if (period.charAt(i) == 'P')
348
                                                continue;
349
                                        if (period.charAt(i) == 'T'){
350
                                                isTimeField = true;
351
                                                continue;
352
                                        }
353
                                        switch (period.charAt(i)){
354
                                        case 'Y':
355
                                                step += Integer.parseInt(val) * millisXanyo;
356
                                                val = "";
357
                                                break;
358
                                        case 'M':
359
                                                if (isTimeField)
360
                                                        step += Integer.parseInt(val) * millisXminute;
361
                                                else
362
                                                        step += Integer.parseInt(val) * millisXmes;
363
                                                val = "";
364
                                                break;
365
                                        case 'D':
366
                                                step += Integer.parseInt(val) * millisXdia;
367
                                                val = "";
368
                                                break;
369
                                        case 'H':
370
                                                step += Integer.parseInt(val) * millisXhora;
371
                                                val = "";
372
                                                break;
373
                                        case 'S':
374
                                                step += Integer.parseInt(val) * 1000;
375
                                                val = "";
376
                                                break;
377
                                        default:
378
                                                val += period.charAt(i);
379
                                        break;
380
                                        }                       
381
                                }
382
                                valueCount = new Integer((int)(distance/step) + 1); // + 1 for the initial point
383
                        }
384
            } else {
385
                    // this is a single value expression
386
                    valueCount = new Integer(1);
387
                    return valueCount.intValue();
388
            }
389
        }
390
        return valueCount.intValue();
391
    }
392

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

    
435
        public String getExpression() {
436
                return expression;
437
        }
438

    
439
        public int getType() {
440
                return type;
441
        }
442

    
443
}