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 1714 fdiaz
/*
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
}