Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / Topology.java @ 17134

History | View | Annotate | Download (28.4 KB)

1
/*
2
 * Created on 07-sep-2007
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
21
 *
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
/* CVS MESSAGES:
45
 *
46
 * $Id: 
47
 * $Log: 
48
 */
49
package org.gvsig.topology;
50

    
51
import java.awt.geom.Rectangle2D;
52
import java.util.ArrayList;
53
import java.util.Collection;
54
import java.util.Collections;
55
import java.util.HashMap;
56
import java.util.Iterator;
57
import java.util.List;
58
import java.util.Map;
59

    
60
import org.apache.log4j.Logger;
61
import org.cresques.cts.IProjection;
62
import org.gvsig.topology.topologyrules.MustBeLargerThanClusterTolerance;
63

    
64
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
65
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
66
import com.iver.cit.gvsig.fmap.MapContext;
67
import com.iver.cit.gvsig.fmap.core.FShape;
68
import com.iver.cit.gvsig.fmap.layers.CancelationException;
69
import com.iver.cit.gvsig.fmap.layers.FLayer;
70
import com.iver.cit.gvsig.fmap.layers.FLayers;
71
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
72
import com.iver.cit.gvsig.fmap.layers.XMLException;
73
import com.iver.utiles.IPersistence;
74
import com.iver.utiles.XMLEntity;
75
import com.iver.utiles.swing.threads.CancellableProgressTask;
76

    
77
/**
78
 * 
79
 * This class represents a Topology, as a group of vectorial layers
80
 * and topology rules that checks geometries and their spatial relationships of
81
 * these layers.
82
 * 
83
 * It extends FLayers to reuse all already existent code related with
84
 * groups of layers (TOC related, etc.)
85
 * 
86
 * 
87
 * 
88
 * TODO Study if we must syncronize writing methods (validate, markAsException, addError,
89
 * ruleId++, etc)
90
 * Study how to add ChangeStatusListener to this topology
91
 * 
92
 * @author azabala
93
 *
94
 */
95
public class Topology extends FLayers implements ITopologyStatus, ITopologyErrorContainer {
96

    
97

    
98
        private static Logger logger = Logger.getLogger(Topology.class.getName());
99
        
100
        /**
101
         * topology name
102
         */
103
        private String name;
104
        /**
105
         * cluster tolerance of the topology
106
         */
107
        
108
        private double clusterTolerance;
109

    
110
        /**
111
         * validation status of the topology
112
         */
113
        private byte status = EMPTY;
114

    
115
        
116
        /**
117
         * If during validation process a topoly exceeds this parameters, validation
118
         * will be stopped.
119
         * 
120
         */
121
        private int maxNumberOfErrors = -1;
122

    
123
        
124
        /**
125
         * topology rules of the topology
126
         */
127
        private List<ITopologyRule> rules;
128

    
129
        
130
        /**
131
         * Each layer of a topology must have a cluster tolerance rule
132
         */
133
        private List<MustBeLargerThanClusterTolerance> clusterToleranceRules;
134

    
135
        
136
        /**
137
         * Regions of the topology to be validated
138
         */
139
        private List<Rectangle2D> dirtyZones;
140

    
141
        /**
142
         * Error container in which topology delegates error container
143
         * responsability.
144
         */
145
        private ITopologyErrorContainer errorContainer;
146
        
147
        
148
        /**
149
         * Map that relates a FLyrVect of the Topology with its rank (weight when we
150
         * are going to snap many coordinates)
151
         */
152
        private Map<FLyrVect, XYZLayerRank> layerRanks;
153
        
154
        /**
155
         * Numerical identifier for rules of a topology
156
         */
157
        private int ruleId = 0;
158
        
159
        /**
160
         * Default constructor for a topology as a FLayers
161
         * 
162
         * @param fmap
163
         * @param parent
164
         */
165
        public Topology(MapContext fmap, 
166
                                        FLayers parent, 
167
                                        double clusterTolerance, 
168
                                        int numberOfErrors,
169
                                        ITopologyErrorContainer errorContainer) {
170
                super(fmap, parent);
171
                this.clusterTolerance = clusterTolerance;
172
                this.maxNumberOfErrors = numberOfErrors;
173
                this.errorContainer = errorContainer;
174
                
175
                rules = new ArrayList<ITopologyRule>();
176
                clusterToleranceRules = new ArrayList<MustBeLargerThanClusterTolerance>();
177
                dirtyZones = new ArrayList<Rectangle2D>();
178
                layerRanks = new HashMap<FLyrVect, XYZLayerRank>();
179
        }
180

    
181
        
182
        
183
        public Topology(MapContext mapContext, FLayers layers){
184
                this(mapContext, layers, 0d, 1000, new SimpleTopologyErrorContainer());
185
        }
186
        
187
        
188
        /**
189
         * Creates a topology from its XML representation
190
         * @param xmlEntity
191
         * @return
192
         */
193
        public static Topology createFromXML(MapContext mapContext, XMLEntity xmlEntity){
194
                FLayers rootLyr = mapContext.getLayers();
195
                Topology solution = new Topology(mapContext, rootLyr);
196
                
197
                try {
198
                        solution.setXMLEntity(xmlEntity);
199
                        if(solution.getErrorContainer() == null){
200
                                solution.setErrorContainer(new SimpleTopologyErrorContainer());
201
                        }
202
                } catch (XMLException e) {
203
                        logger.error("Error al reconstruir la topologia desde fichero xml", e);
204
                }
205
                return solution;
206
        }
207

    
208
        /**
209
         * Changes the cluster tolerance of the topology
210
         * 
211
         * 
212
         * This operation resets the status of the topology (it clears
213
         * errors and dirty zones)
214
         * 
215
         * @param clusterTolerance
216
         */
217
        public void setClusterTolerance(double clusterTolerance) {
218
                if(status == VALIDATING)
219
                        return;//maybe we could launch an exception??
220
                this.clusterTolerance = clusterTolerance;
221
                resetStatus();
222
                Iterator<MustBeLargerThanClusterTolerance> rulesIt = this.clusterToleranceRules.iterator();
223
                while(rulesIt.hasNext()){
224
                        MustBeLargerThanClusterTolerance rule = rulesIt.next();
225
                        rule.setClusterTolerance(clusterTolerance);
226
                }
227
                
228
        }
229

    
230
        public double getClusterTolerance() {
231
                return clusterTolerance;
232
        }
233
        
234
        public void resetStatus(){
235
                status = NOT_VALIDATED;
236
                this.clear();
237
                this.dirtyZones.clear();
238
        }
239

    
240
        /**
241
         * Adds a new topology rule to the topology.
242
         * 
243
         * The layers referenced by the rule must exist in the topology.
244
         * 
245
         * The state of the topology changes to "NON_VALIDATED", and a new dirty zone
246
         * is added for the scope of the new rule (envelope of one or two layers).
247
         * 
248
         * 
249
         * @throws TopologyRuleDefinitionException
250
         */
251
        public void addRule(ITopologyRule rule) throws RuleNotAllowedException,
252
                        TopologyRuleDefinitionException {
253

    
254
                if(status == VALIDATING)
255
                        throw new RuleNotAllowedException("No se puede a?adir una regla si la topologia est? siendo validada");
256
                
257
                
258
                Rectangle2D ruleScope = null;
259
                try {
260
                        if (rule instanceof IOneLyrRule) {
261
                                FLyrVect originLyr = ((IOneLyrRule) rule).getOriginLyr();
262
                                if (getLayer(originLyr.getName()) == null) {
263
                                        throw new RuleNotAllowedException(
264
                                                        "Regla con capa  que no forma parte de la topologia");
265
                                }
266
                                ruleScope = originLyr.getFullExtent();
267
                        }
268
                        if (rule instanceof ITwoLyrRule) {
269
                                FLyrVect destLyr = ((ITwoLyrRule) rule).getDestinationLyr();
270
                                if (getLayer(destLyr.getName()) == null) {
271
                                        throw new RuleNotAllowedException(
272
                                                        "Regla con capa  que no forma parte de la topologia");
273
                                }
274
                                if (ruleScope != null)
275
                                        ruleScope.add(destLyr.getFullExtent());
276
                        }
277
                } catch (ExpansionFileReadException e) {
278
                        e.printStackTrace();
279
                        throw new TopologyRuleDefinitionException(e);
280
                } catch (ReadDriverException e) {
281
                        e.printStackTrace();
282
                        throw new TopologyRuleDefinitionException(e);
283
                }
284
                
285
                // before to add the rule we check if it verifies preconditions
286
                rule.checkPreconditions();
287
                rules.add(rule);
288
                
289
//   Si se a?ade una nueva regla, no es posible conservar los errores
290
//   y las zonas sucias previas
291
//                if(status == EMPTY)
292
//                        status = NOT_VALIDATED;
293
//                else if(status == VALIDATED ){
294
//                        status = VALIDATED_WITH_DIRTY_ZONES;
295
//                        addDirtyZone(ruleScope);
296
//                }else if(status == VALIDATED_WITH_ERRORS){
297
//                        //we dont change the status, but add a new dirty zone
298
//                        addDirtyZone(ruleScope);
299
//                }
300
                resetStatus();
301
                rule.setTopologyErrorContainer(this);
302
                rule.setId(this.ruleId++);
303
        }
304
        
305
        
306
        
307

    
308
        /*
309
         * Overwrited implementations of FLayers methods
310
         */
311
        
312
        public void addLayer(FLayer layer) {
313
                addLayer(layers.size(), layer);
314
        }
315

    
316
        public void addLayer(int pos, FLayer layer)  {
317
                if (!(layer instanceof FLyrVect))
318
                        throw new WrongLyrForTopologyException(
319
                                        "Intentando a?adir capa no vectorial a una topologia");
320
                super.addLayer(pos, layer);
321
                setRank((FLyrVect) layer, 1, 1);
322
                
323
                int shapeType = -1;
324
                try {
325
                        shapeType = ((FLyrVect)layer).getShapeType();
326
                        if( (shapeType == FShape.POINT) || (shapeType == FShape.MULTIPOINT) || (shapeType == FShape.TEXT))
327
                                return;
328
                } catch (ReadDriverException e) {
329
                        e.printStackTrace();
330
                        throw new WrongLyrForTopologyException("Error al intentar verificar el tipo de geometria de la capa", e);
331
                }
332
                
333
                
334
                MustBeLargerThanClusterTolerance rule = new 
335
                        MustBeLargerThanClusterTolerance(this, (FLyrVect) layer, clusterTolerance);
336
                rule.setId(this.ruleId++);
337
                Rectangle2D ruleScope;
338
                try {
339
                        ruleScope = layer.getFullExtent();
340
//                 before to add the rule we check if it verifies preconditions
341
                        rule.checkPreconditions();
342
                        
343
                        if(status == EMPTY)
344
                                status = NOT_VALIDATED;
345
                        else if(status == VALIDATED ){
346
                                status = VALIDATED_WITH_DIRTY_ZONES;
347
                                addDirtyZone(ruleScope);
348
                        }else if(status == VALIDATED_WITH_ERRORS){
349
                                //we dont change the status, but add a new dirty zone
350
//                                addDirtyZone(ruleScope);
351
                                //si habia errores, la reevaluacion haria que se repitiesen
352
                                resetStatus();
353
                        }
354
                        rule.setTopologyErrorContainer(this);
355
                        clusterToleranceRules.add(rule);
356
                        
357
                } catch (ExpansionFileReadException e) {
358
                        e.printStackTrace();
359
                        throw new WrongLyrForTopologyException("No es posible acceder all FullExtent de la capa", e);
360
                } catch (ReadDriverException e) {
361
                        e.printStackTrace();
362
                        throw new WrongLyrForTopologyException("No es posible acceder all FullExtent de la capa", e);
363
                } catch (TopologyRuleDefinitionException e) {
364
                        e.printStackTrace();
365
                        throw new WrongLyrForTopologyException("Regla topologica mal definida", e);
366
                }
367
        }
368

    
369
        /**
370
         * Sets the rank/importance of a layer in xy and z planes.
371
         * 
372
         * @param lyr layer
373
         * 
374
         * @param xyRank importance of this layer coordinates in xy plane
375
         * 
376
         * @param zRank importante of this layer coordinates in z plane
377
         */
378
        public void setRank(FLyrVect lyr, int xyRank, int zRank) {
379
                XYZLayerRank rank = new XYZLayerRank(lyr.getName(), xyRank, zRank);
380
                layerRanks.put(lyr, rank);
381
        }
382
        
383
        
384
        public XYZLayerRank getRank(FLyrVect lyr){
385
                return layerRanks.get(lyr);
386
        }
387

    
388
        /**
389
         * Adds a layer to the topology. If the topology has been validated, changes
390
         * topology status to NON-VALIDATED and adds a dirty zone equals to the
391
         * layer extent.
392
         */
393
        public void addLayer(FLyrVect layer, int xyRank, int zRank) {
394
                this.addLayer(layer);
395
                setRank(layer, xyRank, zRank);
396
        }
397
        
398
        /**
399
         * Remove a layer from a topology.
400
         * 
401
         * This task is more complex than removing a layer from a LayerCollection:
402
         * -must remove all rules which references to this layer.
403
         * -must recompute status and dirty zones.
404
         * etc.
405
         * 
406
         * TODO Implement remove layer as a geoprocess.
407
         * 
408
         */
409
        public void removeLayer(FLayer lyr) throws CancelationException {
410
//                super.removeLayer(lyr);
411
//                this.layerRanks.remove(lyr);
412
        }
413

    
414
        /**
415
         * Ranks (in xy plane and z plane) for layers of the topology.
416
         * 
417
         * The rank of layer marks its weight for computing weihgted average
418
         * coordinates.
419
         * 
420
         * @author azabala
421
         * 
422
         */
423
        class XYZLayerRank implements IPersistence {
424
                int xyRank;
425
                int zRank;
426
                String layerName;
427

    
428
                XYZLayerRank(String layerName, int xyRank, int zRank) {
429
                        this.layerName = layerName;
430
                        this.xyRank = xyRank;
431
                        this.zRank = zRank;
432
                }
433
                
434
                XYZLayerRank(){}
435

    
436
                public String getClassName() {
437
                        return this.getClass().getName();
438
                }
439

    
440
                public XMLEntity getXMLEntity() {
441
                        XMLEntity solution = new XMLEntity();
442
                        solution.putProperty("layerName", layerName);
443
                        solution.putProperty("xyRank", xyRank);
444
                        solution.putProperty("zRank", zRank);
445
                        return solution;
446
                }
447

    
448
                public void setXMLEntity(XMLEntity xml) {
449
                        if(xml.contains("layerName"))
450
                                layerName = xml.getStringProperty("layerName");
451
                        
452
                        if(xml.contains("xyRank"))
453
                                xyRank = xml.getIntProperty("xyRank");
454
                        
455
                        if(xml.contains("zRank"))
456
                                zRank = xml.getIntProperty("zRank");
457
                        
458
                }
459
        }
460

    
461
        public void setStatus(byte status) {
462
                this.status = status;
463
        }
464

    
465
        public byte getStatus() {
466
                return status;
467
        }
468

    
469
        /**
470
         * Adds a dirty zone to the topology (usually whe a feature of a layer of
471
         * the topology has been edited)
472
         */
473
        public void addDirtyZone(Rectangle2D newDirtyZone) {
474
                if(status == NOT_VALIDATED)
475
                        return;
476
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
477
                while (zonesIt.hasNext()) {
478
                        Rectangle2D dirtyZone = zonesIt.next();
479
                        if (dirtyZone.contains(newDirtyZone)) {
480
                                return;// we dont add this dirty zone. Its redundant
481
                        }
482
                        if (newDirtyZone.contains(dirtyZone)) {
483
                                zonesIt.remove();
484
                                dirtyZones.add(newDirtyZone);
485
                                return;
486
                        }
487

    
488
                        if (dirtyZone.intersects(newDirtyZone)) {
489
                                dirtyZone.add(newDirtyZone);
490
                                return;
491
                        }
492
                }// while
493
                
494
                if(status == VALIDATED)
495
                        status = VALIDATED_WITH_DIRTY_ZONES;
496
                
497
                // at this point, we add the new dirty zone
498
                dirtyZones.add(newDirtyZone);
499
        }
500
        
501
        
502
        public void removeDirtyZone(Rectangle2D newDirtyZone) {
503
                if(status == NOT_VALIDATED)
504
                        return;//maybe we must launch an inconsistent status exception
505
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
506
                while (zonesIt.hasNext()) {
507
                        Rectangle2D dirtyZone = zonesIt.next();
508
                        if (newDirtyZone.contains(dirtyZone)) {
509
                                zonesIt.remove();
510
                                continue;
511
                        }
512
                }// while
513

    
514
                // at this point, we add the new dirty zone
515
                dirtyZones.remove(newDirtyZone);
516
        }
517
        
518

    
519
        public Rectangle2D getDirtyZone(int i) {
520
                return dirtyZones.get(i);
521
        }
522
        
523
        public int getNumberOfDirtyZones(){
524
                return dirtyZones.size();
525
        }
526
        
527
        
528
        public void validate(){
529
                validate(null);
530
        }
531
        
532
        /**
533
         * Validates the topology: it validates each topology rule for the given
534
         * dirty zones. After the end of the process,
535
         */
536
        public void validate(CancellableProgressTask progressMonitor) {
537
                
538
                if(progressMonitor != null){
539
                        progressMonitor.setInitialStep(0);
540
                        int numOfSteps = rules.size() + clusterToleranceRules.size();
541
                        progressMonitor.setFinalStep(numOfSteps);
542
                        progressMonitor.setDeterminatedProcess(true);
543
                        progressMonitor.setNote(Messages.getText("Validating_a_topology"));
544
                        progressMonitor.setStatusMessage(Messages.getText(rules.get(0).getDescription()));
545
                }
546
                
547
                
548
                if (this.status == EMPTY) {
549
                        //TODO Maybe we must do progressMonitor.setFinished(true)
550
                        //or throw an exception
551
                        return;
552
                } else if (this.status == VALIDATED) {
553
                        return;
554
                } 
555
                
556
                else if (this.status == NOT_VALIDATED){
557
                        status = VALIDATING;
558
                        
559
                        
560
                        //we make a local copy of dirty zones to avoid to use dirty zones created in 
561
                        //the current validation.
562
                        ArrayList<Rectangle2D> dirtyZonesCopy = new ArrayList<Rectangle2D>();
563
                        Collections.copy(dirtyZonesCopy, this.dirtyZones);
564
                        Iterator<MustBeLargerThanClusterTolerance> it = 
565
                                clusterToleranceRules.iterator();
566
                        while(it.hasNext()){
567
                                MustBeLargerThanClusterTolerance rule = it.next();
568
                                if(progressMonitor != null){
569
                                        if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
570
                                                resetStatus();
571
                                                return;
572
                                        }
573
                                        progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
574
                                                   Messages.getText(rule.getName()));
575
                                        progressMonitor.reportStep();
576
                                   }
577
                                
578
                                if(getNumberOfErrors() >= this.maxNumberOfErrors){
579
                                        if(progressMonitor != null)
580
                                                progressMonitor.setCanceled(true);
581
                                        return;
582
                                }
583
                                
584
                                rule.checkRule(progressMonitor);
585
                        }
586
                        
587
                        Iterator<ITopologyRule> rulesIt = this.rules.iterator();
588
                        while (rulesIt.hasNext()) {
589
                                ITopologyRule rule = rulesIt.next();
590
                                
591
                                if(progressMonitor != null){
592
                                        if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
593
                                                resetStatus();
594
                                                return;
595
                                        }
596
                                        progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
597
                                                   Messages.getText(rule.getName()));
598
                                        progressMonitor.reportStep();
599
                                   }
600
                                
601
                                if(getNumberOfErrors() >= this.maxNumberOfErrors){
602
                                        if(progressMonitor != null)
603
                                                progressMonitor.setCanceled(true);
604
                                        return;
605
                                }
606
                                
607
                                if(dirtyZonesCopy.size() == 0){
608
                                        rule.checkRule(progressMonitor);
609
                                }else{
610
                                        //A topology is NON_VALIDATED with dirty zones when
611
                                        //it has VALIDATED status and we add a new rule.
612
                                        
613
                                        //TODO Check to add a new rule to a topology
614
                                        //with VALIDATED_WITH_ERROR status
615
                                        Iterator<Rectangle2D> dirtyZonesIt = dirtyZonesCopy.iterator();
616
                                        while(dirtyZonesIt.hasNext()){
617
                                                Rectangle2D rect = dirtyZonesIt.next();
618
                                                rule.checkRule(progressMonitor,rect);
619
                                        }//while
620
                                }//else
621
                        }//while
622
                        if(this.errorContainer.getNumberOfErrors() > 0)
623
                                this.status = VALIDATED_WITH_ERRORS;
624
                        else
625
                                this.status = VALIDATED;        
626
                }
627
                else if (this.status == VALIDATED_WITH_ERRORS || 
628
                                this.status == ITopologyStatus.VALIDATED_WITH_DIRTY_ZONES) {
629
                        status = VALIDATING;
630
                        // this topology must have at least one dirty zone
631
                        if (this.dirtyZones.size() < 1){
632
//                                 FIXME Deberiamos lanzar una
633
                                // InconsistentStatusException ??
634
                                return;
635
                        }
636

    
637
                        Iterator<Rectangle2D> dirtyZonesIt = this.dirtyZones.iterator();
638
                        while (dirtyZonesIt.hasNext()) {
639
                                Rectangle2D dirtyZone = dirtyZonesIt.next();
640
                                
641
                                Iterator<MustBeLargerThanClusterTolerance> it = this.clusterToleranceRules.iterator();
642
                                while(it.hasNext()){
643
                                        MustBeLargerThanClusterTolerance rule = it.next();
644
                                        if(progressMonitor != null){
645
                                                if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
646
                                                        resetStatus();
647
                                                        return;
648
                                                }
649
                                                progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
650
                                                           Messages.getText(rule.getName()));
651
                                                progressMonitor.reportStep();
652
                                           }
653
                                        
654
                                        if(getNumberOfErrors() >= this.maxNumberOfErrors){
655
                                                if(progressMonitor != null)
656
                                                        progressMonitor.setCanceled(true);
657
                                                return;
658
                                        }
659
                                        
660
                                        rule.checkRule(dirtyZone);
661
                                }
662
                                
663
                                Iterator<ITopologyRule> rulesIt = this.rules.iterator();
664
                                while (rulesIt.hasNext()) {
665
                                        ITopologyRule rule = rulesIt.next();
666
                                        if(progressMonitor != null){
667
                                                if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
668
                                                        resetStatus();
669
                                                        return;
670
                                                }
671
                                                progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
672
                                                           Messages.getText(rule.getName()));
673
                                                progressMonitor.reportStep();
674
                                           }
675
                                        
676
                                        if(getNumberOfErrors() >= this.maxNumberOfErrors){
677
                                                if(progressMonitor != null)
678
                                                        progressMonitor.setCanceled(true);
679
                                                return;
680
                                        }
681
                                        rule.checkRule(dirtyZone);
682
                                }//while
683
                                
684
                                
685
                        }//while
686
                        if(this.errorContainer.getNumberOfErrors() > 0)
687
                                this.status = VALIDATED_WITH_ERRORS;
688
                        else
689
                                this.status = VALIDATED;
690
                }//if
691
        }
692

    
693
        public int getLayerCount() {
694
                return super.getLayersCount();
695
        }
696
        
697
        public List getLayers(){
698
                return this.layers;
699
        }
700

    
701
        public int getRuleCount() {
702
                return rules.size();
703
        }
704

    
705
        public FLyrVect getLyr(int lyrIndex) {
706
                return (FLyrVect) super.getLayer(lyrIndex);
707
        }
708

    
709
        public ITopologyRule getRule(int ruleIndex) {
710
                return rules.get(ruleIndex);
711
        }
712
        
713
        public ITopologyRule getRuleById(int ruleId){
714
                for(int i = 0; i < rules.size(); i++){
715
                        ITopologyRule rule = rules.get(i);
716
                        if(rule.getId() == ruleId){
717
                                return rule;
718
                        }//if
719
                }//for
720
                
721
                for(int i = 0; i < clusterToleranceRules.size(); i++){
722
                        MustBeLargerThanClusterTolerance rule = clusterToleranceRules.get(i);
723
                        if(rule.getId() == ruleId){
724
                                return rule;
725
                        }//if
726
                }
727
                return null;
728
        }
729

    
730
        /**
731
         * Returns if a specified rectangle touch one of the existing dirty zones.
732
         * If not, probably is needed to add to the dirty zones collection. If true,
733
         * maybe it could modify the dirty zone.
734
         */
735
        public boolean isInDirtyZone(Rectangle2D envelope) {
736
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
737
                while (zonesIt.hasNext()) {
738
                        Rectangle2D rect = zonesIt.next();
739
                        if (rect.contains(envelope))
740
                                return true;
741
                }
742
                return false;
743
        }
744

    
745
        /**
746
         * Modify the dirty zone of the specified index
747
         * 
748
         * TODO Make thread safe ?
749
         */
750
        public void updateDirtyZone(int dirtyZoneIndex, Rectangle2D dirtyZone) {
751
                dirtyZones.remove(dirtyZoneIndex);
752
                dirtyZones.add(dirtyZoneIndex, dirtyZone);
753
        }
754

    
755
        public void setMaxNumberOfErrors(int maxNumberOfErrors) {
756
                this.maxNumberOfErrors = maxNumberOfErrors;
757
        }
758

    
759
        public int getMaxNumberOfErrors() {
760
                return maxNumberOfErrors;
761
        }
762

    
763
        /*
764
         * @see org.gvsig.topology.ITopologyErrorContainer#addTopologyError(org.gvsig.topology.TopologyError)
765
         */
766

    
767
        public void addTopologyError(TopologyError topologyError) {
768
                errorContainer.addTopologyError(topologyError);
769
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
770
                addDirtyZone(rect);
771
        }
772

    
773
        /**
774
         * marks topologyErrors as an exception (and removes its bounds of the 
775
         * dirty zones list)
776
         * @param topologyError error to mark as exceptions
777
         */
778
        public void markAsTopologyException(TopologyError topologyError) {
779
                errorContainer.markAsTopologyException(topologyError);
780
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
781
                removeDirtyZone(rect);
782
                
783
                if(status == VALIDATED_WITH_DIRTY_ZONES){
784
                        if(dirtyZones.size() == 0)
785
                                status = VALIDATED;
786
                }else if(status == VALIDATED_WITH_ERRORS){
787
                        if(getNumberOfErrors() == getNumberOfExceptions())
788
                                status = VALIDATED;
789
                }
790
        }
791
        
792
        public void demoteToError(TopologyError topologyError) {
793
                errorContainer.demoteToError(topologyError);
794
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
795
                addDirtyZone(rect);
796
                if(getNumberOfErrors() > getNumberOfExceptions() )
797
                        status = VALIDATED_WITH_ERRORS;
798
        }
799

    
800
        
801
        
802
        public List<TopologyError> getTopologyErrorsByLyr(FLyrVect layer,
803
                                                                                                        IProjection desiredProjection, 
804
                                                                                                        boolean includeExceptions) {
805
                
806
                return errorContainer.getTopologyErrorsByLyr(layer, 
807
                                                                                 desiredProjection,  
808
                                                                                 includeExceptions);
809
        }
810

    
811
        public List<TopologyError> getTopologyErrorsByRule(String ruleName,
812
                        IProjection desiredProjection, boolean includeExceptions) {
813
                
814
                return errorContainer.getTopologyErrorsByRule(ruleName, 
815
                                                                                                desiredProjection, 
816
                                                                                                includeExceptions);
817
        }
818
        
819

    
820
        public List<TopologyError> getTopologyErrorsByShapeType(int shapeType,
821
                        IProjection desiredProjection, boolean includeExceptions) {
822
                return errorContainer.getTopologyErrorsByShapeType(shapeType, 
823
                                                                                                        desiredProjection, 
824
                                                                                                        includeExceptions);        
825
        }
826

    
827
        
828
        /**
829
         * Get TopologyError filtered byte shapeType, sourte layer of the rule which
830
         * was violtated by this error.
831
         */
832
        public List<TopologyError> getTopologyErrors(String ruleName,
833
                        int shapeType, FLyrVect sourceLayer, IProjection desiredProjection,
834
                        boolean includeExceptions) {
835

    
836
                return errorContainer.getTopologyErrors(ruleName,
837
                                                                                                shapeType, 
838
                                                                                                sourceLayer, 
839
                                                                                                desiredProjection, 
840
                                                                                                includeExceptions);
841
        }
842

    
843
        /**
844
         * Return an unique identifier for the error saved in this
845
         * TopologyErrorContainer.
846
         * 
847
         * Until a new error would be added to this error container, it will
848
         * return always the same error fid.
849
         */
850
        public synchronized String getErrorFid() {
851
                return errorContainer.getErrorFid();
852
        }
853

    
854
        public int getNumberOfErrors() {
855
                return errorContainer.getNumberOfErrors();
856
        }
857

    
858
        public TopologyError getTopologyError(int index) {
859
                return errorContainer.getTopologyError(index);
860
        }
861
        
862
        public void clear() {
863
                errorContainer.clear();
864
        }
865

    
866
        public XMLEntity getXMLEntity() throws XMLException{
867
                
868
                //Topology is a subclass of FLayers, so the call to super
869
                //allows to persist layer status, toc information and layers
870
                XMLEntity xml = super.getXMLEntity();
871
                
872
                //Si no ponemos esto className ser? FLayerDefault, no??
873
                xml.putProperty("className", this.getClass().getName());
874
                xml.putProperty("name", name);
875
                xml.putProperty("clusterTolerance", clusterTolerance);
876
                xml.putProperty("status", status);
877
                xml.putProperty("maxNumberOfErrors", maxNumberOfErrors);
878
                
879
                int numberOfTopologyRules = rules.size();
880
                xml.putProperty("numberOfTopologyRules", numberOfTopologyRules);
881
                for(int i = 0; i < numberOfTopologyRules; i++){
882
                        ITopologyRule rule = rules.get(i);
883
                        xml.addChild(rule.getXMLEntity());
884
                }
885
                
886
                
887
                int numberOfClusterRules = clusterToleranceRules.size();
888
                xml.putProperty("numberOfClusterRules", numberOfClusterRules);
889
                for(int i = 0; i < numberOfClusterRules; i++){
890
                        MustBeLargerThanClusterTolerance rule = clusterToleranceRules.get(i);
891
                        xml.addChild(rule.getXMLEntity());
892
                }
893
                
894
                int numberOfDirtyZones = dirtyZones.size();
895
                xml.putProperty("numberOfDirtyZones", numberOfDirtyZones);
896
                for(int i = 0; i < numberOfDirtyZones; i++){
897
                        Rectangle2D rect = dirtyZones.get(i);
898
                        if(rect != null){
899
                                XMLEntity dirtyZoneXML = new XMLEntity();
900
                                dirtyZoneXML.putProperty("extent" + i + "X", rect.getX());
901
                                dirtyZoneXML.putProperty("extent" + i + "Y", rect.getY());
902
                                dirtyZoneXML.putProperty("extent" + i + "W", rect.getWidth());
903
                                dirtyZoneXML.putProperty("extent" + i + "H", rect.getHeight());        
904
                                
905
                                xml.addChild(dirtyZoneXML);
906
                        }//if
907
                        
908
                }//for
909
                
910
                XMLEntity errorContainerXML = errorContainer.getXMLEntity();
911
                xml.addChild(errorContainerXML);
912
                
913
                Collection<XYZLayerRank> ranksVal = layerRanks.values();
914
                int numberOfRanks = ranksVal.size();
915
                xml.putProperty("numberOfRanks", numberOfRanks);
916
                Iterator<XYZLayerRank> xyzRankIterator = layerRanks.values().iterator();
917
                while(xyzRankIterator.hasNext()){
918
                        XYZLayerRank layerRank = xyzRankIterator.next();
919
                        XMLEntity entity = layerRank.getXMLEntity();
920
                        xml.addChild(entity);
921
                }
922
                return xml;
923
        }
924
        
925

    
926
        public void setXMLEntity(XMLEntity xml) throws XMLException {
927
                super.setXMLEntity(xml);
928
                
929
                //FIXME Cambiar el uso de childrenCount por el empleo de propiedades
930
                int numLayers = this.getLayersCount();
931
                int numProperties = this.getExtendedProperties().size();
932
                
933
                int childrenCount = numLayers + numProperties;
934
                
935
                if(xml.contains("clusterTolerance"))
936
                {
937
                        this.clusterTolerance = xml.getDoubleProperty("clusterTolerance");
938
                }
939
                
940
                if(xml.contains("name"))
941
                {
942
                        this.name = xml.getStringProperty("name");
943
                }
944
                
945
                if(xml.contains("status"))
946
                {
947
                        this.status = (byte) xml.getIntProperty("status");
948
                }
949
                
950
                if(xml.contains("maxNumberOfErrors"))
951
                {
952
                        this.maxNumberOfErrors =  xml.getIntProperty("maxNumberOfErrors");
953
                }
954
                
955
                if(xml.contains("numberOfTopologyRules"))
956
                {
957
                        int numberOfTopologyRules =   xml.getIntProperty("numberOfTopologyRules");
958
                        for(int i = 0; i < numberOfTopologyRules; i++){
959
                                XMLEntity ruleXML = xml.getChild(childrenCount++);
960
                                ITopologyRule rule = TopologyRuleFactory.createFromXML(this, ruleXML);
961
                                this.rules.add(rule);
962
                        }
963
                }
964
                
965
                
966
                if(xml.contains("numberOfClusterRules")){
967
                        int numberOfClusterRules = xml.getIntProperty("numberOfClusterRules");
968
                        for(int i = 0; i < numberOfClusterRules; i++){
969
                                XMLEntity ruleXML = xml.getChild(childrenCount++);
970
                                MustBeLargerThanClusterTolerance rule = (MustBeLargerThanClusterTolerance)TopologyRuleFactory.createFromXML(this, ruleXML);
971
                                this.clusterToleranceRules.add(rule);
972
                        }
973
                }
974
                
975
                if(xml.contains("numberOfDirtyZones")){
976
                        int numberOfDirtyZones = xml.getIntProperty("numberOfDirtyZones");
977
                        for(int i = 0; i < numberOfDirtyZones; i++){
978
                                XMLEntity dirtyZoneXml = xml.getChild(childrenCount++);
979
                                double x = dirtyZoneXml.getDoubleProperty("extent"+i+"X");
980
                                double y = dirtyZoneXml.getDoubleProperty("extent"+i+"Y");
981
                                double w = dirtyZoneXml.getDoubleProperty("extent"+i+"W");
982
                                double h = dirtyZoneXml.getDoubleProperty("extent"+i+"H");
983
                                
984
                                Rectangle2D.Double rect = new Rectangle2D.Double(x, y, w, h);
985
                                dirtyZones.add(rect);
986
                        }
987
                }
988
                
989
                
990
                
991
                XMLEntity errorContainerXML = xml.getChild(childrenCount++);
992
                if(errorContainerXML != null)
993
                {
994
                        this.errorContainer = TopologyPersister.createErrorContainerFromXML(errorContainerXML);
995
                }
996
                
997
                if(xml.contains("numberOfRanks")){
998
                        int numberOfRanks = xml.getIntProperty("numberOfRanks");
999
                        for(int i = 0; i < numberOfRanks; i++){
1000
                                XMLEntity xmlRank = xml.getChild(childrenCount++);
1001
                                XYZLayerRank rank = new XYZLayerRank();
1002
                                rank.setXMLEntity(xmlRank);
1003
                        }
1004
                }                
1005
        }
1006

    
1007
        public int getNumberOfExceptions() {
1008
                return this.errorContainer.getNumberOfExceptions();
1009
        }
1010

    
1011

    
1012

    
1013
        public String getName() {
1014
                return name;
1015
        }
1016

    
1017

    
1018

    
1019
        public void setName(String name) {
1020
                this.name = name;
1021
        }
1022
        
1023
        public ITopologyErrorContainer getErrorContainer(){
1024
                return this.errorContainer;
1025
        }
1026
        
1027
        public void setErrorContainer(ITopologyErrorContainer errorContainer){
1028
                this.errorContainer = errorContainer;
1029
        }
1030

    
1031
}