jsts-rails 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/jsts-rails/version.rb +1 -1
- data/vendor/assets/javascripts/javascript.util.js +33 -1
- data/vendor/assets/javascripts/jsts-original.js +164 -1573
- data/vendor/assets/javascripts/jsts.js +197 -0
- data/vendor/assets/javascripts/jsts/algorithm/Angle.js +387 -0
- data/vendor/assets/javascripts/jsts/algorithm/BoundaryNodeRule.js +67 -0
- data/vendor/assets/javascripts/jsts/algorithm/CGAlgorithms.js +596 -0
- data/vendor/assets/javascripts/jsts/algorithm/CentralEndpointIntersector.js +118 -0
- data/vendor/assets/javascripts/jsts/algorithm/CentroidArea.js +225 -0
- data/vendor/assets/javascripts/jsts/algorithm/CentroidLine.js +85 -0
- data/vendor/assets/javascripts/jsts/algorithm/CentroidPoint.js +77 -0
- data/vendor/assets/javascripts/jsts/algorithm/ConvexHull.js +409 -0
- data/vendor/assets/javascripts/jsts/algorithm/HCoordinate.js +234 -0
- data/vendor/assets/javascripts/jsts/algorithm/LineIntersector.js +502 -0
- data/vendor/assets/javascripts/jsts/algorithm/MCPointInRing.js +124 -0
- data/vendor/assets/javascripts/jsts/algorithm/PointLocator.js +247 -0
- data/vendor/assets/javascripts/jsts/algorithm/RayCrossingCounter.js +215 -0
- data/vendor/assets/javascripts/jsts/algorithm/RobustDeterminant.js +353 -0
- data/vendor/assets/javascripts/jsts/algorithm/RobustLineIntersector.js +477 -0
- data/vendor/assets/javascripts/jsts/algorithm/distance/DiscreteHausdorffDistance.js +228 -0
- data/vendor/assets/javascripts/jsts/algorithm/distance/DistanceToPoint.js +68 -0
- data/vendor/assets/javascripts/jsts/algorithm/distance/PointPairDistance.js +104 -0
- data/vendor/assets/javascripts/jsts/algorithm/locate/PointOnGeometryLocator.js +7 -0
- data/vendor/assets/javascripts/jsts/algorithm/locate/SimplePointInAreaLocator.js +102 -0
- data/vendor/assets/javascripts/jsts/geom/Coordinate.js +158 -0
- data/vendor/assets/javascripts/jsts/geom/CoordinateArrays.js +148 -0
- data/vendor/assets/javascripts/jsts/geom/CoordinateFilter.js +29 -0
- data/vendor/assets/javascripts/jsts/geom/CoordinateList.js +157 -0
- data/vendor/assets/javascripts/jsts/geom/CoordinateSequenceFilter.js +63 -0
- data/vendor/assets/javascripts/jsts/geom/Dimension.js +137 -0
- data/vendor/assets/javascripts/jsts/geom/Envelope.js +833 -0
- data/vendor/assets/javascripts/jsts/geom/Geometry.js +1535 -0
- data/vendor/assets/javascripts/jsts/geom/GeometryCollection.js +230 -0
- data/vendor/assets/javascripts/jsts/geom/GeometryComponentFilter.js +36 -0
- data/vendor/assets/javascripts/jsts/geom/GeometryFactory.js +263 -0
- data/vendor/assets/javascripts/jsts/geom/GeometryFilter.js +29 -0
- data/vendor/assets/javascripts/jsts/geom/IntersectionMatrix.js +650 -0
- data/vendor/assets/javascripts/jsts/geom/LineSegment.js +275 -0
- data/vendor/assets/javascripts/jsts/geom/LineString.js +299 -0
- data/vendor/assets/javascripts/jsts/geom/LinearRing.js +69 -0
- data/vendor/assets/javascripts/jsts/geom/Location.js +83 -0
- data/vendor/assets/javascripts/jsts/geom/MultiLineString.js +47 -0
- data/vendor/assets/javascripts/jsts/geom/MultiPoint.js +64 -0
- data/vendor/assets/javascripts/jsts/geom/MultiPolygon.js +64 -0
- data/vendor/assets/javascripts/jsts/geom/Point.js +197 -0
- data/vendor/assets/javascripts/jsts/geom/Polygon.js +263 -0
- data/vendor/assets/javascripts/jsts/geom/PrecisionModel.js +187 -0
- data/vendor/assets/javascripts/jsts/geom/Triangle.js +313 -0
- data/vendor/assets/javascripts/jsts/geom/util/GeometryCombiner.js +143 -0
- data/vendor/assets/javascripts/jsts/geom/util/GeometryExtracter.js +76 -0
- data/vendor/assets/javascripts/jsts/geom/util/GeometryTransformer.js +295 -0
- data/vendor/assets/javascripts/jsts/geom/util/LinearComponentExtracter.js +207 -0
- data/vendor/assets/javascripts/jsts/geom/util/PointExtracter.js +67 -0
- data/vendor/assets/javascripts/jsts/geom/util/PolygonExtracter.js +71 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Depth.js +145 -0
- data/vendor/assets/javascripts/jsts/geomgraph/DirectedEdge.js +270 -0
- data/vendor/assets/javascripts/jsts/geomgraph/DirectedEdgeStar.js +388 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Edge.js +291 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeEnd.js +188 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeEndStar.js +322 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeIntersection.js +122 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeIntersectionList.js +146 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeList.js +111 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeNodingValidator.js +76 -0
- data/vendor/assets/javascripts/jsts/geomgraph/EdgeRing.js +230 -0
- data/vendor/assets/javascripts/jsts/geomgraph/GeometryGraph.js +469 -0
- data/vendor/assets/javascripts/jsts/geomgraph/GraphComponent.js +181 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Label.js +316 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Node.js +105 -0
- data/vendor/assets/javascripts/jsts/geomgraph/NodeFactory.js +22 -0
- data/vendor/assets/javascripts/jsts/geomgraph/NodeMap.js +128 -0
- data/vendor/assets/javascripts/jsts/geomgraph/PlanarGraph.js +214 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Position.js +63 -0
- data/vendor/assets/javascripts/jsts/geomgraph/Quadrant.js +143 -0
- data/vendor/assets/javascripts/jsts/geomgraph/TopologyLocation.js +251 -0
- data/vendor/assets/javascripts/jsts/geomgraph/index/EdgeSetIntersector.js +47 -0
- data/vendor/assets/javascripts/jsts/geomgraph/index/SegmentIntersector.js +298 -0
- data/vendor/assets/javascripts/jsts/geomgraph/index/SimpleEdgeSetIntersector.js +107 -0
- data/vendor/assets/javascripts/jsts/geomgraph/index/SimpleMCSweepLineIntersector.js +29 -0
- data/vendor/assets/javascripts/jsts/index/ArrayListVisitor.js +37 -0
- data/vendor/assets/javascripts/jsts/index/DoubleBits.js +132 -0
- data/vendor/assets/javascripts/jsts/index/IntervalSize.js +55 -0
- data/vendor/assets/javascripts/jsts/index/ItemVisitor.js +23 -0
- data/vendor/assets/javascripts/jsts/index/SpatialIndex.js +67 -0
- data/vendor/assets/javascripts/jsts/index/bintree/Bintree.js +224 -0
- data/vendor/assets/javascripts/jsts/index/bintree/Interval.js +160 -0
- data/vendor/assets/javascripts/jsts/index/bintree/Key.js +110 -0
- data/vendor/assets/javascripts/jsts/index/bintree/Node.js +204 -0
- data/vendor/assets/javascripts/jsts/index/bintree/NodeBase.js +220 -0
- data/vendor/assets/javascripts/jsts/index/bintree/Root.js +113 -0
- data/vendor/assets/javascripts/jsts/index/chain/MonotoneChain.js +244 -0
- data/vendor/assets/javascripts/jsts/index/chain/MonotoneChainBuilder.js +106 -0
- data/vendor/assets/javascripts/jsts/index/chain/MonotoneChainOverlapAction.js +56 -0
- data/vendor/assets/javascripts/jsts/index/chain/MonotoneChainSelectAction.js +44 -0
- data/vendor/assets/javascripts/jsts/index/kdtree/KdNode.js +171 -0
- data/vendor/assets/javascripts/jsts/index/kdtree/KdTree.js +218 -0
- data/vendor/assets/javascripts/jsts/index/quadtree/Key.js +134 -0
- data/vendor/assets/javascripts/jsts/index/quadtree/Node.js +220 -0
- data/vendor/assets/javascripts/jsts/index/quadtree/NodeBase.js +330 -0
- data/vendor/assets/javascripts/jsts/index/quadtree/Quadtree.js +228 -0
- data/vendor/assets/javascripts/jsts/index/quadtree/Root.js +105 -0
- data/vendor/assets/javascripts/jsts/index/strtree/AbstractNode.js +107 -0
- data/vendor/assets/javascripts/jsts/index/strtree/AbstractSTRtree.js +594 -0
- data/vendor/assets/javascripts/jsts/index/strtree/Boundable.js +37 -0
- data/vendor/assets/javascripts/jsts/index/strtree/BoundablePair.js +0 -0
- data/vendor/assets/javascripts/jsts/index/strtree/Interval.js +94 -0
- data/vendor/assets/javascripts/jsts/index/strtree/ItemBoundable.js +60 -0
- data/vendor/assets/javascripts/jsts/index/strtree/SIRtree.js +122 -0
- data/vendor/assets/javascripts/jsts/index/strtree/STRtree.js +450 -0
- data/vendor/assets/javascripts/jsts/io/GeoJSONParser.js +471 -0
- data/vendor/assets/javascripts/jsts/io/GeoJSONReader.js +58 -0
- data/vendor/assets/javascripts/jsts/io/GeoJSONWriter.js +38 -0
- data/vendor/assets/javascripts/jsts/io/OpenLayersParser.js +245 -0
- data/vendor/assets/javascripts/jsts/io/WKTParser.js +421 -0
- data/vendor/assets/javascripts/jsts/io/WKTReader.js +68 -0
- data/vendor/assets/javascripts/jsts/io/WKTWriter.js +61 -0
- data/vendor/assets/javascripts/jsts/noding/BasicSegmentString.js +87 -0
- data/vendor/assets/javascripts/jsts/noding/FastNodingValidator.js +127 -0
- data/vendor/assets/javascripts/jsts/noding/InteriorIntersectionFinder.js +171 -0
- data/vendor/assets/javascripts/jsts/noding/IntersectionAdder.js +198 -0
- data/vendor/assets/javascripts/jsts/noding/IntersectionFinderAdder.js +79 -0
- data/vendor/assets/javascripts/jsts/noding/MCIndexNoder.js +147 -0
- data/vendor/assets/javascripts/jsts/noding/NodableSegmentString.js +35 -0
- data/vendor/assets/javascripts/jsts/noding/NodedSegmentString.js +235 -0
- data/vendor/assets/javascripts/jsts/noding/Noder.js +41 -0
- data/vendor/assets/javascripts/jsts/noding/NodingValidator.js +5 -0
- data/vendor/assets/javascripts/jsts/noding/Octant.js +84 -0
- data/vendor/assets/javascripts/jsts/noding/OrientedCoordinateArray.js +94 -0
- data/vendor/assets/javascripts/jsts/noding/ScaledNoder.js +105 -0
- data/vendor/assets/javascripts/jsts/noding/SegmentIntersector.js +45 -0
- data/vendor/assets/javascripts/jsts/noding/SegmentNode.js +70 -0
- data/vendor/assets/javascripts/jsts/noding/SegmentNodeList.js +262 -0
- data/vendor/assets/javascripts/jsts/noding/SegmentPointComparator.js +78 -0
- data/vendor/assets/javascripts/jsts/noding/SegmentString.js +61 -0
- data/vendor/assets/javascripts/jsts/noding/SinglePassNoder.js +51 -0
- data/vendor/assets/javascripts/jsts/noding/snapround/HotPixel.js +271 -0
- data/vendor/assets/javascripts/jsts/noding/snapround/MCIndexPointSnapper.js +96 -0
- data/vendor/assets/javascripts/jsts/noding/snapround/MCIndexSnapRounder.js +147 -0
- data/vendor/assets/javascripts/jsts/operation/BoundaryOp.js +166 -0
- data/vendor/assets/javascripts/jsts/operation/GeometryGraphOperation.js +90 -0
- data/vendor/assets/javascripts/jsts/operation/IsSimpleOp.js +293 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/BufferBuilder.js +317 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/BufferInputLineSimplifier.js +294 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/BufferOp.js +340 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/BufferParameters.js +328 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/BufferSubgraph.js +296 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/OffsetCurveBuilder.js +369 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/OffsetCurveSetBuilder.js +301 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/OffsetSegmentGenerator.js +777 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/OffsetSegmentString.js +109 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/RightmostEdgeFinder.js +164 -0
- data/vendor/assets/javascripts/jsts/operation/buffer/SubgraphDepthLocater.js +220 -0
- data/vendor/assets/javascripts/jsts/operation/distance/ConnectedElementLocationFilter.js +67 -0
- data/vendor/assets/javascripts/jsts/operation/distance/DistanceOp.js +506 -0
- data/vendor/assets/javascripts/jsts/operation/distance/GeometryLocation.js +102 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/LineBuilder.js +194 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/MaximalEdgeRing.js +72 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/MinimalEdgeRing.js +33 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/OverlayNodeFactory.js +26 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/OverlayOp.js +584 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/PointBuilder.js +103 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/PolygonBuilder.js +282 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/snap/GeometrySnapper.js +228 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/snap/LineStringSnapper.js +228 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/snap/SnapIfNeededOverlayOp.js +85 -0
- data/vendor/assets/javascripts/jsts/operation/overlay/snap/SnapOverlayOp.js +134 -0
- data/vendor/assets/javascripts/jsts/operation/polygonize/EdgeRing.js +259 -0
- data/vendor/assets/javascripts/jsts/operation/polygonize/PolygonizeDirectedEdge.js +94 -0
- data/vendor/assets/javascripts/jsts/operation/polygonize/PolygonizeEdge.js +31 -0
- data/vendor/assets/javascripts/jsts/operation/polygonize/PolygonizeGraph.js +507 -0
- data/vendor/assets/javascripts/jsts/operation/polygonize/Polygonizer.js +259 -0
- data/vendor/assets/javascripts/jsts/operation/relate/EdgeEndBuilder.js +140 -0
- data/vendor/assets/javascripts/jsts/operation/relate/EdgeEndBundle.js +183 -0
- data/vendor/assets/javascripts/jsts/operation/relate/EdgeEndBundleStar.js +48 -0
- data/vendor/assets/javascripts/jsts/operation/relate/RelateComputer.js +444 -0
- data/vendor/assets/javascripts/jsts/operation/relate/RelateNode.js +46 -0
- data/vendor/assets/javascripts/jsts/operation/relate/RelateNodeFactory.js +25 -0
- data/vendor/assets/javascripts/jsts/operation/relate/RelateNodeGraph.js +118 -0
- data/vendor/assets/javascripts/jsts/operation/relate/RelateOp.js +75 -0
- data/vendor/assets/javascripts/jsts/operation/union/CascadedPolygonUnion.js +319 -0
- data/vendor/assets/javascripts/jsts/operation/union/PointGeometryUnion.js +118 -0
- data/vendor/assets/javascripts/jsts/operation/union/UnaryUnionOp.js +244 -0
- data/vendor/assets/javascripts/jsts/operation/union/UnionInteracting.js +156 -0
- data/vendor/assets/javascripts/jsts/operation/valid/ConnectedInteriorTester.js +259 -0
- data/vendor/assets/javascripts/jsts/operation/valid/ConsistentAreaTester.js +127 -0
- data/vendor/assets/javascripts/jsts/operation/valid/IndexedNestedRingTester.js +89 -0
- data/vendor/assets/javascripts/jsts/operation/valid/IsValidOp.js +619 -0
- data/vendor/assets/javascripts/jsts/operation/valid/TopologyValidationError.js +199 -0
- data/vendor/assets/javascripts/jsts/planargraph/DirectedEdge.js +232 -0
- data/vendor/assets/javascripts/jsts/planargraph/DirectedEdgeStar.js +168 -0
- data/vendor/assets/javascripts/jsts/planargraph/Edge.js +124 -0
- data/vendor/assets/javascripts/jsts/planargraph/GraphComponent.js +182 -0
- data/vendor/assets/javascripts/jsts/planargraph/Node.js +127 -0
- data/vendor/assets/javascripts/jsts/planargraph/NodeMap.js +76 -0
- data/vendor/assets/javascripts/jsts/planargraph/PlanarGraph.js +246 -0
- data/vendor/assets/javascripts/jsts/simplify/LineSegmentIndex.js +101 -0
- data/vendor/assets/javascripts/jsts/triangulate/DelaunayTriangulationBuilder.js +224 -0
- data/vendor/assets/javascripts/jsts/triangulate/IncrementalDelaunayTriangulator.js +111 -0
- data/vendor/assets/javascripts/jsts/triangulate/VoronoiDiagramBuilder.js +172 -0
- data/vendor/assets/javascripts/jsts/triangulate/quadedge/LastFoundQuadEdgeLocator.js +52 -0
- data/vendor/assets/javascripts/jsts/triangulate/quadedge/QuadEdge.js +437 -0
- data/vendor/assets/javascripts/jsts/triangulate/quadedge/QuadEdgeSubdivision.js +1064 -0
- data/vendor/assets/javascripts/jsts/triangulate/quadedge/TrianglePredicate.js +350 -0
- data/vendor/assets/javascripts/jsts/triangulate/quadedge/Vertex.js +496 -0
- data/vendor/assets/javascripts/jsts/util/Assert.js +80 -0
- data/vendor/assets/javascripts/jsts/util/AssertionFailedException.js +23 -0
- data/vendor/assets/javascripts/jsts/util/UniqueCoordinateArrayFilter.js +52 -0
- metadata +204 -1
@@ -0,0 +1,777 @@
|
|
1
|
+
/* Copyright (c) 2011 by The Authors.
|
2
|
+
* Published under the LGPL 2.1 license.
|
3
|
+
* See /license-notice.txt for the full text of the license notice.
|
4
|
+
* See /license.txt for the full text of the license.
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Generates segments which form an offset curve. Supports all end cap and join
|
10
|
+
* options provided for buffering. Implements various heuristics to produce
|
11
|
+
* smoother, simpler curves which are still within a reasonable tolerance of the
|
12
|
+
* true curve.
|
13
|
+
* @constructor
|
14
|
+
*/
|
15
|
+
jsts.operation.buffer.OffsetSegmentGenerator = function(precisionModel,
|
16
|
+
bufParams, distance) {
|
17
|
+
this.seg0 = new jsts.geom.LineSegment();
|
18
|
+
this.seg1 = new jsts.geom.LineSegment();
|
19
|
+
this.offset0 = new jsts.geom.LineSegment();
|
20
|
+
this.offset1 = new jsts.geom.LineSegment();
|
21
|
+
|
22
|
+
this.precisionModel = precisionModel;
|
23
|
+
this.bufParams = bufParams;
|
24
|
+
|
25
|
+
// compute intersections in full precision, to provide accuracy
|
26
|
+
// the points are rounded as they are inserted into the curve line
|
27
|
+
this.li = new jsts.algorithm.RobustLineIntersector();
|
28
|
+
this.filletAngleQuantum = Math.PI / 2.0 / bufParams.getQuadrantSegments();
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Non-round joins cause issues with short closing segments, so don't use
|
32
|
+
* them. In any case, non-round joins only really make sense for relatively
|
33
|
+
* small buffer distances.
|
34
|
+
*/
|
35
|
+
if (this.bufParams.getQuadrantSegments() >= 8 &&
|
36
|
+
this.bufParams.getJoinStyle() === jsts.operation.buffer.BufferParameters.JOIN_ROUND) {
|
37
|
+
this.closingSegLengthFactor = jsts.operation.buffer.OffsetSegmentGenerator.MAX_CLOSING_SEG_LEN_FACTOR;
|
38
|
+
}
|
39
|
+
this.init(distance);
|
40
|
+
};
|
41
|
+
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Factor which controls how close offset segments can be to skip adding a
|
45
|
+
* filler or mitre.
|
46
|
+
*
|
47
|
+
* @private
|
48
|
+
*/
|
49
|
+
jsts.operation.buffer.OffsetSegmentGenerator.OFFSET_SEGMENT_SEPARATION_FACTOR = 1.0E-3;
|
50
|
+
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Factor which controls how close curve vertices on inside turns can be to be
|
54
|
+
* snapped
|
55
|
+
*
|
56
|
+
* @private
|
57
|
+
*/
|
58
|
+
jsts.operation.buffer.OffsetSegmentGenerator.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-3;
|
59
|
+
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Factor which controls how close curve vertices can be to be snapped
|
63
|
+
*
|
64
|
+
* @private
|
65
|
+
*/
|
66
|
+
jsts.operation.buffer.OffsetSegmentGenerator.CURVE_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-6;
|
67
|
+
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Factor which determines how short closing segs can be for round buffers *
|
71
|
+
*
|
72
|
+
* @private
|
73
|
+
*/
|
74
|
+
jsts.operation.buffer.OffsetSegmentGenerator.MAX_CLOSING_SEG_LEN_FACTOR = 80;
|
75
|
+
|
76
|
+
|
77
|
+
/**
|
78
|
+
* the max error of approximation (distance) between a quad segment and the true
|
79
|
+
* fillet curve
|
80
|
+
*
|
81
|
+
* @private
|
82
|
+
*/
|
83
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.maxCurveSegmentError = 0.0;
|
84
|
+
|
85
|
+
|
86
|
+
/**
|
87
|
+
* The angle quantum with which to approximate a fillet curve (based on the
|
88
|
+
* input # of quadrant segments)
|
89
|
+
*
|
90
|
+
* @private
|
91
|
+
*/
|
92
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.filletAngleQuantum = null;
|
93
|
+
|
94
|
+
|
95
|
+
/**
|
96
|
+
* The Closing Segment Length Factor controls how long "closing segments" are.
|
97
|
+
* Closing segments are added at the middle of inside corners to ensure a
|
98
|
+
* smoother boundary for the buffer offset curve. In some cases (particularly
|
99
|
+
* for round joins with default-or-better quantization) the closing segments can
|
100
|
+
* be made quite short. This substantially improves performance (due to fewer
|
101
|
+
* intersections being created).
|
102
|
+
*
|
103
|
+
* A closingSegFactor of 0 results in lines to the corner vertex A
|
104
|
+
* closingSegFactor of 1 results in lines halfway to the corner vertex A
|
105
|
+
* closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex
|
106
|
+
* (this option is reasonable for the very common default situation of round
|
107
|
+
* joins and quadrantSegs >= 8)
|
108
|
+
*
|
109
|
+
* @private
|
110
|
+
*/
|
111
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.closingSegLengthFactor = 1;
|
112
|
+
|
113
|
+
|
114
|
+
/**
|
115
|
+
* @type {OffsetSegmentString}
|
116
|
+
* @private
|
117
|
+
*/
|
118
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.segList = null;
|
119
|
+
|
120
|
+
|
121
|
+
/**
|
122
|
+
* @private
|
123
|
+
*/
|
124
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.distance = 0.0;
|
125
|
+
|
126
|
+
|
127
|
+
/**
|
128
|
+
* @private
|
129
|
+
*/
|
130
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.precisionModel = null;
|
131
|
+
|
132
|
+
|
133
|
+
/**
|
134
|
+
* @private
|
135
|
+
*/
|
136
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.bufParams = null;
|
137
|
+
|
138
|
+
|
139
|
+
/**
|
140
|
+
* @private
|
141
|
+
*/
|
142
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.li = null;
|
143
|
+
|
144
|
+
|
145
|
+
/**
|
146
|
+
* @type {Coordinate}
|
147
|
+
* @private
|
148
|
+
*/
|
149
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.s0 = null;
|
150
|
+
|
151
|
+
|
152
|
+
/**
|
153
|
+
* @type {Coordinate}
|
154
|
+
* @private
|
155
|
+
*/
|
156
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.s1 = null;
|
157
|
+
|
158
|
+
|
159
|
+
/**
|
160
|
+
* @type {Coordinate}
|
161
|
+
* @private
|
162
|
+
*/
|
163
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.s2 = null;
|
164
|
+
|
165
|
+
|
166
|
+
/**
|
167
|
+
* @type {LineSegment}
|
168
|
+
* @private
|
169
|
+
*/
|
170
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.seg0 = null;
|
171
|
+
|
172
|
+
|
173
|
+
/**
|
174
|
+
* @type {LineSegment}
|
175
|
+
* @private
|
176
|
+
*/
|
177
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.seg1 = null;
|
178
|
+
|
179
|
+
|
180
|
+
/**
|
181
|
+
* @type {LineSegment}
|
182
|
+
* @private
|
183
|
+
*/
|
184
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.offset0 = null;
|
185
|
+
|
186
|
+
|
187
|
+
/**
|
188
|
+
* @type {LineSegment}
|
189
|
+
* @private
|
190
|
+
*/
|
191
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.offset1 = null;
|
192
|
+
|
193
|
+
|
194
|
+
/**
|
195
|
+
* @type {number}
|
196
|
+
* @private
|
197
|
+
*/
|
198
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.side = 0;
|
199
|
+
|
200
|
+
|
201
|
+
/**
|
202
|
+
* @type {boolean}
|
203
|
+
* @private
|
204
|
+
*/
|
205
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.hasNarrowConcaveAngle = false;
|
206
|
+
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Tests whether the input has a narrow concave angle (relative to the offset
|
210
|
+
* distance). In this case the generated offset curve will contain
|
211
|
+
* self-intersections and heuristic closing segments. This is expected behaviour
|
212
|
+
* in the case of buffer curves. For pure offset curves, the output needs to be
|
213
|
+
* further treated before it can be used.
|
214
|
+
*
|
215
|
+
* @return true if the input has a narrow concave angle.
|
216
|
+
*/
|
217
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.hasNarrowConcaveAngle = function() {
|
218
|
+
return this.hasNarrowConcaveAngle;
|
219
|
+
};
|
220
|
+
|
221
|
+
|
222
|
+
/**
|
223
|
+
* @private
|
224
|
+
*/
|
225
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.init = function(distance) {
|
226
|
+
this.distance = distance;
|
227
|
+
this.maxCurveSegmentError = this.distance *
|
228
|
+
(1 - Math.cos(this.filletAngleQuantum / 2.0));
|
229
|
+
this.segList = new jsts.operation.buffer.OffsetSegmentString();
|
230
|
+
this.segList.setPrecisionModel(this.precisionModel);
|
231
|
+
/**
|
232
|
+
* Choose the min vertex separation as a small fraction of the offset
|
233
|
+
* distance.
|
234
|
+
*/
|
235
|
+
this.segList
|
236
|
+
.setMinimumVertexDistance(this.distance *
|
237
|
+
jsts.operation.buffer.OffsetSegmentGenerator.CURVE_VERTEX_SNAP_DISTANCE_FACTOR);
|
238
|
+
};
|
239
|
+
|
240
|
+
|
241
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.initSideSegments = function(
|
242
|
+
s1, s2, side) {
|
243
|
+
this.s1 = s1;
|
244
|
+
this.s2 = s2;
|
245
|
+
this.side = side;
|
246
|
+
this.seg1.setCoordinates(this.s1, this.s2);
|
247
|
+
this.computeOffsetSegment(this.seg1, this.side, this.distance, this.offset1);
|
248
|
+
};
|
249
|
+
|
250
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.getCoordinates = function() {
|
251
|
+
return this.segList.getCoordinates();
|
252
|
+
};
|
253
|
+
|
254
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.closeRing = function() {
|
255
|
+
this.segList.closeRing();
|
256
|
+
};
|
257
|
+
|
258
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addSegments = function(
|
259
|
+
pt, isForward) {
|
260
|
+
this.segList.addPts(pt, isForward);
|
261
|
+
};
|
262
|
+
|
263
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFirstSegment = function() {
|
264
|
+
this.segList.addPt(this.offset1.p0);
|
265
|
+
};
|
266
|
+
|
267
|
+
|
268
|
+
/**
|
269
|
+
* Add last offset point
|
270
|
+
*/
|
271
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLastSegment = function() {
|
272
|
+
this.segList.addPt(this.offset1.p1);
|
273
|
+
};
|
274
|
+
|
275
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addNextSegment = function(
|
276
|
+
p, addStartPoint) {
|
277
|
+
// s0-s1-s2 are the coordinates of the previous segment and the current one
|
278
|
+
this.s0 = this.s1;
|
279
|
+
this.s1 = this.s2;
|
280
|
+
this.s2 = p;
|
281
|
+
this.seg0.setCoordinates(this.s0, this.s1);
|
282
|
+
this.computeOffsetSegment(this.seg0, this.side, this.distance, this.offset0);
|
283
|
+
this.seg1.setCoordinates(this.s1, this.s2);
|
284
|
+
this.computeOffsetSegment(this.seg1, this.side, this.distance, this.offset1);
|
285
|
+
|
286
|
+
// do nothing if points are equal
|
287
|
+
if (this.s1.equals(this.s2))
|
288
|
+
return;
|
289
|
+
|
290
|
+
var orientation = jsts.algorithm.CGAlgorithms.computeOrientation(this.s0,
|
291
|
+
this.s1, this.s2);
|
292
|
+
var outsideTurn = (orientation === jsts.algorithm.CGAlgorithms.CLOCKWISE && this.side === jsts.geomgraph.Position.LEFT) ||
|
293
|
+
(orientation === jsts.algorithm.CGAlgorithms.COUNTERCLOCKWISE && this.side === jsts.geomgraph.Position.RIGHT);
|
294
|
+
|
295
|
+
if (orientation == 0) { // lines are collinear
|
296
|
+
this.addCollinear(addStartPoint);
|
297
|
+
} else if (outsideTurn) {
|
298
|
+
this.addOutsideTurn(orientation, addStartPoint);
|
299
|
+
} else { // inside turn
|
300
|
+
this.addInsideTurn(orientation, addStartPoint);
|
301
|
+
}
|
302
|
+
};
|
303
|
+
|
304
|
+
|
305
|
+
/**
|
306
|
+
* @private
|
307
|
+
*/
|
308
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addCollinear = function(
|
309
|
+
addStartPoint) {
|
310
|
+
/**
|
311
|
+
* This test could probably be done more efficiently, but the situation of
|
312
|
+
* exact collinearity should be fairly rare.
|
313
|
+
*/
|
314
|
+
this.li.computeIntersection(this.s0, this.s1, this.s1, this.s2);
|
315
|
+
var numInt = this.li.getIntersectionNum();
|
316
|
+
/**
|
317
|
+
* if numInt is < 2, the lines are parallel and in the same direction. In this
|
318
|
+
* case the point can be ignored, since the offset lines will also be
|
319
|
+
* parallel.
|
320
|
+
*/
|
321
|
+
if (numInt >= 2) {
|
322
|
+
/**
|
323
|
+
* segments are collinear but reversing. Add an "end-cap" fillet all the way
|
324
|
+
* around to other direction This case should ONLY happen for LineStrings,
|
325
|
+
* so the orientation is always CW. (Polygons can never have two consecutive
|
326
|
+
* segments which are parallel but reversed, because that would be a self
|
327
|
+
* intersection.
|
328
|
+
*
|
329
|
+
*/
|
330
|
+
if (this.bufParams.getJoinStyle() === jsts.operation.buffer.BufferParameters.JOIN_BEVEL ||
|
331
|
+
this.bufParams.getJoinStyle() === jsts.operation.buffer.BufferParameters.JOIN_MITRE) {
|
332
|
+
if (addStartPoint)
|
333
|
+
this.segList.addPt(this.offset0.p1);
|
334
|
+
this.segList.addPt(this.offset1.p0);
|
335
|
+
} else {
|
336
|
+
this.addFillet(this.s1, this.offset0.p1, this.offset1.p0,
|
337
|
+
jsts.algorithm.CGAlgorithms.CLOCKWISE, this.distance);
|
338
|
+
}
|
339
|
+
}
|
340
|
+
};
|
341
|
+
|
342
|
+
|
343
|
+
/**
|
344
|
+
* Adds the offset points for an outside (convex) turn
|
345
|
+
*
|
346
|
+
* @param orientation
|
347
|
+
* @param addStartPoint
|
348
|
+
* @private
|
349
|
+
*/
|
350
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addOutsideTurn = function(
|
351
|
+
orientation, addStartPoint) {
|
352
|
+
/**
|
353
|
+
* Heuristic: If offset endpoints are very close together, just use one of
|
354
|
+
* them as the corner vertex. This avoids problems with computing mitre
|
355
|
+
* corners in the case where the two segments are almost parallel (which is
|
356
|
+
* hard to compute a robust intersection for).
|
357
|
+
*/
|
358
|
+
if (this.offset0.p1.distance(this.offset1.p0) < this.distance *
|
359
|
+
jsts.operation.buffer.OffsetSegmentGenerator.OFFSET_SEGMENT_SEPARATION_FACTOR) {
|
360
|
+
this.segList.addPt(this.offset0.p1);
|
361
|
+
return;
|
362
|
+
}
|
363
|
+
|
364
|
+
if (this.bufParams.getJoinStyle() === jsts.operation.buffer.BufferParameters.JOIN_MITRE) {
|
365
|
+
this.addMitreJoin(this.s1, this.offset0, this.offset1, this.distance);
|
366
|
+
} else if (this.bufParams.getJoinStyle() === jsts.operation.buffer.BufferParameters.JOIN_BEVEL) {
|
367
|
+
this.addBevelJoin(this.offset0, this.offset1);
|
368
|
+
} else {
|
369
|
+
// add a circular fillet connecting the endpoints of the offset segments
|
370
|
+
if (addStartPoint)
|
371
|
+
this.segList.addPt(this.offset0.p1);
|
372
|
+
// TESTING - comment out to produce beveled joins
|
373
|
+
this.addFillet(this.s1, this.offset0.p1, this.offset1.p0, orientation,
|
374
|
+
this.distance);
|
375
|
+
this.segList.addPt(this.offset1.p0);
|
376
|
+
}
|
377
|
+
};
|
378
|
+
|
379
|
+
|
380
|
+
/**
|
381
|
+
* Adds the offset points for an inside (concave) turn.
|
382
|
+
*
|
383
|
+
* @param orientation
|
384
|
+
* @param addStartPoint
|
385
|
+
* @private
|
386
|
+
*/
|
387
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addInsideTurn = function(
|
388
|
+
orientation, addStartPoint) {
|
389
|
+
/**
|
390
|
+
* add intersection point of offset segments (if any)
|
391
|
+
*/
|
392
|
+
this.li.computeIntersection(this.offset0.p0, this.offset0.p1, this.offset1.p0, this.offset1.p1);
|
393
|
+
if (this.li.hasIntersection()) {
|
394
|
+
this.segList.addPt(this.li.getIntersection(0));
|
395
|
+
} else {
|
396
|
+
/**
|
397
|
+
* If no intersection is detected, it means the angle is so small and/or the
|
398
|
+
* offset so large that the offsets segments don't intersect. In this case
|
399
|
+
* we must add a "closing segment" to make sure the buffer curve is
|
400
|
+
* continuous, fairly smooth (e.g. no sharp reversals in direction) and
|
401
|
+
* tracks the buffer correctly around the corner. The curve connects the
|
402
|
+
* endpoints of the segment offsets to points which lie toward the centre
|
403
|
+
* point of the corner. The joining curve will not appear in the final
|
404
|
+
* buffer outline, since it is completely internal to the buffer polygon.
|
405
|
+
*
|
406
|
+
* In complex buffer cases the closing segment may cut across many other
|
407
|
+
* segments in the generated offset curve. In order to improve the
|
408
|
+
* performance of the noding, the closing segment should be kept as short as
|
409
|
+
* possible. (But not too short, since that would defeat its purpose). This
|
410
|
+
* is the purpose of the closingSegFactor heuristic value.
|
411
|
+
*/
|
412
|
+
|
413
|
+
/**
|
414
|
+
* The intersection test above is vulnerable to robustness errors; i.e. it
|
415
|
+
* may be that the offsets should intersect very close to their endpoints,
|
416
|
+
* but aren't reported as such due to rounding. To handle this situation
|
417
|
+
* appropriately, we use the following test: If the offset points are very
|
418
|
+
* close, don't add closing segments but simply use one of the offset points
|
419
|
+
*/
|
420
|
+
this.hasNarrowConcaveAngle = true;
|
421
|
+
// System.out.println("NARROW ANGLE - distance = " + distance);
|
422
|
+
if (this.offset0.p1.distance(this.offset1.p0) < this.distance *
|
423
|
+
jsts.operation.buffer.OffsetSegmentGenerator.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) {
|
424
|
+
this.segList.addPt(this.offset0.p1);
|
425
|
+
} else {
|
426
|
+
// add endpoint of this segment offset
|
427
|
+
this.segList.addPt(this.offset0.p1);
|
428
|
+
|
429
|
+
/**
|
430
|
+
* Add "closing segment" of required length.
|
431
|
+
*/
|
432
|
+
if (this.closingSegLengthFactor > 0) {
|
433
|
+
var mid0 = new jsts.geom.Coordinate((this.closingSegLengthFactor *
|
434
|
+
this.offset0.p1.x + this.s1.x) /
|
435
|
+
(this.closingSegLengthFactor + 1), (this.closingSegLengthFactor *
|
436
|
+
this.offset0.p1.y + this.s1.y) /
|
437
|
+
(this.closingSegLengthFactor + 1));
|
438
|
+
this.segList.addPt(mid0);
|
439
|
+
var mid1 = new jsts.geom.Coordinate((this.closingSegLengthFactor *
|
440
|
+
this.offset1.p0.x + this.s1.x) /
|
441
|
+
(this.closingSegLengthFactor + 1), (this.closingSegLengthFactor *
|
442
|
+
this.offset1.p0.y + this.s1.y) /
|
443
|
+
(this.closingSegLengthFactor + 1));
|
444
|
+
this.segList.addPt(mid1);
|
445
|
+
} else {
|
446
|
+
/**
|
447
|
+
* This branch is not expected to be used except for testing purposes.
|
448
|
+
* It is equivalent to the JTS 1.9 logic for closing segments (which
|
449
|
+
* results in very poor performance for large buffer distances)
|
450
|
+
*/
|
451
|
+
this.segList.addPt(this.s1);
|
452
|
+
}
|
453
|
+
|
454
|
+
// */
|
455
|
+
// add start point of next segment offset
|
456
|
+
this.segList.addPt(this.offset1.p0);
|
457
|
+
}
|
458
|
+
}
|
459
|
+
};
|
460
|
+
|
461
|
+
|
462
|
+
/**
|
463
|
+
* Compute an offset segment for an input segment on a given side and at a given
|
464
|
+
* distance. The offset points are computed in full double precision, for
|
465
|
+
* accuracy.
|
466
|
+
*
|
467
|
+
* @param seg
|
468
|
+
* the segment to offset.
|
469
|
+
* @param side
|
470
|
+
* the side of the segment ( {@link Position} ) the offset lies on.
|
471
|
+
* @param distance
|
472
|
+
* the offset distance.
|
473
|
+
* @param offset
|
474
|
+
* the points computed for the offset segment.
|
475
|
+
* @private
|
476
|
+
*/
|
477
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.computeOffsetSegment = function(
|
478
|
+
seg, side, distance, offset) {
|
479
|
+
var sideSign = side === jsts.geomgraph.Position.LEFT ? 1 : -1;
|
480
|
+
var dx = seg.p1.x - seg.p0.x;
|
481
|
+
var dy = seg.p1.y - seg.p0.y;
|
482
|
+
var len = Math.sqrt(dx * dx + dy * dy);
|
483
|
+
// u is the vector that is the length of the offset, in the direction of the
|
484
|
+
// segment
|
485
|
+
var ux = sideSign * distance * dx / len;
|
486
|
+
var uy = sideSign * distance * dy / len;
|
487
|
+
offset.p0.x = seg.p0.x - uy;
|
488
|
+
offset.p0.y = seg.p0.y + ux;
|
489
|
+
offset.p1.x = seg.p1.x - uy;
|
490
|
+
offset.p1.y = seg.p1.y + ux;
|
491
|
+
};
|
492
|
+
|
493
|
+
|
494
|
+
/**
|
495
|
+
* Add an end cap around point p1, terminating a line segment coming from p0
|
496
|
+
*/
|
497
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLineEndCap = function(
|
498
|
+
p0, p1) {
|
499
|
+
var seg = new jsts.geom.LineSegment(p0, p1);
|
500
|
+
|
501
|
+
var offsetL = new jsts.geom.LineSegment();
|
502
|
+
this.computeOffsetSegment(seg, jsts.geomgraph.Position.LEFT, this.distance,
|
503
|
+
offsetL);
|
504
|
+
var offsetR = new jsts.geom.LineSegment();
|
505
|
+
this.computeOffsetSegment(seg, jsts.geomgraph.Position.RIGHT, this.distance,
|
506
|
+
offsetR);
|
507
|
+
|
508
|
+
var dx = p1.x - p0.x;
|
509
|
+
var dy = p1.y - p0.y;
|
510
|
+
var angle = Math.atan2(dy, dx);
|
511
|
+
|
512
|
+
switch (this.bufParams.getEndCapStyle()) {
|
513
|
+
case jsts.operation.buffer.BufferParameters.CAP_ROUND:
|
514
|
+
// add offset seg points with a fillet between them
|
515
|
+
this.segList.addPt(offsetL.p1);
|
516
|
+
this.addFillet(p1, angle + Math.PI / 2, angle - Math.PI / 2,
|
517
|
+
jsts.algorithm.CGAlgorithms.CLOCKWISE, this.distance);
|
518
|
+
this.segList.addPt(offsetR.p1);
|
519
|
+
break;
|
520
|
+
case jsts.operation.buffer.BufferParameters.CAP_FLAT:
|
521
|
+
// only offset segment points are added
|
522
|
+
this.segList.addPt(offsetL.p1);
|
523
|
+
this.segList.addPt(offsetR.p1);
|
524
|
+
break;
|
525
|
+
case jsts.operation.buffer.BufferParameters.CAP_SQUARE:
|
526
|
+
// add a square defined by extensions of the offset segment endpoints
|
527
|
+
var squareCapSideOffset = new jsts.geom.Coordinate();
|
528
|
+
squareCapSideOffset.x = Math.abs(this.distance) * Math.cos(angle);
|
529
|
+
squareCapSideOffset.y = Math.abs(this.distance) * Math.sin(angle);
|
530
|
+
|
531
|
+
var squareCapLOffset = new jsts.geom.Coordinate(offsetL.p1.x +
|
532
|
+
squareCapSideOffset.x, offsetL.p1.y + squareCapSideOffset.y);
|
533
|
+
var squareCapROffset = new jsts.geom.Coordinate(offsetR.p1.x +
|
534
|
+
squareCapSideOffset.x, offsetR.p1.y + squareCapSideOffset.y);
|
535
|
+
this.segList.addPt(squareCapLOffset);
|
536
|
+
this.segList.addPt(squareCapROffset);
|
537
|
+
break;
|
538
|
+
|
539
|
+
}
|
540
|
+
};
|
541
|
+
|
542
|
+
|
543
|
+
/**
|
544
|
+
* Adds a mitre join connecting the two reflex offset segments. The mitre will
|
545
|
+
* be beveled if it exceeds the mitre ratio limit.
|
546
|
+
*
|
547
|
+
* @param offset0
|
548
|
+
* the first offset segment.
|
549
|
+
* @param offset1
|
550
|
+
* the second offset segment.
|
551
|
+
* @param distance
|
552
|
+
* the offset distance.
|
553
|
+
* @private
|
554
|
+
*/
|
555
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addMitreJoin = function(
|
556
|
+
p, offset0, offset1, distance) {
|
557
|
+
var isMitreWithinLimit = true;
|
558
|
+
var intPt = null;
|
559
|
+
|
560
|
+
/**
|
561
|
+
* This computation is unstable if the offset segments are nearly collinear.
|
562
|
+
* Howver, this situation should have been eliminated earlier by the check for
|
563
|
+
* whether the offset segment endpoints are almost coincident
|
564
|
+
*/
|
565
|
+
try {
|
566
|
+
intPt = jsts.algorithm.HCoordinate.intersection(offset0.p0, offset0.p1,
|
567
|
+
offset1.p0, offset1.p1);
|
568
|
+
|
569
|
+
var mitreRatio = distance <= 0.0 ? 1.0 : intPt.distance(p) /
|
570
|
+
Math.abs(distance);
|
571
|
+
|
572
|
+
if (mitreRatio > this.bufParams.getMitreLimit())
|
573
|
+
this.isMitreWithinLimit = false;
|
574
|
+
} catch (e) {
|
575
|
+
if (e instanceof jsts.error.NotRepresentableError) {
|
576
|
+
intPt = new jsts.geom.Coordinate(0, 0);
|
577
|
+
this.isMitreWithinLimit = false;
|
578
|
+
}
|
579
|
+
}
|
580
|
+
|
581
|
+
if (isMitreWithinLimit) {
|
582
|
+
this.segList.addPt(intPt);
|
583
|
+
} else {
|
584
|
+
this.addLimitedMitreJoin(offset0, offset1, distance, bufParams
|
585
|
+
.getMitreLimit());
|
586
|
+
// addBevelJoin(offset0, offset1);
|
587
|
+
}
|
588
|
+
};
|
589
|
+
|
590
|
+
|
591
|
+
/**
|
592
|
+
* Adds a limited mitre join connecting the two reflex offset segments. A
|
593
|
+
* limited mitre is a mitre which is beveled at the distance determined by the
|
594
|
+
* mitre ratio limit.
|
595
|
+
*
|
596
|
+
* @param offset0
|
597
|
+
* the first offset segment.
|
598
|
+
* @param offset1
|
599
|
+
* the second offset segment.
|
600
|
+
* @param distance
|
601
|
+
* the offset distance.
|
602
|
+
* @param mitreLimit
|
603
|
+
* the mitre limit ratio.
|
604
|
+
* @private
|
605
|
+
*/
|
606
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLimitedMitreJoin = function(
|
607
|
+
offset0, offset1, distance, mitreLimit) {
|
608
|
+
var basePt = this.seg0.p1;
|
609
|
+
|
610
|
+
var ang0 = jsts.algorithm.Angle.angle(basePt, this.seg0.p0);
|
611
|
+
var ang1 = jsts.algorithm.Angle.angle(basePt, this.seg1.p1);
|
612
|
+
|
613
|
+
// oriented angle between segments
|
614
|
+
var angDiff = jsts.algorithm.Angle.angleBetweenOriented(this.seg0.p0, basePt,
|
615
|
+
this.seg1.p1);
|
616
|
+
// half of the interior angle
|
617
|
+
var angDiffHalf = angDiff / 2;
|
618
|
+
|
619
|
+
// angle for bisector of the interior angle between the segments
|
620
|
+
var midAng = jsts.algorithm.Angle.normalize(ang0 + angDiffHalf);
|
621
|
+
// rotating this by PI gives the bisector of the reflex angle
|
622
|
+
var mitreMidAng = jsts.algorithm.Angle.normalize(midAng + Math.PI);
|
623
|
+
|
624
|
+
// the miterLimit determines the distance to the mitre bevel
|
625
|
+
var mitreDist = mitreLimit * distance;
|
626
|
+
// the bevel delta is the difference between the buffer distance
|
627
|
+
// and half of the length of the bevel segment
|
628
|
+
var bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf));
|
629
|
+
var bevelHalfLen = distance - bevelDelta;
|
630
|
+
|
631
|
+
// compute the midpoint of the bevel segment
|
632
|
+
var bevelMidX = basePt.x + mitreDist * Math.cos(mitreMidAng);
|
633
|
+
var bevelMidY = basePt.y + mitreDist * Math.sin(mitreMidAng);
|
634
|
+
var bevelMidPt = new jsts.geom.Coordinate(bevelMidX, bevelMidY);
|
635
|
+
|
636
|
+
// compute the mitre midline segment from the corner point to the bevel
|
637
|
+
// segment midpoint
|
638
|
+
var mitreMidLine = new jsts.geom.LineSegment(basePt, bevelMidPt);
|
639
|
+
|
640
|
+
// finally the bevel segment endpoints are computed as offsets from
|
641
|
+
// the mitre midline
|
642
|
+
var bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen);
|
643
|
+
var bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen);
|
644
|
+
|
645
|
+
if (this.side == jsts.geomgraph.Position.LEFT) {
|
646
|
+
this.segList.addPt(bevelEndLeft);
|
647
|
+
this.segList.addPt(bevelEndRight);
|
648
|
+
} else {
|
649
|
+
this.segList.addPt(bevelEndRight);
|
650
|
+
this.segList.addPt(bevelEndLeft);
|
651
|
+
}
|
652
|
+
};
|
653
|
+
|
654
|
+
|
655
|
+
/**
|
656
|
+
* Adds a bevel join connecting the two offset segments around a reflex corner.
|
657
|
+
*
|
658
|
+
* @param {LineSegment}
|
659
|
+
* offset0 the first offset segment.
|
660
|
+
* @param {LineSegment}
|
661
|
+
* offset1 the second offset segment.
|
662
|
+
* @private
|
663
|
+
*/
|
664
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addBevelJoin = function(
|
665
|
+
offset0, offset1) {
|
666
|
+
this.segList.addPt(offset0.p1);
|
667
|
+
this.segList.addPt(offset1.p0);
|
668
|
+
};
|
669
|
+
|
670
|
+
|
671
|
+
/**
|
672
|
+
* Add points for a circular fillet around a reflex corner. Adds the start and
|
673
|
+
* end points
|
674
|
+
*
|
675
|
+
* @param p
|
676
|
+
* base point of curve.
|
677
|
+
* @param p0
|
678
|
+
* start point of fillet curve.
|
679
|
+
* @param p1
|
680
|
+
* endpoint of fillet curve.
|
681
|
+
* @param direction
|
682
|
+
* the orientation of the fillet.
|
683
|
+
* @param radius
|
684
|
+
* the radius of the fillet.
|
685
|
+
* @private
|
686
|
+
*/
|
687
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFillet = function(p,
|
688
|
+
p0, p1, direction, radius) {
|
689
|
+
if (!(p1 instanceof jsts.geom.Coordinate)) {
|
690
|
+
this.addFillet2.apply(this, arguments);
|
691
|
+
return;
|
692
|
+
}
|
693
|
+
|
694
|
+
var dx0 = p0.x - p.x;
|
695
|
+
var dy0 = p0.y - p.y;
|
696
|
+
var startAngle = Math.atan2(dy0, dx0);
|
697
|
+
var dx1 = p1.x - p.x;
|
698
|
+
var dy1 = p1.y - p.y;
|
699
|
+
var endAngle = Math.atan2(dy1, dx1);
|
700
|
+
|
701
|
+
if (direction === jsts.algorithm.CGAlgorithms.CLOCKWISE) {
|
702
|
+
if (startAngle <= endAngle)
|
703
|
+
startAngle += 2.0 * Math.PI;
|
704
|
+
} else { // direction == COUNTERCLOCKWISE
|
705
|
+
if (startAngle >= endAngle)
|
706
|
+
startAngle -= 2.0 * Math.PI;
|
707
|
+
}
|
708
|
+
this.segList.addPt(p0);
|
709
|
+
this.addFillet(p, startAngle, endAngle, direction, radius);
|
710
|
+
this.segList.addPt(p1);
|
711
|
+
};
|
712
|
+
|
713
|
+
|
714
|
+
/**
|
715
|
+
* Adds points for a circular fillet arc between two specified angles. The start
|
716
|
+
* and end point for the fillet are not added - the caller must add them if
|
717
|
+
* required.
|
718
|
+
*
|
719
|
+
* @param direction
|
720
|
+
* is -1 for a CW angle, 1 for a CCW angle.
|
721
|
+
* @param radius
|
722
|
+
* the radius of the fillet.
|
723
|
+
* @private
|
724
|
+
*/
|
725
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFillet2 = function(p,
|
726
|
+
startAngle, endAngle, direction, radius) {
|
727
|
+
var directionFactor = direction === jsts.algorithm.CGAlgorithms.CLOCKWISE ? -1
|
728
|
+
: 1;
|
729
|
+
|
730
|
+
var totalAngle = Math.abs(startAngle - endAngle);
|
731
|
+
var nSegs = parseInt((totalAngle / this.filletAngleQuantum + 0.5));
|
732
|
+
|
733
|
+
if (nSegs < 1)
|
734
|
+
return; // no segments because angle is less than increment - nothing to do!
|
735
|
+
|
736
|
+
var initAngle, currAngleInc;
|
737
|
+
|
738
|
+
// choose angle increment so that each segment has equal length
|
739
|
+
initAngle = 0.0;
|
740
|
+
currAngleInc = totalAngle / nSegs;
|
741
|
+
|
742
|
+
var currAngle = initAngle;
|
743
|
+
var pt = new jsts.geom.Coordinate();
|
744
|
+
while (currAngle < totalAngle) {
|
745
|
+
var angle = startAngle + directionFactor * currAngle;
|
746
|
+
pt.x = p.x + radius * Math.cos(angle);
|
747
|
+
pt.y = p.y + radius * Math.sin(angle);
|
748
|
+
this.segList.addPt(pt);
|
749
|
+
currAngle += currAngleInc;
|
750
|
+
}
|
751
|
+
};
|
752
|
+
|
753
|
+
|
754
|
+
/**
|
755
|
+
* Creates a CW circle around a point
|
756
|
+
*/
|
757
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.createCircle = function(
|
758
|
+
p) {
|
759
|
+
// add start point
|
760
|
+
var pt = new jsts.geom.Coordinate(p.x + this.distance, p.y);
|
761
|
+
this.segList.addPt(pt);
|
762
|
+
this.addFillet(p, 0.0, 2.0 * Math.PI, -1, this.distance);
|
763
|
+
this.segList.closeRing();
|
764
|
+
};
|
765
|
+
|
766
|
+
|
767
|
+
/**
|
768
|
+
* Creates a CW square around a point
|
769
|
+
*/
|
770
|
+
jsts.operation.buffer.OffsetSegmentGenerator.prototype.createSquare = function(
|
771
|
+
p) {
|
772
|
+
this.segList.addPt(new jsts.geom.Coordinate(p.x + distance, p.y + distance));
|
773
|
+
this.segList.addPt(new jsts.geom.Coordinate(p.x + distance, p.y - distance));
|
774
|
+
this.segList.addPt(new jsts.geom.Coordinate(p.x - distance, p.y - distance));
|
775
|
+
this.segList.addPt(new jsts.geom.Coordinate(p.x - distance, p.y + distance));
|
776
|
+
this.segList.closeRing();
|
777
|
+
};
|