summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Geometry/LineString.js
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Geometry/LineString.js')
-rw-r--r--misc/openlayers/lib/OpenLayers/Geometry/LineString.js646
1 files changed, 0 insertions, 646 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Geometry/LineString.js b/misc/openlayers/lib/OpenLayers/Geometry/LineString.js
deleted file mode 100644
index b7d7dac..0000000
--- a/misc/openlayers/lib/OpenLayers/Geometry/LineString.js
+++ /dev/null
@@ -1,646 +0,0 @@
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Curve.js
- */
-
-/**
- * Class: OpenLayers.Geometry.LineString
- * A LineString is a Curve which, once two points have been added to it, can
- * never be less than two points long.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Curve>
- */
-OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
-
- /**
- * Constructor: OpenLayers.Geometry.LineString
- * Create a new LineString geometry
- *
- * Parameters:
- * points - {Array(<OpenLayers.Geometry.Point>)} An array of points used to
- * generate the linestring
- *
- */
-
- /**
- * APIMethod: removeComponent
- * Only allows removal of a point if there are three or more points in
- * the linestring. (otherwise the result would be just a single point)
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>} The point to be removed
- *
- * Returns:
- * {Boolean} The component was removed.
- */
- removeComponent: function(point) {
- var removed = this.components && (this.components.length > 2);
- if (removed) {
- OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
- arguments);
- }
- return removed;
- },
-
- /**
- * APIMethod: intersects
- * Test for instersection between two geometries. This is a cheapo
- * implementation of the Bently-Ottmann algorigithm. It doesn't
- * really keep track of a sweep line data structure. It is closer
- * to the brute force method, except that segments are sorted and
- * potential intersections are only calculated when bounding boxes
- * intersect.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {Boolean} The input geometry intersects this geometry.
- */
- intersects: function(geometry) {
- var intersect = false;
- var type = geometry.CLASS_NAME;
- if(type == "OpenLayers.Geometry.LineString" ||
- type == "OpenLayers.Geometry.LinearRing" ||
- type == "OpenLayers.Geometry.Point") {
- var segs1 = this.getSortedSegments();
- var segs2;
- if(type == "OpenLayers.Geometry.Point") {
- segs2 = [{
- x1: geometry.x, y1: geometry.y,
- x2: geometry.x, y2: geometry.y
- }];
- } else {
- segs2 = geometry.getSortedSegments();
- }
- var seg1, seg1x1, seg1x2, seg1y1, seg1y2,
- seg2, seg2y1, seg2y2;
- // sweep right
- outer: for(var i=0, len=segs1.length; i<len; ++i) {
- seg1 = segs1[i];
- seg1x1 = seg1.x1;
- seg1x2 = seg1.x2;
- seg1y1 = seg1.y1;
- seg1y2 = seg1.y2;
- inner: for(var j=0, jlen=segs2.length; j<jlen; ++j) {
- seg2 = segs2[j];
- if(seg2.x1 > seg1x2) {
- // seg1 still left of seg2
- break;
- }
- if(seg2.x2 < seg1x1) {
- // seg2 still left of seg1
- continue;
- }
- seg2y1 = seg2.y1;
- seg2y2 = seg2.y2;
- if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) {
- // seg2 above seg1
- continue;
- }
- if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) {
- // seg2 below seg1
- continue;
- }
- if(OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) {
- intersect = true;
- break outer;
- }
- }
- }
- } else {
- intersect = geometry.intersects(this);
- }
- return intersect;
- },
-
- /**
- * Method: getSortedSegments
- *
- * Returns:
- * {Array} An array of segment objects. Segment objects have properties
- * x1, y1, x2, and y2. The start point is represented by x1 and y1.
- * The end point is represented by x2 and y2. Start and end are
- * ordered so that x1 < x2.
- */
- getSortedSegments: function() {
- var numSeg = this.components.length - 1;
- var segments = new Array(numSeg), point1, point2;
- for(var i=0; i<numSeg; ++i) {
- point1 = this.components[i];
- point2 = this.components[i + 1];
- if(point1.x < point2.x) {
- segments[i] = {
- x1: point1.x,
- y1: point1.y,
- x2: point2.x,
- y2: point2.y
- };
- } else {
- segments[i] = {
- x1: point2.x,
- y1: point2.y,
- x2: point1.x,
- y2: point1.y
- };
- }
- }
- // more efficient to define this somewhere static
- function byX1(seg1, seg2) {
- return seg1.x1 - seg2.x1;
- }
- return segments.sort(byX1);
- },
-
- /**
- * Method: splitWithSegment
- * Split this geometry with the given segment.
- *
- * Parameters:
- * seg - {Object} An object with x1, y1, x2, and y2 properties referencing
- * segment endpoint coordinates.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source segment must be within the
- * tolerance distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of one of the source segment's
- * endpoints will be assumed to occur at the endpoint.
- *
- * Returns:
- * {Object} An object with *lines* and *points* properties. If the given
- * segment intersects this linestring, the lines array will reference
- * geometries that result from the split. The points array will contain
- * all intersection points. Intersection points are sorted along the
- * segment (in order from x1,y1 to x2,y2).
- */
- splitWithSegment: function(seg, options) {
- var edge = !(options && options.edge === false);
- var tolerance = options && options.tolerance;
- var lines = [];
- var verts = this.getVertices();
- var points = [];
- var intersections = [];
- var split = false;
- var vert1, vert2, point;
- var node, vertex, target;
- var interOptions = {point: true, tolerance: tolerance};
- var result = null;
- for(var i=0, stop=verts.length-2; i<=stop; ++i) {
- vert1 = verts[i];
- points.push(vert1.clone());
- vert2 = verts[i+1];
- target = {x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y};
- point = OpenLayers.Geometry.segmentsIntersect(
- seg, target, interOptions
- );
- if(point instanceof OpenLayers.Geometry.Point) {
- if((point.x === seg.x1 && point.y === seg.y1) ||
- (point.x === seg.x2 && point.y === seg.y2) ||
- point.equals(vert1) || point.equals(vert2)) {
- vertex = true;
- } else {
- vertex = false;
- }
- if(vertex || edge) {
- // push intersections different than the previous
- if(!point.equals(intersections[intersections.length-1])) {
- intersections.push(point.clone());
- }
- if(i === 0) {
- if(point.equals(vert1)) {
- continue;
- }
- }
- if(point.equals(vert2)) {
- continue;
- }
- split = true;
- if(!point.equals(vert1)) {
- points.push(point);
- }
- lines.push(new OpenLayers.Geometry.LineString(points));
- points = [point.clone()];
- }
- }
- }
- if(split) {
- points.push(vert2.clone());
- lines.push(new OpenLayers.Geometry.LineString(points));
- }
- if(intersections.length > 0) {
- // sort intersections along segment
- var xDir = seg.x1 < seg.x2 ? 1 : -1;
- var yDir = seg.y1 < seg.y2 ? 1 : -1;
- result = {
- lines: lines,
- points: intersections.sort(function(p1, p2) {
- return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y);
- })
- };
- }
- return result;
- },
-
- /**
- * Method: split
- * Use this geometry (the source) to attempt to split a target geometry.
- *
- * Parameters:
- * target - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- split: function(target, options) {
- var results = null;
- var mutual = options && options.mutual;
- var sourceSplit, targetSplit, sourceParts, targetParts;
- if(target instanceof OpenLayers.Geometry.LineString) {
- var verts = this.getVertices();
- var vert1, vert2, seg, splits, lines, point;
- var points = [];
- sourceParts = [];
- for(var i=0, stop=verts.length-2; i<=stop; ++i) {
- vert1 = verts[i];
- vert2 = verts[i+1];
- seg = {
- x1: vert1.x, y1: vert1.y,
- x2: vert2.x, y2: vert2.y
- };
- targetParts = targetParts || [target];
- if(mutual) {
- points.push(vert1.clone());
- }
- for(var j=0; j<targetParts.length; ++j) {
- splits = targetParts[j].splitWithSegment(seg, options);
- if(splits) {
- // splice in new features
- lines = splits.lines;
- if(lines.length > 0) {
- lines.unshift(j, 1);
- Array.prototype.splice.apply(targetParts, lines);
- j += lines.length - 2;
- }
- if(mutual) {
- for(var k=0, len=splits.points.length; k<len; ++k) {
- point = splits.points[k];
- if(!point.equals(vert1)) {
- points.push(point);
- sourceParts.push(new OpenLayers.Geometry.LineString(points));
- if(point.equals(vert2)) {
- points = [];
- } else {
- points = [point.clone()];
- }
- }
- }
- }
- }
- }
- }
- if(mutual && sourceParts.length > 0 && points.length > 0) {
- points.push(vert2.clone());
- sourceParts.push(new OpenLayers.Geometry.LineString(points));
- }
- } else {
- results = target.splitWith(this, options);
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetSplit || sourceSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- /**
- * Method: splitWith
- * Split this geometry (the target) with the given geometry (the source).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} A geometry used to split this
- * geometry (the source).
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- splitWith: function(geometry, options) {
- return geometry.split(this, options);
-
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- var vertices;
- if(nodes === true) {
- vertices = [
- this.components[0],
- this.components[this.components.length-1]
- ];
- } else if (nodes === false) {
- vertices = this.components.slice(1, this.components.length-1);
- } else {
- vertices = this.components.slice();
- }
- return vertices;
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and x2 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var details = edge && options && options.details;
- var result, best = {};
- var min = Number.POSITIVE_INFINITY;
- if(geometry instanceof OpenLayers.Geometry.Point) {
- var segs = this.getSortedSegments();
- var x = geometry.x;
- var y = geometry.y;
- var seg;
- for(var i=0, len=segs.length; i<len; ++i) {
- seg = segs[i];
- result = OpenLayers.Geometry.distanceToSegment(geometry, seg);
- if(result.distance < min) {
- min = result.distance;
- best = result;
- if(min === 0) {
- break;
- }
- } else {
- // if distance increases and we cross y0 to the right of x0, no need to keep looking.
- if(seg.x2 > x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) {
- break;
- }
- }
- }
- if(details) {
- best = {
- distance: best.distance,
- x0: best.x, y0: best.y,
- x1: x, y1: y
- };
- } else {
- best = best.distance;
- }
- } else if(geometry instanceof OpenLayers.Geometry.LineString) {
- var segs0 = this.getSortedSegments();
- var segs1 = geometry.getSortedSegments();
- var seg0, seg1, intersection, x0, y0;
- var len1 = segs1.length;
- var interOptions = {point: true};
- outer: for(var i=0, len=segs0.length; i<len; ++i) {
- seg0 = segs0[i];
- x0 = seg0.x1;
- y0 = seg0.y1;
- for(var j=0; j<len1; ++j) {
- seg1 = segs1[j];
- intersection = OpenLayers.Geometry.segmentsIntersect(seg0, seg1, interOptions);
- if(intersection) {
- min = 0;
- best = {
- distance: 0,
- x0: intersection.x, y0: intersection.y,
- x1: intersection.x, y1: intersection.y
- };
- break outer;
- } else {
- result = OpenLayers.Geometry.distanceToSegment({x: x0, y: y0}, seg1);
- if(result.distance < min) {
- min = result.distance;
- best = {
- distance: min,
- x0: x0, y0: y0,
- x1: result.x, y1: result.y
- };
- }
- }
- }
- }
- if(!details) {
- best = best.distance;
- }
- if(min !== 0) {
- // check the final vertex in this line's sorted segments
- if(seg0) {
- result = geometry.distanceTo(
- new OpenLayers.Geometry.Point(seg0.x2, seg0.y2),
- options
- );
- var dist = details ? result.distance : result;
- if(dist < min) {
- if(details) {
- best = {
- distance: min,
- x0: result.x1, y0: result.y1,
- x1: result.x0, y1: result.y0
- };
- } else {
- best = dist;
- }
- }
- }
- }
- } else {
- best = geometry.distanceTo(this, options);
- // swap since target comes from this line
- if(details) {
- best = {
- distance: best.distance,
- x0: best.x1, y0: best.y1,
- x1: best.x0, y1: best.y0
- };
- }
- }
- return best;
- },
-
- /**
- * APIMethod: simplify
- * This function will return a simplified LineString.
- * Simplification is based on the Douglas-Peucker algorithm.
- *
- *
- * Parameters:
- * tolerance - {number} threshhold for simplification in map units
- *
- * Returns:
- * {OpenLayers.Geometry.LineString} the simplified LineString
- */
- simplify: function(tolerance){
- if (this && this !== null) {
- var points = this.getVertices();
- if (points.length < 3) {
- return this;
- }
-
- var compareNumbers = function(a, b){
- return (a-b);
- };
-
- /**
- * Private function doing the Douglas-Peucker reduction
- */
- var douglasPeuckerReduction = function(points, firstPoint, lastPoint, tolerance){
- var maxDistance = 0;
- var indexFarthest = 0;
-
- for (var index = firstPoint, distance; index < lastPoint; index++) {
- distance = perpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
- if (distance > maxDistance) {
- maxDistance = distance;
- indexFarthest = index;
- }
- }
-
- if (maxDistance > tolerance && indexFarthest != firstPoint) {
- //Add the largest point that exceeds the tolerance
- pointIndexsToKeep.push(indexFarthest);
- douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance);
- douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance);
- }
- };
-
- /**
- * Private function calculating the perpendicular distance
- * TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower
- */
- var perpendicularDistance = function(point1, point2, point){
- //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle
- //Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle*
- //Area = .5*Base*H *Solve for height
- //Height = Area/.5/Base
-
- var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y));
- var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
- var height = area / bottom * 2;
-
- return height;
- };
-
- var firstPoint = 0;
- var lastPoint = points.length - 1;
- var pointIndexsToKeep = [];
-
- //Add the first and last index to the keepers
- pointIndexsToKeep.push(firstPoint);
- pointIndexsToKeep.push(lastPoint);
-
- //The first and the last point cannot be the same
- while (points[firstPoint].equals(points[lastPoint])) {
- lastPoint--;
- //Addition: the first point not equal to first point in the LineString is kept as well
- pointIndexsToKeep.push(lastPoint);
- }
-
- douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance);
- var returnPoints = [];
- pointIndexsToKeep.sort(compareNumbers);
- for (var index = 0; index < pointIndexsToKeep.length; index++) {
- returnPoints.push(points[pointIndexsToKeep[index]]);
- }
- return new OpenLayers.Geometry.LineString(returnPoints);
-
- }
- else {
- return this;
- }
- },
-
- CLASS_NAME: "OpenLayers.Geometry.LineString"
-});