Add split method for linestring and multilinestring geometries. Use for splitting one geometry with another. Optionally performs a mutual split. r=ahocevar (closes #1929)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@8974 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -153,6 +153,237 @@ OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
|
||||
}
|
||||
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
|
||||
@@ -225,7 +456,7 @@ OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
|
||||
if(result.distance < min) {
|
||||
min = result.distance;
|
||||
best = result;
|
||||
if(min == 0) {
|
||||
if(min === 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -249,13 +480,14 @@ OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
|
||||
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, true);
|
||||
intersection = OpenLayers.Geometry.segmentsIntersect(seg0, seg1, interOptions);
|
||||
if(intersection) {
|
||||
min = 0;
|
||||
best = {
|
||||
|
||||
Reference in New Issue
Block a user