Statistics
| Revision:

svn-document-layout / trunk / org.gvsig.app.document.layout2.app / org.gvsig.app.document.layout2.app.mainplugin / src / main / java / org / gvsig / layout / mapbox / model / MapBoxModel.java @ 1714

History | View | Annotate | Download (32.7 KB)

1
/*
2
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
3
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
4
 */
5
package org.gvsig.layout.mapbox.model;
6

    
7
import java.awt.Rectangle;
8
import java.awt.geom.Dimension2D;
9
import java.awt.geom.Point2D;
10
import java.awt.geom.Rectangle2D;
11
import java.util.ArrayList;
12
import java.util.Collections;
13
import java.util.HashSet;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.Objects;
17
import java.util.Set;
18
import org.apache.commons.lang3.tuple.ImmutablePair;
19
import org.apache.commons.lang3.tuple.Pair;
20
import org.apache.commons.math.util.MathUtils;
21
import static org.gvsig.layout.mapbox.fframe.FFrameMapBox.MAPBOX_EPSILON;
22
import org.gvsig.tools.ToolsLocator;
23
import org.gvsig.tools.dynobject.DynStruct;
24
import org.gvsig.tools.lang.CloneableUtils;
25
import org.gvsig.tools.persistence.PersistenceManager;
26
import org.gvsig.tools.persistence.Persistent;
27
import org.gvsig.tools.persistence.PersistentState;
28
import org.gvsig.tools.persistence.exception.PersistenceException;
29
import org.gvsig.tools.util.IsEmpty;
30
import org.slf4j.Logger;
31
import org.slf4j.LoggerFactory;
32

    
33
/**
34
 *
35
 * @author fdiaz
36
 */
37
public class MapBoxModel implements IsEmpty, Persistent, org.gvsig.tools.lang.Cloneable {
38
    
39
    private static final Logger LOGGER = LoggerFactory.getLogger(MapBoxModel.class);
40

    
41
    public static final String PERSISTENCE_DEFINITION_NAME = "MapBoxModel";
42
    
43
    public static final int POSITION_OUT_OF_MAPBOX = -1;
44
    public static final int POSITION_IN_CELL = 0;
45
    public static final int POSITION_AT_TOP_OF_CELL = 1;
46
    public static final int POSITION_AT_BOTOM_OF_CELL = 2;
47
    public static final int POSITION_ON_LEFT_EDGE_OF_CELL = 3;
48
    public static final int POSITION_ON_RIGHT_EDGE_OF_CELL = 4;
49

    
50
    private List<Cell> cells;
51
    private Dimension2D dimension;
52

    
53
    public MapBoxModel() {
54
        this.cells = new ArrayList<>();
55
    }
56
    
57
    public MapBoxModel(Dimension2D dimension, int columns, int rows) {
58
        this();
59
        this.dimension = dimension;
60
        
61
        double cellWidth = dimension.getWidth()/columns;
62
        double cellHeight = dimension.getHeight()/rows;
63
        for (int i = 0; i < columns; i++) {
64
            for (int j = 0; j < rows; j++) {
65
                cells.add(new CellImpl(i*cellWidth, j*cellHeight, cellWidth, cellHeight));
66
            }
67
        }
68
    }
69
    
70
    public MapBoxModel(Dimension2D dimension, List<Cell> cells) {
71
        this();
72
        this.dimension = dimension;
73
        
74
        for (Cell cell : cells) {
75
            this.cells.add(cell);
76
        }
77
    }
78
    
79
    public Cell getCell(double x, double y) {
80
        for (Cell cell : cells) {
81
            if(cell.contains(x, y)){
82
                return cell;
83
            }
84
        }
85
        return null;
86
    }
87
    
88
    public List<Cell> getCells() {
89
        return cells;
90
    }
91
    
92
    public List<Cell> getCells(Rectangle2D r) {
93
        List<Cell> res = new ArrayList();
94
        for (Cell cell : cells) {
95
            if(cell.isContained(r)) { // || cell.intersects(r)){
96
                res.add(cell);
97
            }
98
        }
99
        return res;
100
        
101
    }
102
    
103
    public void add(Cell c) {
104
        this.cells.add(c);
105
    }
106
    
107
    public void insertRow(Cell cell) { 
108
        try {
109
            Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
110
            double y = cell.getY();
111
            /* Obtenemos las celdas a las que pertenece la celda del par?metro
112
                para obtener la altura de la fila que ser? la menor altura
113
                de todas las de la misma fila
114
            */
115
            List<Cell> sameRowCells = getRowCells(y);
116
            double rowHeight = Double.POSITIVE_INFINITY;
117
            for (Cell sameRowCell : sameRowCells) {
118
                if(sameRowCell.getHeight()<rowHeight){
119
                    rowHeight = sameRowCell.getHeight();
120
                }
121
            }
122
            
123
            // Obtenemos todas las celdas que est?n debajo de donde tenemos que a?adir una fila nueva
124
            List<Cell> nextRowsCells = getNextRowsCells(y);
125

    
126
            // Obtenemos todas las celdas que est?n atravesadas por la l?nea horizontal de donde tenemos que a?adir una fila nueva
127
            List<Cell> rowTraversedCells = getTraversedRowCells(y);
128

    
129
            List<Cell> visited = new ArrayList<>();
130
            // A?adimos las celdas de la fila nueva
131
            for (Cell curCell : sameRowCells) {
132
                Cell c = curCell.clone();
133
                c.setY(y);
134
                c.setHeight(rowHeight);
135
                this.add(c);
136
                visited.add(curCell);
137
            }
138
            
139
            // Movemos las celdas que deben estar debajo de la fila nueva
140
            for (Cell curCell : nextRowsCells) {
141
                curCell.setY(curCell.getY() + rowHeight);
142
                visited.add(curCell);
143
            }
144

    
145
            // Ampliamos la altura de las celdas que son atravesadas por la l?nea horizontal de donde se ha a?adido la fila nueva
146
            for (Cell curCell : rowTraversedCells) {
147
                if(visited.contains(curCell)){
148
                    continue;
149
                }
150
                curCell.setHeight(curCell.getHeight()+ rowHeight);
151
            }
152
            this.dimension.setSize(dimension.getWidth(), dimension.getHeight() + rowHeight);
153
            resize(oldDimension);
154
        } catch (Exception ex) {
155
            LOGGER.warn("Can't insert row before cell "+Objects.toString(cell), ex);
156
        }
157
    }
158

    
159
    /**
160
     * Insert a column to the left of the cell column passed as a parameter
161
     * 
162
     * @param cell 
163
     */
164
    public void insertColumn(Cell cell) { 
165
        try {
166
            Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
167
            double x = cell.getX();
168
            /* Obtenemos las celdas de la columna a la que pertenece la celda del par?metro
169
                para obtener la anchura de la columna que ser? la menor anchura
170
                de todas las de la misma fila
171
            */
172
            List<Cell> sameColumnCells = getColumnCells(x);
173
            double rowWidth = Double.POSITIVE_INFINITY;
174
            for (Cell sameColumnCell : sameColumnCells) {
175
                if(sameColumnCell.getWidth()<rowWidth){
176
                    rowWidth = sameColumnCell.getWidth();
177
                }
178
            }
179
            
180
            // Obtenemos todas las celdas que est?n a la derecha de donde tenemos que a?adir la columna nueva
181
            List<Cell> nextColumnsCells = getNextColumnsCells(x);
182

    
183
            // Obtenemos todas las celdas que est?n atravesadas por la l?nea vertical de donde tenemos que a?adir la columna nueva
184
            List<Cell> columnTraversedCells = getTraversedColumnCells(x);
185

    
186
            List<Cell> visited = new ArrayList<>();
187
            // A?adimos las celdas de la fila nueva
188
            for (Cell curCell : sameColumnCells) {
189
                Cell c = (Cell) CloneableUtils.cloneQuietly(curCell);
190
                c.setX(x);
191
                c.setWidth(rowWidth);
192
                this.add(c);
193
                visited.add(curCell);
194
            }
195
            
196
            // Movemos las celdas que deben estar a la derecha de la fila nueva
197
            for (Cell curCell : nextColumnsCells) {
198
                curCell.setX(curCell.getX() + rowWidth);
199
                visited.add(curCell);
200
            }
201

    
202
            // Ampliamos la anchura de las celdas que son atravesadas por la l?nea vertical de donde se ha a?adido la columna nueva
203
            for (Cell curCell : columnTraversedCells) {
204
                if(visited.contains(curCell)){
205
                    continue;
206
                }
207
                curCell.setWidth(curCell.getWidth()+ rowWidth);
208
            }
209
            this.dimension.setSize(dimension.getWidth()+rowWidth, dimension.getHeight());
210
            resize(oldDimension);
211
        } catch (Exception ex) {
212
            LOGGER.warn("Can't insert column before cell "+Objects.toString(cell), ex);
213
        }
214
    }
215
    
216
    /**
217
     * Adds a row below the row to which the cell passed as a parameter belongs
218
     * @param cell 
219
     */
220
    public void addRow(Cell cell) {
221
        try {
222
            /* Nos guardamos la dimension del cajetin actual para devolversela al acabar */
223
            Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
224
            /* Obtenemos las celdas  que est?n justo encima de donde tenemos que a?adir una fila nueva
225
            para obtener la altura de la fila que ser? la menor altura
226
            de todas las de la misma fila
227
             */
228
            double y = cell.getY() + cell.getHeight();
229
            List<Cell> previousRowCells = getPreviousRowCells(y);
230
            double rowHeight = Double.POSITIVE_INFINITY;
231
            for (Cell previousRowCell : previousRowCells) {
232
                if(previousRowCell.getHeight()<rowHeight){
233
                    rowHeight = previousRowCell.getHeight();
234
                }
235
            }
236
            
237
            // Obtenemos todas las celdas que est?n debajo de donde tenemos que a?adir una fila nueva
238
            List<Cell> nextRowsCells = getNextRowsCells(y);
239

    
240
            // Obtenemos todas las celdas que est?n atravesadas por la l?nea horizontal de donde tenemos que a?adir una fila nueva
241
            List<Cell> rowTraversedCells = getTraversedRowCells(y);
242

    
243
            List<Cell> visited = new ArrayList<>();
244
            // A?adimos las celdas de la fila nueva
245
            for (Cell curCell : previousRowCells) {
246
                Cell c = (Cell) CloneableUtils.cloneQuietly(curCell);
247
                c.setY(y);
248
                c.setHeight(rowHeight);
249
                this.add(c);
250
                visited.add(curCell);
251
            }
252
            
253
            // Movemos las celdas que deben estar debajo de la fila nueva
254
            for (Cell curCell : nextRowsCells) {
255
                if(visited.contains(curCell)){
256
                    continue;
257
                }
258
                curCell.setY(curCell.getY() + rowHeight);
259
                visited.add(curCell);
260
            }
261
            
262
            // Ampliamos la altura de las celdas que son atravesadas por la l?nea horizontal de donde se ha a?adido la fila nueva
263
            for (Cell curCell : rowTraversedCells) {
264
                if(visited.contains(curCell)){
265
                    continue;
266
                }
267
                curCell.setHeight(curCell.getHeight()+ rowHeight);
268
            }
269
            /*Recalculamos la dimension segun la fila a?adida*/
270
            this.dimension.setSize(dimension.getWidth(), dimension.getHeight() + rowHeight);
271

    
272
            /*Devolvemos la dimension que ten?a el cajet?n de manera proporcionada*/
273
            resize(oldDimension);
274
        } catch (Exception ex) {
275
            LOGGER.warn("Can't add row after cell "+Objects.toString(cell), ex);
276
        }
277
    }
278
    
279
    /**
280
     * Adds a column to the right of the cell column passed as a parameter
281
     * @param cell 
282
     */
283
    public void addColumn(Cell cell) {
284
        try {
285
            /* Nos guardamos la dimension del cajetin actual para devolversela al acabar */
286
            Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
287
            double x = cell.getX() + cell.getWidth();
288
            /* Obtenemos las celdas que est?n justo a la izquierda de donde tenemos que a?adir una fila nueva
289
                para obtener la anchura de la columna que ser? la menor anchura
290
                de todas las de la misma columna
291
            */
292
            List<Cell> previousColumnCells = getPreviousColumnCells(x);
293
            double columnWidth = Double.POSITIVE_INFINITY;
294
            for (Cell previousColumnCell : previousColumnCells) {
295
                if(previousColumnCell.getWidth()<columnWidth){
296
                    columnWidth = previousColumnCell.getWidth();
297
                }
298
            }
299
            
300
            // Obtenemos todas las celdas que est?n a la derecha de donde tenemos que a?adir una fila nueva
301
            List<Cell> nextColumnsCells = getNextColumnsCells(x);
302

    
303
            // Obtenemos todas las celdas que est?n atravesadas por la l?nea vertical de donde tenemos que a?adir la columna nueva
304
            List<Cell> columnTraversedCells = getTraversedColumnCells(cell.getX() + cell.getWidth());
305

    
306
            List<Cell> visited = new ArrayList<>();
307
            // A?adimos las celdas de la columna nueva
308
            for (Cell curCell : previousColumnCells) {
309
                Cell c = (Cell) CloneableUtils.cloneQuietly(curCell);
310
                c.setX(x);
311
                c.setWidth(columnWidth);
312
                this.add(c);
313
                visited.add(curCell);
314
            }
315
            
316
            // Movemos las celdas que deben estar a la derecha de la columna nueva
317
            for (Cell curCell : nextColumnsCells) {
318
                if(visited.contains(curCell)){
319
                    continue;
320
                }
321
                curCell.setX(curCell.getX() + columnWidth);
322
                visited.add(curCell);
323
            }
324
            
325
            // Ampliamos la anchura de las celdas que son atravesadas por la l?nea vertical de donde se ha a?adido la columna nueva
326
            for (Cell curCell : columnTraversedCells) {
327
                if(visited.contains(curCell)){
328
                    continue;
329
                }
330
                curCell.setWidth(curCell.getWidth()+columnWidth);
331
            }
332
            /*Recalculamos la dimension segun la columna a?adida*/
333
            this.dimension.setSize(dimension.getWidth()+columnWidth, dimension.getHeight());
334
            /*Devolvemos la dimension que ten?a el cajet?n de manera proporcionada*/
335
            resize(oldDimension);
336
        } catch (Exception ex) {
337
            LOGGER.warn("Can't insert column after cell "+Objects.toString(cell), ex);
338
        }
339
    }
340
    
341
    /**
342
     * Devuelve las celdas que empiezan en la l?nea horizontal en que est? a una altura y
343
     * 
344
     * @param y
345
     * @return 
346
     */
347
    private List<Cell> getRowCells(double y) {
348
        List<Cell> res = new ArrayList<>();
349
        for (Cell cell : cells) {
350
            if(MathUtils.equals(cell.getY(),y,MAPBOX_EPSILON)) { //FIXME: entorno
351
                res.add(cell);
352
            }
353
        }
354
        return res;
355
    }
356
    
357
    /**
358
     * Devuelve las celdas que empiezan en la l?nea horizontal en que est? a una altura y
359
     * 
360
     * @param y
361
     * @return 
362
     */
363
    private List<Cell> getRowCellsBetween(double y, double y1) {
364
        Set<Cell> res = new HashSet();
365
        for (Cell cell : cells) {
366
            if (MathUtils.equals(cell.getY(), y, MAPBOX_EPSILON)
367
                && MathUtils.equals(cell.getY() + cell.getHeight(), y1, MAPBOX_EPSILON)) {
368
                res.add(cell);
369
            }
370
            if (MathUtils.equals(cell.getY(), y, MAPBOX_EPSILON)
371
                && cell.getY() + cell.getHeight() < y1) {
372
                res.add(cell);
373
            }
374
            if (MathUtils.equals(cell.getY() + cell.getHeight(), y1, MAPBOX_EPSILON)
375
                && cell.getY() > y) {
376
                res.add(cell);
377
            }
378
            if(cell.getY() > y && cell.getY()+cell.getHeight() < y1) {
379
                res.add(cell);
380
            }
381

    
382
        }
383
        return new ArrayList<>(res);
384
    }
385
    
386
    /**
387
     * Devuelve las celdas que empiezan debajo de la l?nea horizontal en que est? a una altura y
388
     * 
389
     * @param y
390
     * @return 
391
     */
392
    private List<Cell> getNextRowsCells(double y) {
393
        List<Cell> res = new ArrayList<>();
394
        for (Cell cell : cells) {
395
            if(cell.getY() >= y || MathUtils.equals(cell.getY(),y,MAPBOX_EPSILON)) {
396
                res.add(cell);
397
            }
398
        }
399
        return res;
400
    }
401
    
402
    /**
403
     * Devuelve las celdas que terminan en la l?nea horizontal que est? a una altura y
404
     * 
405
     * @param y
406
     * @return 
407
     */
408
    private List<Cell> getPreviousRowCells(double y) {
409
        List<Cell> res = new ArrayList<>();
410
        for (Cell cell : cells) {
411
            if(MathUtils.equals(cell.getY()+cell.getHeight(),y,MAPBOX_EPSILON)) {
412
                res.add(cell);
413
            }
414
        }
415
        return res;
416
    }
417
    
418
    /**
419
     * Devuelve las celdas que son atravesadas por la l?nea horizontal que est? a una altura y
420
     * 
421
     * @param y
422
     * @return 
423
     */
424
    private List<Cell> getTraversedRowCells(double y) {
425
        List<Cell> res = new ArrayList<>();
426
        for (Cell cell : cells) {
427
            if(cell.getY() < y && cell.getY()+cell.getHeight() > y) {
428
                res.add(cell);
429
            }
430
        }
431
        return res;
432
    }
433
    
434
    /**
435
     * Devuelve las celdas que empiezan en la l?nea vertical que est? a una distancia x del origen
436
     * 
437
     * @param y
438
     * @return 
439
     */
440
    private List<Cell> getColumnCells(double x) {
441
        List<Cell> res = new ArrayList<>();
442
        for (Cell cell : cells) {
443
            if(MathUtils.equals(cell.getX(),x,MAPBOX_EPSILON)) {
444
                res.add(cell);
445
            }
446
        }
447
        return res;
448
    }
449
    
450
    /**
451
     * Devuelve las celdas que empiezan en la l?nea horizontal en que est? a una altura y
452
     * 
453
     * @param x
454
     * @return 
455
     */
456
    private List<Cell> getColumnCellsBetween(double x, double x1) {
457
        Set<Cell> res = new HashSet();
458
        for (Cell cell : cells) {
459
            if(MathUtils.equals(cell.getX(),x,MAPBOX_EPSILON) && 
460
                MathUtils.equals(cell.getX()+cell.getWidth(),x1,MAPBOX_EPSILON)) {
461
                res.add(cell);
462
            }
463
            if(MathUtils.equals(cell.getX(),x,MAPBOX_EPSILON) && 
464
                cell.getX()+cell.getWidth()< x1) {
465
                res.add(cell);
466
            }
467
            if(MathUtils.equals(cell.getX()+cell.getWidth(),x1,MAPBOX_EPSILON)&& 
468
                cell.getX() > x) {
469
                res.add(cell);
470
            }
471
            if(cell.getX() > x && cell.getX()+cell.getWidth() < x1) {
472
                res.add(cell);
473
            }
474

    
475
        }
476
        return new ArrayList<>(res);
477
    }
478
    
479
    
480
    /**
481
     * Devuelve las celdas que empiezan m?s all? de la l?nea vertical que est? a una distancia x del origen
482
     * 
483
     * @param y
484
     * @return 
485
     */
486
    private List<Cell> getNextColumnsCells(double x) {
487
        List<Cell> res = new ArrayList<>();
488
        for (Cell cell : cells) {
489
            if(cell.getX() >= x || MathUtils.equals(cell.getX(),x,MAPBOX_EPSILON)) {
490
                res.add(cell);
491
            }
492
        }
493
        return res;
494
    }
495
    
496
    /**
497
     * Devuelve las celdas que terminan en la l?nea vertical que est? a una distancia x del origen
498
     * 
499
     * @param y
500
     * @return 
501
     */
502
    private List<Cell> getPreviousColumnCells(double x) {
503
        List<Cell> res = new ArrayList<>();
504
        for (Cell cell : cells) {
505
            if(MathUtils.equals(cell.getX()+cell.getWidth(),x,MAPBOX_EPSILON)) {
506
                res.add(cell);
507
            }
508
        }
509
        return res;
510
    }
511
    
512
    /**
513
     * Devuelve las celdas que son atravesadas por la l?nea vertical que est? a una distancia x del origen
514
     * 
515
     * @param y
516
     * @return 
517
     */
518
    private List<Cell> getTraversedColumnCells(double x) {
519
        List<Cell> res = new ArrayList<>();
520
        for (Cell cell : cells) {
521
            if(cell.getX() < x && cell.getX()+cell.getWidth() > x) {
522
                res.add(cell);
523
            }
524
        }
525
        return res;
526
    }
527
    
528
    public void dump(List<Cell> theCells) {
529
        if(theCells == null){
530
            theCells = cells;
531
        }
532
        for (Cell cell : theCells) {
533
            System.out.println(cell.toString());
534
        }
535
    }
536
    
537
    public void sort() {
538
        Collections.sort(cells, (Cell o1, Cell o2) -> {
539
            int res = Double.compare(o1.getY(), o2.getY());
540
            if(res == 0){
541
                res = Double.compare(o1.getX(), o2.getX());
542
            }
543
            return res;
544
        });
545
    }
546
    
547
    public Cell join(List<Cell> theCells) {
548
        Cell join = (Cell) CloneableUtils.cloneQuietly(theCells.get(0));
549
        for (Cell theCell : theCells) {
550
            join.join(theCell);
551
        }
552
        return join;
553
    }
554
    
555
    public void combine(List<Cell> theCells) {
556
        Cell join = join(theCells);
557
        if(join == null) {
558
            return;
559
        }
560
        removeCells(theCells);
561
        cells.add(join);
562
    }
563
    
564
    public void splitCellHorizontally(Cell theCell) {
565
        double h = theCell.getHeight() / 2;
566
        theCell.setHeight(h);
567
        Cell cloned = (Cell) CloneableUtils.cloneQuietly(theCell);
568
        cloned.setY(theCell.getY() + h);
569
        cells.add(cloned);
570
    }
571

    
572
    public void splitCellsHorizontally(List<Cell> theCells) {
573
        for (Cell theCell : theCells) {
574
            splitCellHorizontally(theCell);
575
        }
576
    }
577

    
578
    public void splitCellVertically(Cell theCell) {
579
        double w = theCell.getWidth() / 2;
580
        theCell.setWidth(w);
581
        Cell cloned = (Cell) CloneableUtils.cloneQuietly(theCell);
582
        cloned.setX(theCell.getX() + w);
583
        cells.add(cloned);
584
    }
585

    
586
    public void splitCellsVertically(List<Cell> theCells) {
587
        for (Cell theCell : theCells) {
588
            splitCellVertically(theCell);
589
        }
590
    }
591

    
592
    public void removeCells(List<Cell> theCells) {
593
        cells.removeAll(theCells);
594
    }
595
    
596
    public void removeCells(Rectangle r) {
597
        for (Iterator<Cell> iterator = cells.iterator(); iterator.hasNext();) {
598
            Cell cell = iterator.next();
599
            if(cell.isContained(r)) { // || cell.intersects(r)){
600
                iterator.remove();
601
            }
602
        }
603
    }
604
    
605
    public void removeColumn(Cell cell) {
606
        /* Nos guardamos la dimension del cajetin actual para devolversela al acabar */
607
        Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
608
        
609
        double x = cell.getX();
610
        double columnWidth = cell.getWidth();
611
        List<Cell> columnCells = getColumnCellsBetween(x, x+columnWidth);
612
        List<Cell> nextColumnsCells = getNextColumnsCells(cell.getX()+cell.getWidth());
613
        List<Cell> leftTraversedColumnsCells = getTraversedColumnCells(cell.getX());
614
        List<Cell> rightTraversedColumnsCells = getTraversedColumnCells(cell.getX()+cell.getWidth());
615
        List<Cell> visited = new ArrayList<>();
616
        for (Cell columnCell : columnCells) {
617
            cells.remove(columnCell);
618
            visited.add(columnCell);
619
        }
620
        for (Cell nextColumnsCell : nextColumnsCells) {
621
            if(visited.contains(nextColumnsCell)){
622
                continue;
623
            }
624
            nextColumnsCell.setX(nextColumnsCell.getX()-columnWidth);
625
            visited.add(nextColumnsCell);
626
        }
627
        for (Cell leftTraversedColumnsCell : leftTraversedColumnsCells) {
628
            if(visited.contains(leftTraversedColumnsCell)){
629
                continue;
630
            }
631
            if(rightTraversedColumnsCells.contains(leftTraversedColumnsCell)){
632
                leftTraversedColumnsCell.setWidth(leftTraversedColumnsCell.getWidth()-columnWidth);
633
            } else {
634
                leftTraversedColumnsCell.setWidth(x-leftTraversedColumnsCell.getX());
635
            }
636
            visited.add(leftTraversedColumnsCell);
637
        }
638
        for (Cell rightTraversedColumnsCell : rightTraversedColumnsCells) {
639
            if(visited.contains(rightTraversedColumnsCell)){
640
                continue;
641
            }
642
            rightTraversedColumnsCell.setWidth(rightTraversedColumnsCell.getX()+rightTraversedColumnsCell.getWidth()-(x+columnWidth));
643
            rightTraversedColumnsCell.setY(x+columnWidth);
644
        }
645
        /*Recalculamos la dimension segun la columna a?adida*/
646
        this.dimension.setSize(dimension.getWidth()-columnWidth, dimension.getHeight());
647
        /*Devolvemos la dimension que ten?a el cajet?n de manera proporcionada*/
648
        resize(oldDimension);
649
    }
650
    
651
    public void removeRow(Cell cell) {
652
        /* Nos guardamos la dimension del cajetin actual para devolversela al acabar */
653
        Dimension2D oldDimension = (Dimension2D)(this.dimension.clone());
654
        double y = cell.getY();
655
        double rowHeight = cell.getHeight();
656
        List<Cell> rowCells = getRowCellsBetween(y, y+rowHeight);
657
        List<Cell> nextRowsCells = getNextRowsCells(cell.getY()+cell.getHeight());
658
        List<Cell> upTraversedRowsCells = getTraversedRowCells(cell.getY());
659
        List<Cell> downTraversedRowsCells = getTraversedRowCells(cell.getY()+cell.getHeight());
660
        List<Cell> visited = new ArrayList<>();
661
        for (Cell rowCell : rowCells) {
662
                cells.remove(rowCell);
663
                visited.add(rowCell);
664
        }
665
        for (Cell nextRowsCell : nextRowsCells) {
666
            if(visited.contains(nextRowsCell)){
667
                continue;
668
            }
669
            nextRowsCell.setY(nextRowsCell.getY()-rowHeight);
670
            visited.add(nextRowsCell);
671
        }
672
        for (Cell upTraversedRowsCell : upTraversedRowsCells) {
673
            if(visited.contains(upTraversedRowsCell)){
674
                continue;
675
            }
676
            if(downTraversedRowsCells.contains(upTraversedRowsCell)){
677
                upTraversedRowsCell.setHeight(upTraversedRowsCell.getHeight()-rowHeight);
678
            } else {
679
                upTraversedRowsCell.setHeight(y-upTraversedRowsCell.getY());
680
            }
681
            visited.add(upTraversedRowsCell);
682
        }
683
        for (Cell downTraversedRowsCell : downTraversedRowsCells) {
684
            if(visited.contains(downTraversedRowsCell)){
685
                continue;
686
            }
687
            downTraversedRowsCell.setHeight(downTraversedRowsCell.getY()+downTraversedRowsCell.getHeight()-(y+rowHeight));
688
            downTraversedRowsCell.setY(y+rowHeight);
689
        }
690
        /*Recalculamos la dimension segun la fila borrada*/
691
        this.dimension.setSize(dimension.getWidth(), dimension.getHeight() - rowHeight);
692
        /*Devolvemos la dimension que ten?a el cajet?n de manera proporcionada*/
693
        resize(oldDimension);
694
        
695
    }
696
    
697
    public void resize(Dimension2D dimension){
698
        if (this.dimension != null) {
699
            double scaleX = dimension.getWidth() / this.dimension.getWidth();
700
            double scaleY = dimension.getHeight() / this.dimension.getHeight();
701
            for (Cell cell : cells) {
702
                cell.setWidth(cell.getWidth() * scaleX);
703
                cell.setHeight(cell.getHeight() * scaleY);
704
                cell.setX(cell.getX() * scaleX);
705
                cell.setY(cell.getY() * scaleY);
706
            }
707
        }
708
        this.dimension = dimension;
709
    }
710
    
711
    @Override
712
    public boolean isEmpty() {
713
        return this.cells.isEmpty();
714
    }
715

    
716
    public Pair<Integer, Cell> getRelativePosition(Point2D p, double tolerance) {
717
        for (Cell cell : cells) {
718
            if(Math.abs(cell.getX()-p.getX())<=tolerance){
719
                return new ImmutablePair<>(POSITION_ON_LEFT_EDGE_OF_CELL, cell);
720
            }
721
            if(Math.abs(cell.getY()-p.getY())<=tolerance){
722
                return new ImmutablePair<>(POSITION_AT_TOP_OF_CELL, cell);
723
            }
724
            if(Math.abs(cell.getX()+cell.getWidth()-p.getX())<=tolerance){
725
                return new ImmutablePair<>(POSITION_ON_RIGHT_EDGE_OF_CELL, cell);
726
            }
727
            if(Math.abs(cell.getY()+cell.getHeight()-p.getY())<=tolerance){
728
                return new ImmutablePair<>(POSITION_AT_BOTOM_OF_CELL, cell);
729
            }
730
            if(cell.getRectangle().contains(p)){
731
                return new ImmutablePair<>(POSITION_IN_CELL, cell);
732
            }
733
        }
734
        return new ImmutablePair<>(POSITION_OUT_OF_MAPBOX, null);
735
    }
736
    
737
    public void moveVerticalLine(double x0, double x1){
738
        List<Cell> columnCells = getColumnCells(x0);
739
        double maxX = Double.POSITIVE_INFINITY;
740
        for (Cell columnCell : columnCells) {
741
            maxX = Math.min(columnCell.getX()+columnCell.getWidth(), maxX);
742
        }
743
        List<Cell> previousColumnCells = getPreviousColumnCells(x0);
744
        double minX = Double.NEGATIVE_INFINITY;
745
        for (Cell previousColumnCell : previousColumnCells) {
746
            minX = Math.max(previousColumnCell.getX(), minX);
747
        }
748
        if(x1 < minX){
749
            throw new IllegalArgumentException("The line cannot be moved beyond the previous cell");
750
        }
751
        if(x1 > maxX){
752
            throw new IllegalArgumentException("The line cannot be moved beyond the next cell");
753
        }
754
        
755
        if(MathUtils.equals(x0, 0d, MAPBOX_EPSILON)) { //Primera l?nea afecta a la dimensi?n del cajet?n
756
            for (Cell cell : cells) {
757
                if(cell.getX() == 0d){
758
                    cell.setWidth(cell.getWidth()-x1);
759
                } else {
760
                    cell.setX(cell.getX()-x1);
761
                }
762
            }
763
            this.dimension.setSize(this.dimension.getWidth()-(x1-x0), this.dimension.getHeight());
764
            
765
        } else if(MathUtils.equals(x0,dimension.getWidth(),MAPBOX_EPSILON)) { //Ultima l?nea afecta a la dimensi?n del cajet?n
766
            for (Cell previousColumnCell : previousColumnCells) {
767
                previousColumnCell.setWidth(x1-previousColumnCell.getX());
768
            }
769
            this.dimension.setSize(this.dimension.getWidth()+(x1-x0), this.dimension.getHeight());
770
            
771
        } else { //No afecta a la dimensi?n del cajet?n
772
            for (Cell previousColumnCell : previousColumnCells) {
773
                previousColumnCell.setWidth(x1-previousColumnCell.getX());
774
            }
775
            for (Cell columnCell : columnCells) {
776
                columnCell.setX(x1);
777
                columnCell.setWidth(columnCell.getWidth()-(x1-x0));
778
            }
779
        }
780
    }
781

    
782
    public void moveHorizontalLine(double y0, double y1){
783
        List<Cell> rowCells = getRowCells(y0);
784
        double maxY = Double.POSITIVE_INFINITY;
785
        for (Cell rowCell : rowCells) {
786
            maxY = Math.min(rowCell.getY()+rowCell.getHeight(), maxY);
787
        }
788
        List<Cell> previousRowCells = getPreviousRowCells(y0);
789
        double minY = Double.NEGATIVE_INFINITY;
790
        for (Cell previousRowCell : previousRowCells) {
791
            minY = Math.max(previousRowCell.getY(), minY);
792
        }
793
        if(y1 < minY){
794
            throw new IllegalArgumentException("The line cannot be moved beyond the previous cell");
795
        }
796
        if(y1 > maxY){
797
            throw new IllegalArgumentException("The line cannot be moved beyond the next cell");
798
        }
799
        
800
        if(MathUtils.equals(y0,0d,MAPBOX_EPSILON)) { //Primera l?nea afecta a la dimensi?n del cajet?n
801
            for (Cell cell : cells) {
802
                if(cell.getY() == 0d){
803
                    cell.setHeight(cell.getHeight()-y1);
804
                } else {
805
                    cell.setY(cell.getY()-y1);
806
                }
807
            }
808
            this.dimension.setSize(this.dimension.getWidth(), this.dimension.getHeight()-(y1-y0));
809
        } else if(MathUtils.equals(y0,dimension.getHeight(),MAPBOX_EPSILON)) { //Ultima l?nea afecta a la dimensi?n del cajet?n
810
            for (Cell previousRowCell : previousRowCells) {
811
                previousRowCell.setHeight(y1-previousRowCell.getY());
812
            }
813
            this.dimension.setSize(this.dimension.getWidth(), this.dimension.getHeight()+(y1-y0));
814
            
815
        } else { //No afecta a la dimensi?n del cajet?n
816
            for (Cell previousRowCell : previousRowCells) {
817
                previousRowCell.setHeight(y1-previousRowCell.getY());
818
            }
819
            for (Cell rowCell : rowCells) {
820
                rowCell.setY(y1);
821
                rowCell.setHeight(rowCell.getHeight()-(y1-y0));
822
            }
823
        }
824
    }
825
    
826
    @Override
827
    public Object clone() throws CloneNotSupportedException {
828
        MapBoxModel other = (MapBoxModel) super.clone();
829
        
830
        List<Cell> clonedCells = new ArrayList<>();
831
        for (Cell cell : cells) {
832
            clonedCells.add(cell.clone());
833
        }
834
        other.cells = clonedCells;
835
        if(this.dimension != null){
836
            other.dimension = (Dimension2D) this.dimension.clone();
837
        }
838
        return other;
839
    }
840

    
841
    public static void registerPersistent() {
842
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
843
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
844
            DynStruct definition =
845
                manager.addDefinition(MapBoxModel.class,
846
                    PERSISTENCE_DEFINITION_NAME,
847
                    "FFrameMapBox persistence definition", null, null);
848

    
849
            definition.addDynFieldList("cells").setClassOfItems(Cell.class).setMandatory(true);
850
            definition.addDynFieldDouble("width").setMandatory(true);
851
            definition.addDynFieldDouble("height").setMandatory(true);
852
        }
853
    }
854

    
855
    @Override
856
    public void loadFromState(PersistentState state)
857
        throws PersistenceException {
858
        List<Cell> c = state.getList("cells");
859
        if(c!=null){
860
            this.cells = new ArrayList<>(c);
861
        }
862
        double width = state.getDouble("width");
863
        double height = state.getDouble("height");
864
        this.dimension = new Dimension2DDouble(width, height);
865
    }
866

    
867
    @Override
868
    public void saveToState(PersistentState state) throws PersistenceException {
869
        state.set("cells", this.cells);
870
        state.set("width", this.dimension.getWidth());
871
        state.set("height", this.dimension.getHeight());
872
    }
873
    
874
}