Statistics
| Revision:

gvsig-projects-pool / org.gvsig.online / trunk / org.gvsig.online / org.gvsig.online.lib / org.gvsig.online.lib.impl / src / main / java / org / gvsig / online / lib / impl / TilesCalculator.java @ 9512

History | View | Annotate | Download (15.2 KB)

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.online.lib.impl;
7

    
8
import java.awt.Dimension;
9
import java.util.ArrayList;
10
import java.util.Arrays;
11
import java.util.Collections;
12
import java.util.HashSet;
13
import java.util.Iterator;
14
import java.util.List;
15
import java.util.Set;
16
import org.apache.commons.lang3.builder.HashCodeBuilder;
17
import org.gvsig.fmap.geom.Geometry;
18
import org.gvsig.fmap.geom.GeometryLocator;
19
import org.gvsig.fmap.geom.GeometryManager;
20
import org.gvsig.fmap.geom.GeometryUtils;
21
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
22
import org.gvsig.fmap.geom.operation.GeometryOperationException;
23
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
24
import org.gvsig.fmap.geom.primitive.Envelope;
25
import org.gvsig.tools.ToolsLocator;
26
import org.gvsig.tools.i18n.I18nManager;
27
import org.gvsig.tools.library.impl.DefaultLibrariesInitializer;
28
import org.gvsig.tools.task.SimpleTaskStatus;
29
import org.gvsig.tools.task.UserCancelTaskException;
30

    
31
/**
32
 *
33
 * @author jjdelcerro
34
 */
35
@SuppressWarnings("UseSpecificCatch")
36
public class TilesCalculator {
37

    
38
    public interface CalculatorData {
39
        
40
        public Envelope getEnvelope();
41
        
42
        public double getWidth();
43
        
44
        public double getHeight();
45
        
46
        public long getElements(Envelope envelope);
47
    }
48
    
49
    private class Cell implements Comparable<Cell>{
50
        int col;
51
        int row;
52
        int colspan;
53
        int rowspan;
54
        boolean removed;
55
        
56
        public Cell(int col,int row) {
57
            this.col = col;
58
            this.row = row;
59
            this.removed = false;
60
        }
61
        
62
        public boolean canSpanCol(Cell other) {
63
            return (this.row == other.row) && ( this.col+this.colspan+1 == other.col )  && (this.rowspan == other.rowspan);
64
        }
65

    
66
        public boolean canSpanRow(Cell other) {
67
            return (this.col == other.col) && ( this.row+this.rowspan+1 == other.row )  && (this.colspan == other.colspan);
68
        }
69

    
70
        @Override
71
        public int compareTo(Cell other) {
72
            int r = Integer.compare(this.row, other.row);
73
            if( r==0 ) {
74
                r = Integer.compare(this.col, other.col);
75
            }
76
            return r;
77
        }
78
        
79
        public Envelope getEnvelope(int cellsize) throws CreateEnvelopeException {
80
            Envelope env = getGeometryManager().createEnvelope(
81
                    (cellsize*col),
82
                    (cellsize*row),
83
                    (cellsize*(col+colspan+1)),
84
                    (cellsize*(row+rowspan+1)),
85
                    Geometry.SUBTYPES.GEOM2D
86
            );
87
            return env;
88
        }
89

    
90
        @Override
91
        public String toString() {
92
            return "row:"+row+",col:"+col+",colspan:"+colspan+",rowspan:"+rowspan+",removed:"+removed;
93
        }
94

    
95
        @Override
96
        public boolean equals(Object other0) {
97
            if( !(other0 instanceof Cell) ) {
98
                return false;
99
            }
100
            Cell other = (Cell)other0;
101
            return this.col == other.col 
102
                    && this.row == other.row 
103
                    && this.colspan == other.colspan 
104
                    && this.rowspan == other.rowspan;
105
        }
106

    
107
        @Override
108
        public int hashCode() {
109
            HashCodeBuilder builder = new HashCodeBuilder();
110
            return builder.append(this.getClass().hashCode())
111
                    .append(this.col)
112
                    .append(this.row)
113
                    .append(this.colspan)
114
                    .append(this.rowspan)
115
                    .toHashCode();                    
116
        }
117
        
118
    }
119

    
120
    private GeometryManager geometryManager ;
121
    
122
    public TilesCalculator() {
123
        
124
    }    
125
    
126
    private double getArea(Envelope env) throws GeometryOperationNotSupportedException, GeometryOperationException {
127
        return env.getGeometry().area();
128
    }
129
    
130
    private GeometryManager getGeometryManager() {
131
        if( this.geometryManager==null ) {
132
            this.geometryManager = GeometryLocator.getGeometryManager();
133
        }
134
        return this.geometryManager;
135
    }
136
    
137
    private Envelope[] getNextLevel(Envelope env) throws CreateEnvelopeException {
138
        double with = env.getLength(Geometry.DIMENSIONS.X) / 2.0;
139
        double height = env.getLength(Geometry.DIMENSIONS.Y) / 2.0;
140
        Envelope[] envs = new Envelope[] {
141
            this.getGeometryManager().createEnvelope(
142
                env.getMinimum(Geometry.DIMENSIONS.X),
143
                env.getMinimum(Geometry.DIMENSIONS.Y),
144
                env.getMinimum(Geometry.DIMENSIONS.X)+with,
145
                env.getMinimum(Geometry.DIMENSIONS.Y)+height,
146
                Geometry.SUBTYPES.GEOM2D
147
            ),
148
            this.getGeometryManager().createEnvelope(
149
                env.getMinimum(Geometry.DIMENSIONS.X),
150
                env.getMinimum(Geometry.DIMENSIONS.Y)+height,
151
                env.getMinimum(Geometry.DIMENSIONS.X)+with,
152
                env.getMaximum(Geometry.DIMENSIONS.Y),
153
                Geometry.SUBTYPES.GEOM2D
154
            ),
155
            this.getGeometryManager().createEnvelope(
156
                env.getMinimum(Geometry.DIMENSIONS.X)+with,
157
                env.getMinimum(Geometry.DIMENSIONS.Y),
158
                env.getMaximum(Geometry.DIMENSIONS.X),
159
                env.getMinimum(Geometry.DIMENSIONS.Y)+height,
160
                Geometry.SUBTYPES.GEOM2D
161
            ),
162
            this.getGeometryManager().createEnvelope(
163
                env.getMinimum(Geometry.DIMENSIONS.X)+with,
164
                env.getMinimum(Geometry.DIMENSIONS.Y)+height,
165
                env.getMaximum(Geometry.DIMENSIONS.X),
166
                env.getMaximum(Geometry.DIMENSIONS.Y),
167
                Geometry.SUBTYPES.GEOM2D
168
            )
169
        };
170
        return envs;
171
    }
172
    
173

    
174
    private Dimension getDimension(Envelope env) throws GeometryOperationNotSupportedException, GeometryOperationException {
175
        double area = getArea(env);
176
        int cellSize = (int) Math.sqrt(area);
177
        return new Dimension(cellSize,cellSize);
178
    }
179
    
180
    public Dimension calculateCellSize(CalculatorData data) {
181
        return this.calculateCellSize(data, 1000, null);
182
    }
183
    
184
    public Dimension calculateCellSize(CalculatorData data, long maxElementsByCell, SimpleTaskStatus status) {
185
        I18nManager i18n = ToolsLocator.getI18nManager();
186
        if (status == null) {
187
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Calculating_cell_size"));
188
            status.setAutoremove(true);
189
            status.add();
190
        } else {
191
            status.push();
192
        }
193
        try {
194
            status.setIndeterminate();
195
            status.setCurValue(0);
196
            Envelope curEnvelope = data.getEnvelope();
197
            long totalElements = data.getElements(curEnvelope);
198

    
199
            if( totalElements < maxElementsByCell ) {
200
                status.terminate();
201
                return getDimension(curEnvelope);
202
            }
203

    
204
            while(true) {
205
                if( status.isCancellationRequested() ) {
206
                    status.cancel();
207
                    throw new UserCancelTaskException();
208
                }
209
                long maxElements = 0;
210
                Envelope maxElementsEnvelope = null;
211
                for (Envelope envelope : getNextLevel(curEnvelope)) {
212
                    long numElements = data.getElements(envelope);
213
                    if( maxElements < numElements ) {
214
                        maxElements = numElements;
215
                        maxElementsEnvelope = envelope;
216
                    }
217
                }
218
                if( maxElements>0 && maxElements<=maxElementsByCell) {
219
                    status.terminate();
220
                    return getDimension(maxElementsEnvelope);
221
                }
222
                curEnvelope = maxElementsEnvelope;
223
            }
224
        } catch(Throwable t) {
225
            throw new RuntimeException("Can't calculate grid cell size", t);
226
        } finally {
227
            status.pop();
228
        }
229
    }
230
    
231
    private Cell calculateCell( int cellSize, double x, double y) {
232
//        Envelope fullenv = data.getEnvelope();
233
//        int cellx = (int) ((x - fullenv.getMinimum(Geometry.DIMENSIONS.X))/cellSize);
234
//        int celly = (int) ((y - fullenv.getMinimum(Geometry.DIMENSIONS.Y))/cellSize);
235
        int cellx = (int) (x/cellSize);
236
        int celly = (int) (y/cellSize);
237
        return new Cell(cellx,celly);
238
    }
239
    
240
    private List<Cell> calculateCell(int cellSize, Geometry geom) {
241
        Envelope geomenv = geom.getEnvelope();
242
        Cell upperLeftCell = calculateCell(
243
                cellSize, 
244
                geomenv.getMinimum(Geometry.DIMENSIONS.X),
245
                geomenv.getMinimum(Geometry.DIMENSIONS.Y)
246
        );
247
        Cell bottomRightCell = calculateCell(
248
                cellSize, 
249
                geomenv.getMaximum(Geometry.DIMENSIONS.X),
250
                geomenv.getMaximum(Geometry.DIMENSIONS.Y)
251
        );
252
        List<Cell> cells = new ArrayList<>();
253
        for (int i = upperLeftCell.col; i <= bottomRightCell.col; i++) {
254
            for (int j = upperLeftCell.row; j <= bottomRightCell.row; j++) {
255
                cells.add(new Cell(i,j));
256
            }            
257
        }
258
        return cells;
259
    }
260

    
261
    private List<Cell> calculateCells(int cellSize, Iterator<Geometry> geoms) {
262
        Set<Cell> cells = new HashSet<>();
263

    
264
        while (geoms.hasNext()) {
265
            Geometry g = geoms.next();
266
            if (g != null) {
267
                cells.addAll(calculateCell(cellSize, g));
268
            }
269
        }
270
        List<Cell> orderedCells = new ArrayList<>(cells);
271
        Collections.sort(orderedCells);
272
        return orderedCells;
273
    }
274
    
275
    private void joinCells(List<Cell> orderedCells) {
276
            for (Cell cell1 : orderedCells) {
277
                if( cell1.removed ) {
278
                    continue;
279
                }
280
                for (Cell cell2 : orderedCells) {
281
                    if( cell2.removed ) {
282
                        continue;
283
                    }
284
                    if( cell1.canSpanCol(cell2) ) {
285
                        cell1.colspan++;
286
                        cell2.removed = true;
287
                    }
288
                }        
289
            }
290
            for (Cell cell1 : orderedCells) {
291
                if( cell1.removed ) {
292
                    continue;
293
                }
294
                for (Cell cell2 : orderedCells) {
295
                    if( cell2.removed ) {
296
                        continue;
297
                    }
298
                    if( cell1.canSpanRow(cell2) ) {
299
                        cell1.rowspan++;
300
                        cell2.removed = true;
301
                    }
302
                }        
303
            }
304
    }
305
    
306
    public List<Envelope> calculateEnvelopes(int cellSize, List<Geometry> geoms) {
307
        return calculateEnvelopes(cellSize, geoms.iterator());
308
    }
309
    
310
    public List<Envelope> calculateEnvelopes(int cellSize, Iterator<Geometry> geoms) {
311
        try {
312
            List<Cell> orderedCells = calculateCells(cellSize, geoms);
313
            joinCells(orderedCells);
314
            
315
            List<Envelope> envs = new ArrayList<>();
316
            for (Cell cell : orderedCells) {
317
                if( cell.removed ) {
318
                    continue;
319
                }
320
                envs.add(cell.getEnvelope(cellSize));
321
            }
322
            return envs;
323
        } catch(Throwable t) {
324
            throw new RuntimeException("Can't calculate envelops of geometries", t);
325
        }
326
    }
327
    
328
    /*
329
cols 10
330
row  10
331
cellsize 100
332
env 0,0 1000,1000
333

334
r1c7 - 720,120 760,150
335
r1c8 - 820,120 860,150
336
r2c8 - 820,220 860,250
337
r3c7 - 720,320 760,350
338

339
r6c0 -
340
r6c1 -
341
r6c2 -
342
r7c0 -
343
r7c1 -
344
r7c2 -
345
    
346
r6c4 - 450,650 650,650
347
r6c5 - 450,650 650,650
348
r6c6 - 450,650 650,650
349
    
350
       c0 c1 c2 c3 c4 c5 c6 c7 c8 c9
351
    r0
352
    r1                      x  x
353
    r2                         x
354
    r3                      x
355
    r4
356
    r5
357
    r6  xxxxxx      xxxxxx
358
    r7  xxxxxx
359
    r8  
360
    r9  
361
    
362
    */
363
    
364
    public static void main(String[] args) {
365
        new DefaultLibrariesInitializer().fullInitialize();
366
        
367
        Geometry[] elements = new Geometry[] {
368
            GeometryUtils.createFrom("LINESTRING (720 120, 760 150)"),
369
            GeometryUtils.createFrom("LINESTRING (820 120, 860 150)"),
370
            GeometryUtils.createFrom("LINESTRING (820 220, 860 250)"),
371
            GeometryUtils.createFrom("LINESTRING (720 320, 760 350)"),
372
            GeometryUtils.createFrom("LINESTRING ( 50 650, 250 650)"),
373
            GeometryUtils.createFrom("LINESTRING (450 650, 650 650)"),
374
            GeometryUtils.createFrom("LINESTRING ( 50 750, 250 750)")
375
        };
376
        CalculatorData data = new CalculatorData() {
377
            @Override
378
            public Envelope getEnvelope() {
379
                return GeometryUtils.createEnvelope(0, 0, 1000, 1000, Geometry.SUBTYPES.GEOM2D);
380
            }
381

    
382
            @Override
383
            public double getWidth() {
384
                return 1000;
385
            }
386

    
387
            @Override
388
            public double getHeight() {
389
                return 1000;
390
            }
391

    
392
            @Override
393
            public long getElements(Envelope envelope) {
394
                int n = 0;
395
                for (Geometry geom : elements) {
396
                    if( envelope.intersects(geom) ) {
397
                        n++;
398
                    }
399
                }
400
                return n;
401
            }
402
        };
403
        TilesCalculator calculator = new TilesCalculator();
404
        Dimension dim = calculator.calculateCellSize(data,1,null);
405
        System.out.println(dim.width+", "+dim.height);
406

    
407
        System.out.println("Celdas con elementos:");
408
        List<Cell> cells = calculator.calculateCells(100, Arrays.asList(elements).iterator());
409
        for (Cell cell : cells) {
410
            System.out.println(cell);
411
        }
412
        System.out.println("Celdas con elementos conm los join:");
413
        calculator.joinCells(cells);
414
        for (Cell cell : cells) {
415
            System.out.println(cell);
416
        }
417
/*
418
62, 62
419
Celdas con elementos:
420
row:1,col:7,colspan:0,rowspan:0,removed:false
421
row:1,col:8,colspan:0,rowspan:0,removed:false
422
row:2,col:8,colspan:0,rowspan:0,removed:false
423
row:3,col:7,colspan:0,rowspan:0,removed:false
424
row:6,col:0,colspan:0,rowspan:0,removed:false
425
row:6,col:1,colspan:0,rowspan:0,removed:false
426
row:6,col:2,colspan:0,rowspan:0,removed:false
427
row:6,col:4,colspan:0,rowspan:0,removed:false
428
row:6,col:5,colspan:0,rowspan:0,removed:false
429
row:6,col:6,colspan:0,rowspan:0,removed:false
430
row:7,col:0,colspan:0,rowspan:0,removed:false
431
row:7,col:1,colspan:0,rowspan:0,removed:false
432
row:7,col:2,colspan:0,rowspan:0,removed:false
433
Celdas con elementos con los join:
434
row:1,col:7,colspan:1,rowspan:0,removed:false
435
row:1,col:8,colspan:0,rowspan:0,removed:true
436
row:2,col:8,colspan:0,rowspan:0,removed:false
437
row:3,col:7,colspan:0,rowspan:0,removed:false
438
row:6,col:0,colspan:2,rowspan:1,removed:false
439
row:6,col:1,colspan:0,rowspan:0,removed:true
440
row:6,col:2,colspan:0,rowspan:0,removed:true
441
row:6,col:4,colspan:2,rowspan:0,removed:false
442
row:6,col:5,colspan:0,rowspan:0,removed:true
443
row:6,col:6,colspan:0,rowspan:0,removed:true
444
row:7,col:0,colspan:2,rowspan:0,removed:true
445
row:7,col:1,colspan:0,rowspan:0,removed:true
446
row:7,col:2,colspan:0,rowspan:0,removed:true        
447
*/      
448
    }
449
}