Statistics
| Revision:

root / trunk / libraries / libTopology / src / com / vividsolutions / jcs / conflate / roads / ConflationSession.java @ 22873

History | View | Annotate | Download (15.2 KB)

1 22873 azabala
package com.vividsolutions.jcs.conflate.roads;
2
3
import java.io.*;
4
import java.util.*;
5
6
import com.vividsolutions.jcs.conflate.roads.match.RoadMatchOptions;
7
import com.vividsolutions.jcs.conflate.roads.match.RoadMatcherProcess;
8
import com.vividsolutions.jcs.conflate.roads.model.*;
9
import com.vividsolutions.jcs.conflate.roads.model.sourcematchconsistency.SourceMatchConsistencyRule;
10
import com.vividsolutions.jcs.jump.FUTURE_CollectionUtil;
11
import com.vividsolutions.jts.geom.*;
12
import com.vividsolutions.jts.util.Assert;
13
import com.vividsolutions.jump.feature.*;
14
import com.vividsolutions.jump.task.TaskMonitor;
15
import com.vividsolutions.jump.util.*;
16
import com.vividsolutions.jump.workbench.ui.plugin.AddNewLayerPlugIn;
17
18
/**
19
 * The overall container class that represents the entire process of merging two
20
 * RoadNetworks.
21
 *
22
 * @author David Zwiers, Vivid Solutions Inc.
23
 * @author jaquino Vivid Solutions Inc.
24
 */
25
public class ConflationSession implements Serializable {
26
27
        public static final String DEFAULT_NAME = "New Session";
28
29
        /**
30
         * Returns any coincident segments in the input data. If there are no
31
         * coincident segments in a source dataset, the corresponding feature
32
         * collection will be empty.
33
         *
34
         * @return an array of 2 {@link FeatureCollection}s containing any
35
         *         coincident segments.
36
         */
37
        private static FeatureCollection[] getIllegalGeometries(
38
                        FeatureCollection[] inputFC) {
39
                FeatureCollection[] illegalGeometryFC = new FeatureCollection[2];
40
                illegalGeometryFC[0] = getIllegalGeometries(inputFC[0]);
41
                illegalGeometryFC[1] = getIllegalGeometries(inputFC[1]);
42
                return illegalGeometryFC;
43
        }
44
45
        private boolean automatedProcessRunning = false;
46
47
        /**
48
         * Checks for valid edge geometry. Edge geometry must be simple LineStrings.
49
         * If there are no illegal geometries the feature collection will be empty.
50
         *
51
         * @return a {@link FeatureCollection}containing any edges with illegal
52
         *         geometry
53
         */
54
        private static FeatureCollection getIllegalGeometries(
55
                        FeatureCollection inputFC) {
56
                FeatureCollection fc = new FeatureDataset(inputFC.getFeatureSchema());
57
                for (Iterator i = inputFC.iterator(); i.hasNext();) {
58
                        Feature f = (Feature) i.next();
59
                        Geometry geom = f.getGeometry();
60
                        boolean isValid = geom instanceof LineString && geom.isSimple();
61
                        if (!isValid)
62
                                fc.add(f);
63
                }
64
                return fc;
65
        }
66
67
        /** Transient because the UI stuff is not Serializable */
68
        private transient RoadsEventFirer roadsEventFirer;
69
70
        private boolean autoMatched = false;
71
72
        private String name;
73
74
        private Statistics statistics = new Statistics(this);
75
76
        private RoadMatchOptions matchOptions = new RoadMatchOptions();
77
78
        private ConsistencyRule consistencyRule = new SourceMatchConsistencyRule();
79
80
        private FeatureCollection[] originalFeatureCollections;
81
82
        private FeatureCollection[] coincidentSegmentFeatureCollections;
83
84
        private FeatureCollection[] illegalGeometryFC;
85
86
        private PrecedenceRuleEngine precedenceRuleEngine;
87
88
        private boolean[] warningAboutAdjustments = new boolean[] { false, false };
89
90
        private FeatureCollection[] contextFeatureCollections;
91
92
        private FeatureCollection[] unmatchedNodeConstraints;
93
94
        public boolean isWarningAboutAdjustments(int i) {
95
                //TODO: Combine #warningAboutAdjustments with
96
                //RoadNetwork#editable into a single field: #adjustmentConstraint.
97
                //Easiest is to implement it as a String -- if instead we go with the
98
                //enum pattern, remember to implement #readResolve.
99
                //[Jon Aquino 2004-04-30]
100
                return warningAboutAdjustments[i];
101
        }
102
103
        public void setWarningAboutAdjustments(int i,
104
                        boolean warningAboutAdjustments) {
105
                this.warningAboutAdjustments[i] = warningAboutAdjustments;
106
        }
107
108
        /**
109
         * This is not dead code! #readObject is a special serialization method.
110
         */
111
        private void readObject(ObjectInputStream in) throws IOException,
112
                        ClassNotFoundException {
113
                in.defaultReadObject();
114
                getRoadsEventFirer().addListener(statistics);
115
        }
116
117
        public ConflationSession(FeatureCollection originalFeatureCollection0,
118
                        FeatureCollection originalFeatureCollection1) {
119
                this(DEFAULT_NAME, originalFeatureCollection0,
120
                                originalFeatureCollection1, AddNewLayerPlugIn
121
                                                .createBlankFeatureCollection(), AddNewLayerPlugIn
122
                                                .createBlankFeatureCollection(), AddNewLayerPlugIn
123
                                                .createBlankFeatureCollection(), AddNewLayerPlugIn
124
                                                .createBlankFeatureCollection());
125
        }
126
127
        public ConflationSession(String name,
128
                        FeatureCollection originalFeatureCollection0,
129
                        FeatureCollection originalFeatureCollection1,
130
                        FeatureCollection contextFeatureCollection0,
131
                        FeatureCollection contextFeatureCollection1,
132
                        FeatureCollection nodeConstraints0,
133
                        FeatureCollection nodeConstraints1) {
134
                setName(name);
135
                getRoadsEventFirer().addListener(statistics);
136
                originalFeatureCollections = new FeatureCollection[] {
137
                                originalFeatureCollection0, originalFeatureCollection1 };
138
                contextFeatureCollections = new FeatureCollection[] {
139
                                contextFeatureCollection0, contextFeatureCollection1 };
140
                // do validations on input features
141
                illegalGeometryFC = getIllegalGeometries(originalFeatureCollections);
142
                FeatureCollection hideConflationAttributesFeatureCollection0 = new HideConflationAttributesFeatureCollectionWrapper(
143
                                originalFeatureCollection0);
144
                FeatureCollection hideConflationAttributesFeatureCollection1 = new HideConflationAttributesFeatureCollectionWrapper(
145
                                originalFeatureCollection1);
146
                sourceNetworks[0] = new RoadNetwork(SourceFeature
147
                                .createSchema(hideConflationAttributesFeatureCollection0
148
                                                .getFeatureSchema()), this);
149
                sourceNetworks[1] = new RoadNetwork(SourceFeature
150
                                .createSchema(hideConflationAttributesFeatureCollection1
151
                                                .getFeatureSchema()), this);
152
                //Ensure sourceNetworks field is populated before adding to the
153
                //networks, because RoadNetwork#add leads to a call to
154
                //ConflationSession#getSourceNetworkN [Jon Aquino 12/1/2003]
155
                initializeSourceNetwork(sourceNetworks[0],
156
                                hideConflationAttributesFeatureCollection0);
157
                initializeSourceNetwork(sourceNetworks[1],
158
                                hideConflationAttributesFeatureCollection1);
159
                unmatchedNodeConstraints = new FeatureCollection[] {
160
                                assignNodeConstraints(nodeConstraints0, getSourceNetwork(0)),
161
                                assignNodeConstraints(nodeConstraints1, getSourceNetwork(1)) };
162
        }
163
164
        private static FeatureCollection assignNodeConstraints(
165
                        FeatureCollection nodeConstraints, RoadNetwork network) {
166
                Collection unassignedNodeConstraints = new ArrayList();
167
                Set nodeConstraintCoordinates = new HashSet();
168
                for (Iterator i = nodeConstraints.iterator(); i.hasNext();) {
169
                        Feature feature = (Feature) i.next();
170
                        //Allow multipoints as workaround for ShapefileWriter bug: it seems
171
                        //to save points as multipoints. [Jon Aquino 2004-06-01]
172
                        if (!(feature.getGeometry() instanceof Point)
173
                                        && !(feature.getGeometry() instanceof MultiPoint)) {
174
                                unassignedNodeConstraints.add(feature.getGeometry());
175
                                continue;
176
                        }
177
                        nodeConstraintCoordinates.addAll(Arrays.asList(feature
178
                                        .getGeometry().getCoordinates()));
179
                }
180
                unassignedNodeConstraints.addAll(assignNodeConstraints(
181
                                nodeConstraintCoordinates, network));
182
                return toFeatureCollection(unassignedNodeConstraints);
183
        }
184
185
        private static FeatureCollection toFeatureCollection(Collection geometries) {
186
                FeatureCollection featureCollection = AddNewLayerPlugIn
187
                                .createBlankFeatureCollection();
188
                for (Iterator i = geometries.iterator(); i.hasNext();) {
189
                        Geometry geometry = (Geometry) i.next();
190
                        Feature feature = new BasicFeature(featureCollection
191
                                        .getFeatureSchema());
192
                        feature.setGeometry(geometry);
193
                        featureCollection.add(feature);
194
                }
195
                return featureCollection;
196
        }
197
198
        private static Collection assignNodeConstraints(
199
                        Set nodeConstraintCoordinates, RoadNetwork network) {
200
                Set unassignedNodeConstraints = new HashSet(nodeConstraintCoordinates);
201
                for (Iterator i = network.getGraph().getEdges().iterator(); i.hasNext();) {
202
                        SourceRoadSegment roadSegment = (SourceRoadSegment) i.next();
203
                        roadSegment.setStartNodeConstrained(nodeConstraintCoordinates
204
                                        .contains(roadSegment.getApparentStartCoordinate()));
205
                        roadSegment.setEndNodeConstrained(nodeConstraintCoordinates
206
                                        .contains(roadSegment.getApparentEndCoordinate()));
207
                        unassignedNodeConstraints.remove(roadSegment
208
                                        .getApparentStartCoordinate());
209
                        unassignedNodeConstraints.remove(roadSegment
210
                                        .getApparentEndCoordinate());
211
                }
212
                return CollectionUtil.collect(unassignedNodeConstraints, new Block() {
213
                        public Object yield(Object coordinate) {
214
                                return geometryFactory.createPoint((Coordinate) coordinate);
215
                        }
216
                });
217
        }
218
219
        private static GeometryFactory geometryFactory = new GeometryFactory();
220
221
        /**
222
         * Returns any coincident segments in the input data. If there are no
223
         * coincident segments in a source dataset, the corresponding feature
224
         * collection will be empty.
225
         *
226
         * @return an array of 2 {@link FeatureCollection}s containing any
227
         *         coincident segments.
228
         */
229
        public FeatureCollection[] getCoincidentSegments() {
230
                if (coincidentSegmentFeatureCollections == null) {
231
                        coincidentSegmentFeatureCollections = new FeatureCollection[2];
232
                        coincidentSegmentFeatureCollections[0] = sourceNetworks[0]
233
                                        .checkCoincidentEdges();
234
                        coincidentSegmentFeatureCollections[1] = sourceNetworks[1]
235
                                        .checkCoincidentEdges();
236
                }
237
                return coincidentSegmentFeatureCollections;
238
        }
239
240
        /**
241
         * Returns any coincident segments in the input data. If there are no
242
         * coincident segments in a source dataset, the corresponding feature
243
         * collection will be empty.
244
         *
245
         * @return an array of 2 {@link FeatureCollection}s containing any
246
         *         coincident segments.
247
         */
248
        public FeatureCollection[] getIllegalGeometries() {
249
                return illegalGeometryFC;
250
        }
251
252
        public RoadMatchOptions getMatchOptions() {
253
                return matchOptions;
254
        }
255
256
        public RoadMatcherProcess autoMatch(final TaskMonitor monitor) {
257
                //Assert.isTrue(!autoMatched);
258
                // MD - for now, run automatching right away. Probably eventually needs
259
                // to be done under user control
260
                final RoadMatcherProcess rm = new RoadMatcherProcess(
261
                                getSourceNetwork(0), getSourceNetwork(1));
262
                doAutomatedProcess(new Block() {
263
                        public Object yield() {
264
                                rm.match(matchOptions, monitor);
265
                                return null;
266
                        }
267
                });
268
                autoMatched = true;
269
                return rm;
270
        }
271
272
        public void updateResultStates(final TaskMonitor monitor) {
273
                Block block = new Block() {
274
                        public Object yield() {
275
                                int totalRoadSegments = getSourceNetwork(0).getGraph()
276
                                                .getEdges().size()
277
                                                + getSourceNetwork(1).getGraph().getEdges().size();
278
                                int[] roadSegmentsUpdated = new int[] { 0 };
279
                                updateResultStates(getSourceNetwork(0), monitor,
280
                                                totalRoadSegments, roadSegmentsUpdated);
281
                                updateResultStates(getSourceNetwork(1), monitor,
282
                                                totalRoadSegments, roadSegmentsUpdated);
283
                                return null;
284
                        }
285
                };
286
                if (getConsistencyRule() instanceof Optimizable) {
287
                        ((Optimizable) getConsistencyRule()).doOptimizedOp(block);
288
                } else {
289
                        block.yield();
290
                }
291
        }
292
293
        public void doAutomatedProcess(Block process) {
294
                boolean automatedProcessRunningOriginally = automatedProcessRunning;
295
                automatedProcessRunning = true;
296
                try {
297
                        process.yield();
298
                } finally {
299
                        automatedProcessRunning = automatedProcessRunningOriginally;
300
                }
301
        }
302
303
        private void updateResultStates(RoadNetwork network, TaskMonitor monitor,
304
                        int totalRoadSegments, int[] roadSegmentsUpdated) {
305
                monitor.report("Updating result states");
306
                for (Iterator i = network.getGraph().getEdges().iterator(); i.hasNext();) {
307
                        SourceRoadSegment roadSegment = (SourceRoadSegment) i.next();
308
                        roadSegment.setResultState(ResultStateRules.instance()
309
                                        .determineResultState(roadSegment));
310
                        monitor.report(++roadSegmentsUpdated[0], totalRoadSegments,
311
                                        "road segments");
312
                }
313
        }
314
315
        private void initializeSourceNetwork(RoadNetwork sourceNetwork,
316
                        FeatureCollection originalFeatureCollection) {
317
                for (Iterator i = originalFeatureCollection.iterator(); i.hasNext();) {
318
                        Feature originalFeature = (Feature) i.next();
319
                        Geometry geom = (Geometry) originalFeature.getGeometry().clone();
320
                        if (geom instanceof LineString) {
321
                                sourceNetwork.add(new SourceRoadSegment((LineString) geom,
322
                                                originalFeature, sourceNetwork));
323
                        }
324
                }
325
        }
326
327
        public RoadNetwork getSourceNetwork(int index) {
328
                return sourceNetworks[index];
329
        }
330
331
        public RoadNetwork getSourceNetwork(String name) {
332
                if (sourceNetworks[0].getName().equals(name)) {
333
                        return sourceNetworks[0];
334
                }
335
                if (sourceNetworks[1].getName().equals(name)) {
336
                        return sourceNetworks[1];
337
                }
338
                Assert.shouldNeverReachHere();
339
                return null;
340
        }
341
342
        public FeatureCollection getOriginalFeatureCollection(int index) {
343
                return originalFeatureCollections[index];
344
        }
345
346
        public FeatureCollection getContextFeatureCollection(int index) {
347
                return contextFeatureCollections[index];
348
        }
349
350
        private RoadNetwork[] sourceNetworks = new RoadNetwork[2];
351
352
        public int getIndex(RoadNetwork network){
353
                if(sourceNetworks[0].equals(network))
354
                        return 0;
355
                if(sourceNetworks[1].equals(network))
356
                        return 1;
357
                return -1;
358
        }
359
360
        public Statistics getStatistics() {
361
                return statistics;
362
        }
363
364
        public ConsistencyRule getConsistencyRule() {
365
                return consistencyRule;
366
        }
367
368
        private Blackboard blackboard = new Blackboard();
369
370
        private File file;
371
372
        public Blackboard getBlackboard() {
373
                return blackboard;
374
        }
375
376
        public void setFile(File file) {
377
                this.file = file;
378
        }
379
380
        public File getFile() {
381
                return file;
382
        }
383
384
        public ConflationSession setConsistencyRule(ConsistencyRule consistencyRule) {
385
                this.consistencyRule = consistencyRule;
386
                return this;
387
        }
388
389
        public boolean isAutoMatched() {
390
                return autoMatched;
391
        }
392
393
        public RoadsEventFirer getRoadsEventFirer() {
394
                if (roadsEventFirer == null) {
395
                        //Get here after deserialization [Jon Aquino 2004-01-29]
396
                        roadsEventFirer = new RoadsEventFirer();
397
                }
398
                return roadsEventFirer;
399
        }
400
401
        public void setMatchOptions(RoadMatchOptions matchOptions) {
402
                this.matchOptions = matchOptions;
403
        }
404
405
        public PrecedenceRuleEngine getPrecedenceRuleEngine() {
406
                return precedenceRuleEngine;
407
        }
408
409
        public void setPrecedenceRuleEngine(
410
                        PrecedenceRuleEngine precedenceRuleEngine) {
411
                this.precedenceRuleEngine = precedenceRuleEngine;
412
        }
413
414
        private boolean locked = false;
415
416
        public String getName() {
417
                return name;
418
        }
419
420
        public void setName(String name) {
421
                this.name = name;
422
        }
423
424
        public Collection getRoadSegments() {
425
                return FUTURE_CollectionUtil.concatenate(getSourceNetwork(0).getGraph()
426
                                .getEdges(), getSourceNetwork(1).getGraph().getEdges());
427
        }
428
429
        public boolean isAutomatedProcessRunning() {
430
                return automatedProcessRunning;
431
        }
432
433
        public FeatureCollection[] getUnmatchedNodeConstraints() {
434
                return unmatchedNodeConstraints;
435
        }
436
437
        /**
438
         * @param locked
439
         */
440
        public void setLocked(boolean locked) {
441
                this.locked = locked;
442
        }
443
444
        /**
445
         * @return locked
446
         */
447
        public boolean isLocked() {
448
                return locked;
449
        }
450
451
        private boolean filterDataSetsZoom = true;
452
453
        /**
454
         * @return Returns the filterDataSetsZoom.
455
         */
456
        public boolean isFilterDataSetsZoom() {
457
                return filterDataSetsZoom;
458
        }
459
460
        /**
461
         * @param filterDataSetsZoom The filterDataSetsZoom to set.
462
         */
463
        public void setFilterDataSetsZoom(boolean filterDataSetsZoom) {
464
                this.filterDataSetsZoom = filterDataSetsZoom;
465
        }
466
467
        private HashMap dataLayers = new HashMap();
468
469
        public void addDataLayer(String string, FeatureCollection collection) {
470
                dataLayers.put(string, collection);
471
        }
472
473
        public FeatureCollection getDataLayer(String string){
474
                return (FeatureCollection) dataLayers.get(string);
475
        }
476
477
        public List getDataLayerNames(){
478
                return new ArrayList(dataLayers.keySet());
479
        }
480
}