Statistics
| Revision:

root / trunk / libraries / libTopology / src / org / gvsig / topology / Topology.java @ 17054

History | View | Annotate | Download (28.1 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
                } catch (XMLException e) {
200
                        logger.error("Error al reconstruir la topologia desde fichero xml", e);
201
                }
202
                return solution;
203
        }
204

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

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

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

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

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

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

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

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

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

    
425
                XYZLayerRank(String layerName, int xyRank, int zRank) {
426
                        this.layerName = layerName;
427
                        this.xyRank = xyRank;
428
                        this.zRank = zRank;
429
                }
430
                
431
                XYZLayerRank(){}
432

    
433
                public String getClassName() {
434
                        return this.getClass().getName();
435
                }
436

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

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

    
458
        public void setStatus(byte status) {
459
                this.status = status;
460
        }
461

    
462
        public byte getStatus() {
463
                return status;
464
        }
465

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

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

    
511
                // at this point, we add the new dirty zone
512
                dirtyZones.remove(newDirtyZone);
513
        }
514
        
515

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

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

    
690
        public int getLayerCount() {
691
                return super.getLayersCount();
692
        }
693
        
694
        public List getLayers(){
695
                return this.layers;
696
        }
697

    
698
        public int getRuleCount() {
699
                return rules.size();
700
        }
701

    
702
        public FLyrVect getLyr(int lyrIndex) {
703
                return (FLyrVect) super.getLayer(lyrIndex);
704
        }
705

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

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

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

    
752
        public void setMaxNumberOfErrors(int maxNumberOfErrors) {
753
                this.maxNumberOfErrors = maxNumberOfErrors;
754
        }
755

    
756
        public int getMaxNumberOfErrors() {
757
                return maxNumberOfErrors;
758
        }
759

    
760
        /*
761
         * @see org.gvsig.topology.ITopologyErrorContainer#addTopologyError(org.gvsig.topology.TopologyError)
762
         */
763

    
764
        public void addTopologyError(TopologyError topologyError) {
765
                errorContainer.addTopologyError(topologyError);
766
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
767
                addDirtyZone(rect);
768
        }
769

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

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

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

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

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

    
833
                return errorContainer.getTopologyErrors(ruleName,
834
                                                                                                shapeType, 
835
                                                                                                sourceLayer, 
836
                                                                                                desiredProjection, 
837
                                                                                                includeExceptions);
838
        }
839

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

    
851
        public int getNumberOfErrors() {
852
                return errorContainer.getNumberOfErrors();
853
        }
854

    
855
        public TopologyError getTopologyError(int index) {
856
                return errorContainer.getTopologyError(index);
857
        }
858
        
859
        public void clear() {
860
                errorContainer.clear();
861
        }
862

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

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

    
1004
        public int getNumberOfExceptions() {
1005
                return this.errorContainer.getNumberOfExceptions();
1006
        }
1007

    
1008

    
1009

    
1010
        public String getName() {
1011
                return name;
1012
        }
1013

    
1014

    
1015

    
1016
        public void setName(String name) {
1017
                this.name = name;
1018
        }
1019

    
1020
}