Statistics
| Revision:

root / trunk / libraries / libTopology / src / com / vividsolutions / jcs / conflate / boundarymatch / MatchedSegment.java @ 22873

History | View | Annotate | Download (10.1 KB)

1

    
2

    
3
/*
4
 * The JCS Conflation Suite (JCS) is a library of Java classes that
5
 * can be used to build automated or semi-automated conflation solutions.
6
 *
7
 * Copyright (C) 2003 Vivid Solutions
8
 * 
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 * 
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 * 
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 * 
23
 * For more information, contact:
24
 *
25
 * Vivid Solutions
26
 * Suite #1A
27
 * 2328 Government Street
28
 * Victoria BC  V8T 5G5
29
 * Canada
30
 *
31
 * (250)385-6040
32
 * www.vividsolutions.com
33
 */
34

    
35
package com.vividsolutions.jcs.conflate.boundarymatch;
36

    
37
import java.util.*;
38
import com.vividsolutions.jts.geom.Coordinate;
39
import com.vividsolutions.jump.geom.*;
40

    
41
import com.vividsolutions.jts.geom.LineSegment;
42

    
43
/**
44
 * Contains the information about the linesegments (or subsegments)
45
 * in other {@link Feature}s which
46
 * match a given {@link LineSegment}.
47
 * If one of the matching segments is identical, the <code>hasExactMatch</code>
48
 * flag is set.
49
 */
50
public class MatchedSegment
51
{
52
  private MatchedShell matchedShell;
53
  private int index;
54
  private LineSegment lineseg;  // the LineSegment for this segment
55
  private List matchedSubsegs = new ArrayList();
56
  private boolean isMatchesSorted = false;
57
  private boolean hasExactMatch = false;
58
  private List adjustedVertices = new ArrayList();
59

    
60
  public MatchedSegment(MatchedShell matchedShell, int index)
61
  {
62
    this.matchedShell = matchedShell;
63
    this.index = index;
64
    Coordinate p0 = matchedShell.getCoordinate(index);
65
    Coordinate p1 = matchedShell.getCoordinate(index + 1);
66
    lineseg = new LineSegment(p0, p1);
67
  }
68

    
69
  public LineSegment getSegment() { return lineseg; }
70
  public MatchedShell getEdge() { return matchedShell; }
71

    
72
  /**
73
   * Adds a segment which matches part or all of this segment.
74
   *
75
   * @param matchSeg the segment which matches this segment
76
   * @param distanceTolerance the tolerance value for the match
77
   */
78
  public void addMatchedSegment(MatchedSegment matchSeg, double distanceTolerance)
79
  {
80
    MatchedSubsegment ss = new MatchedSubsegment(lineseg, matchSeg, distanceTolerance);
81
    matchedSubsegs.add(ss);
82
    /**
83
     * Attach subsegs to the matched segment too.
84
     * This info will be used later to adjust the matched seg
85
     */
86
    matchSeg.matchedSubsegs.add(ss);
87

    
88
    if (lineseg.equalsTopo(matchSeg.lineseg)) {
89
        hasExactMatch = true;
90
        matchSeg.hasExactMatch = true;
91
    }
92
    /* DEBUGGING OUTPUT ONLY
93
    System.out.print(index + " : ");
94
    if (hasExactMatch)
95
        Debug.println(lineseg + "   has exact match");
96
    else
97
        Debug.println(lineseg + "   matches  " + mls.index + ": " + mls.lineseg);
98
    */
99
  }
100

    
101
  /**
102
   * Determine whethers this segment needs to have adjustments computed
103
   *
104
   * @return true if this segment needs to have adjustments computed
105
   */
106
  public boolean isAdjustable()
107
  {
108
    if (matchedSubsegs.size() <= 0) return false;
109
    if (hasExactMatch) return false;
110
    return true;
111
  }
112

    
113
  public boolean isAdjusted()
114
  {
115
    if (hasExactMatch) return false;
116
    boolean isAdjusted = false;
117
    for (int i = 0; i < matchedSubsegs.size(); i++) {
118
      MatchedSubsegment subSeg = (MatchedSubsegment) matchedSubsegs.get(i);
119
      /**
120
       * Within each Subsegment
121
       * coordinates are sorted in order along the target segment.
122
       * The first and last coordinates are not added
123
       * if they are adjusted versions of the segment endpoints,
124
       * since these will be provided by the corresponding MatchedVertex
125
       */
126
      if (i >= 0 || ! subSeg.isEndPointAdjusted(0))
127
        isAdjusted = true;
128
      if (i < matchedSubsegs.size() - 1  || ! subSeg.isEndPointAdjusted(1))
129
        isAdjusted = true;
130
    }
131
    return isAdjusted;
132
  }
133

    
134
  public void computeAdjusted()
135
  {
136
    /**
137
     * Sort the matched subsegments in order along this segment.  Note that this
138
     * code does not attempt to handle robustness problems - if the segments are
139
     * too short they may be incorrectly sorted.  Choosing a reasonably large
140
     * tolerance value should prevent this situation from happening.
141
     */
142
    if (! isMatchesSorted)  {
143
      Collections.sort(matchedSubsegs);
144
      isMatchesSorted = true;
145
    }
146
    /**
147
     * Record the adjusted vertices in the associated matched segment.
148
     * These vertices will be later inserted into the adjusted segment.
149
     */
150
    for (int i = 0; i < matchedSubsegs.size(); i++) {
151
      MatchedSubsegment subSeg = (MatchedSubsegment) matchedSubsegs.get(i);
152
      MatchedSegment matchedSeg = subSeg.getMatchedSegment();
153
      matchedSeg.addAdjustedVertex(subSeg.getAdjustedCoordinate(0));
154
      matchedSeg.addAdjustedVertex(subSeg.getAdjustedCoordinate(1));
155
    }
156
  }
157

    
158
  public void addInsertedSubjectVertices(CoordinateList coordList)
159
  {
160
    // matched segments are sorted along the Subject segment
161
    for (int i = 0; i < matchedSubsegs.size(); i++) {
162
      MatchedSubsegment refSeg = (MatchedSubsegment) matchedSubsegs.get(i);
163
      /**
164
       * Within each SourceSubsegment
165
       * coordinates are sorted in order along the target segment.
166
       * The first and last coordinates are not added
167
       * if they are adjusted versions of the segment endpoints,
168
       * since these will be provided by the corresponding MatchedVertex
169
       */
170
      if (i > 0 || ! refSeg.isEndPointAdjusted(0))
171
        coordList.add(refSeg.getAdjustedCoordinate(0));
172
      if (i < matchedSubsegs.size() - 1  || ! refSeg.isEndPointAdjusted(1))
173
        coordList.add(refSeg.getAdjustedCoordinate(1));
174
    }
175
  }
176

    
177
  private boolean isAdjustedVertex(Coordinate p)
178
  {
179
    Coordinate p0 = matchedShell.getAdjustedVertex(index);
180
    if (p.equals(p0)) return true;
181
    Coordinate p1 = matchedShell.getAdjustedVertex(index + 1);
182
    if (p.equals(p1)) return true;
183
    return false;
184
  }
185

    
186
  private void addAdjustedVertexIndicator(Coordinate adjPt, List adjInd)
187
  {
188
    // if a vertex has been adjusted to the same pt, don't create an indicator
189
    if (isAdjustedVertex(adjPt)) return;
190

    
191
    Coordinate origPt = lineseg.project(adjPt);
192
    Coordinate[] line = MatchedShellSubject.createAdjustedVertexIndicator(origPt, adjPt);
193
    adjInd.add(line);
194
  }
195

    
196
  public void addAdjustedVertexIndicators(List adjIndList)
197
  {
198
    // matched segments are sorted along the Subject segment
199
    for (int i = 0; i < matchedSubsegs.size(); i++) {
200
      MatchedSubsegment refSeg = (MatchedSubsegment) matchedSubsegs.get(i);
201
      /**
202
       * Within each subsubsegment
203
       * coordinates are sorted in order along the Subject segment.
204
       * The first and last coordinates are not added
205
       * if they are adjusted versions of the segment endpoints,
206
       * since these will be provided by the corresponding MatchedVertex
207
       */
208
      if (i > 0 || ! refSeg.isEndPointAdjusted(0)) {
209
        addAdjustedVertexIndicator(refSeg.getAdjustedCoordinate(0), adjIndList);
210
      }
211
      if (i < matchedSubsegs.size() - 1  || ! refSeg.isEndPointAdjusted(1)) {
212
        addAdjustedVertexIndicator(refSeg.getAdjustedCoordinate(1), adjIndList);
213
      }
214

    
215
// testing only - test range of size of adjustments
216
/*
217
System.out.println("adjusted 0: "
218
+ refSeg.getAdjustedCoordinate(0)
219
+ " "
220
+ CGAlgorithms.distancePointLine(refSeg.getAdjustedCoordinate(0),
221
      lineseg.p0, lineseg.p1) );
222
System.out.println("adjusted 1: "
223
+ refSeg.getAdjustedCoordinate(1)
224
+ "   "
225
+ CGAlgorithms.distancePointLine(refSeg.getAdjustedCoordinate(1),
226
      lineseg.p0, lineseg.p1)
227
);
228
      */
229
    }
230
  }
231

    
232
  public boolean isEndPointAdjusted(int index)
233
  {
234
    MatchedSubsegment srcSeg = getExtremalMatchedSegment(index);
235
    if (srcSeg == null) return false;
236
    return srcSeg.isEndPointAdjusted(index);
237
  }
238

    
239
  public Coordinate getAdjustedEndPoint(int index)
240
  {
241
    MatchedSubsegment srcSeg = getExtremalMatchedSegment(index);
242
    if (srcSeg == null) return null;
243
    return srcSeg.getAdjustedCoordinate(index);
244
  }
245

    
246
  /**
247
   * Find one or other of the extremal matched segments (i.e. the end items
248
   * in the list)
249
   *
250
   * @param index 0 or 1, depending on whether the first or last matched segment is desired
251
   */
252
  private MatchedSubsegment getExtremalMatchedSegment(int index)
253
  {
254
    if (matchedSubsegs.size() < 1) return null;
255
    MatchedSubsegment srcSeg = null;
256
    switch (index) {
257
    case 0:
258
      srcSeg = (MatchedSubsegment) matchedSubsegs.get(0);
259
      break;
260
    case 1:
261
      srcSeg = (MatchedSubsegment) matchedSubsegs.get(matchedSubsegs.size() - 1);
262
      break;
263
    }
264
    return srcSeg;
265
  }
266

    
267
  /**
268
   * Records a vertex that was adjusted in some other Matched shell.
269
   *
270
   * @param coord the adjusted value of the vertex
271
   */
272
  private void addAdjustedVertex(Coordinate coord)
273
  {
274
    adjustedVertices.add(coord);
275
  }
276

    
277
  /**
278
   * Creates a list of inserted vertices for a Reference segment.
279
   * Vertices are inserted into the segment as long
280
   * as they are not equal to one of the endpoints
281
   * of the segment.
282
   * Note that no explicit check is made to ensure that short linesegments are not
283
   * created as a result of the insertion.
284
   * However, this should never happen, since an inserted vertex which might create a short
285
   * line segment should have been snapped to an endpoint already.
286
   */
287
  public List computeReferenceInsertedVertices()
288
  {
289
    List addedVert = new ArrayList();
290
    for (int i = 0; i < adjustedVertices.size(); i++) {
291
        Coordinate coord = (Coordinate) adjustedVertices.get(i);
292
        // only add vertices which are NOT an endpoint
293
        if (! ( lineseg.p0.equals(coord) ||
294
                lineseg.p1.equals(coord)  ) ) {
295
          Vertex v = new Vertex(coord, lineseg);
296
          addedVert.add(v);
297
        }
298
      // sort the added vertices in order along this segment
299
      Collections.sort(addedVert, new Vertex.PositionComparator());
300
    }
301
    return addedVert;
302
  }
303
}