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 |
} |