| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
package org.locationtech.jts.noding.snapround; |
| 14 |
|
| 15 |
import org.locationtech.jts.geom.Envelope; |
| 16 |
import org.locationtech.jts.index.ItemVisitor; |
| 17 |
import org.locationtech.jts.index.SpatialIndex; |
| 18 |
import org.locationtech.jts.index.chain.MonotoneChain; |
| 19 |
import org.locationtech.jts.index.chain.MonotoneChainSelectAction; |
| 20 |
import org.locationtech.jts.index.strtree.STRtree; |
| 21 |
import org.locationtech.jts.noding.NodedSegmentString; |
| 22 |
import org.locationtech.jts.noding.SegmentString; |
| 23 |
|
| 24 |
/** |
| 25 |
* "Snaps" all {@link SegmentString}s in a {@link SpatialIndex} containing |
| 26 |
* {@link MonotoneChain}s to a given {@link HotPixel}. |
| 27 |
* |
| 28 |
* @version 1.7 |
| 29 |
*/ |
| 30 |
public class MCIndexPointSnapper |
| 31 |
{ |
| 32 |
|
| 33 |
|
| 34 |
private STRtree index; |
| 35 |
|
| 36 |
public MCIndexPointSnapper(SpatialIndex index) { |
| 37 |
this.index = (STRtree) index; |
| 38 |
} |
| 39 |
|
| 40 |
/** |
| 41 |
* Snaps (nodes) all interacting segments to this hot pixel. |
| 42 |
* The hot pixel may represent a vertex of an edge, |
| 43 |
* in which case this routine uses the optimization |
| 44 |
* of not noding the vertex itself |
| 45 |
* |
| 46 |
* @param hotPixel the hot pixel to snap to |
| 47 |
* @param parentEdge the edge containing the vertex, if applicable, or <code>null</code> |
| 48 |
* @param hotPixelVertexIndex the index of the hotPixel vertex, if applicable, or -1 |
| 49 |
* @return <code>true</code> if a node was added for this pixel |
| 50 |
*/ |
| 51 |
public boolean snap(HotPixel hotPixel, SegmentString parentEdge, int hotPixelVertexIndex) |
| 52 |
{ |
| 53 |
final Envelope pixelEnv = hotPixel.getSafeEnvelope(); |
| 54 |
final HotPixelSnapAction hotPixelSnapAction = new HotPixelSnapAction(hotPixel, parentEdge, hotPixelVertexIndex); |
| 55 |
|
| 56 |
index.query(pixelEnv, new ItemVisitor() { |
| 57 |
public void visitItem(Object item) { |
| 58 |
MonotoneChain testChain = (MonotoneChain) item; |
| 59 |
testChain.select(pixelEnv, hotPixelSnapAction); |
| 60 |
} |
| 61 |
} |
| 62 |
); |
| 63 |
return hotPixelSnapAction.isNodeAdded(); |
| 64 |
} |
| 65 |
|
| 66 |
public boolean snap(HotPixel hotPixel) |
| 67 |
{ |
| 68 |
return snap(hotPixel, null, -1); |
| 69 |
} |
| 70 |
|
| 71 |
public static class HotPixelSnapAction |
| 72 |
extends MonotoneChainSelectAction |
| 73 |
{ |
| 74 |
private HotPixel hotPixel; |
| 75 |
private SegmentString parentEdge; |
| 76 |
|
| 77 |
private int hotPixelVertexIndex; |
| 78 |
private boolean isNodeAdded = false; |
| 79 |
|
| 80 |
public HotPixelSnapAction(HotPixel hotPixel, SegmentString parentEdge, int hotPixelVertexIndex) |
| 81 |
{ |
| 82 |
this.hotPixel = hotPixel; |
| 83 |
this.parentEdge = parentEdge; |
| 84 |
this.hotPixelVertexIndex = hotPixelVertexIndex; |
| 85 |
} |
| 86 |
|
| 87 |
/** |
| 88 |
* Reports whether the HotPixel caused a node to be added in any target |
| 89 |
* segmentString (including its own). If so, the HotPixel must be added as a |
| 90 |
* node as well. |
| 91 |
* |
| 92 |
* @return true if a node was added in any target segmentString. |
| 93 |
*/ |
| 94 |
public boolean isNodeAdded() { |
| 95 |
return isNodeAdded; |
| 96 |
} |
| 97 |
|
| 98 |
/** |
| 99 |
* Check if a segment of the monotone chain intersects |
| 100 |
* the hot pixel vertex and introduce a snap node if so. |
| 101 |
* Optimized to avoid noding segments which |
| 102 |
* contain the vertex (which otherwise |
| 103 |
* would cause every vertex to be noded). |
| 104 |
*/ |
| 105 |
public void select(MonotoneChain mc, int startIndex) |
| 106 |
{ |
| 107 |
NodedSegmentString ss = (NodedSegmentString) mc.getContext(); |
| 108 |
/** |
| 109 |
* Check to avoid snapping a hotPixel vertex to the same vertex. |
| 110 |
* This method is called for segments which intersects the |
| 111 |
* hot pixel, |
| 112 |
* so need to check if either end of the segment is equal to the hot pixel |
| 113 |
* and if so, do not snap. |
| 114 |
* |
| 115 |
* Sep 22 2012 - MD - currently do need to snap to every vertex, |
| 116 |
* since otherwise the testCollapse1 test in SnapRoundingTest fails. |
| 117 |
*/ |
| 118 |
if (parentEdge == ss) { |
| 119 |
|
| 120 |
if (startIndex == hotPixelVertexIndex |
| 121 |
|| startIndex + 1 == hotPixelVertexIndex) |
| 122 |
return; |
| 123 |
} |
| 124 |
|
| 125 |
isNodeAdded |= hotPixel.addSnappedNode(ss, startIndex); |
| 126 |
} |
| 127 |
|
| 128 |
} |
| 129 |
|
| 130 |
} |
| 131 |
|