heli-agri
Version:
HeliAgri is a high-performance, feature-packed library for creating interactive maps on the web. It can display map tiles, vector data and markers loaded from any source on any web page. OpenLayers has been developed to further the use of geographic infor
216 lines (215 loc) • 8.35 kB
JavaScript
/**
* @module ol/geom/LineString
*/
import SimpleGeometry from './SimpleGeometry.js';
import { assignClosestPoint, maxSquaredDelta } from './flat/closest.js';
import { closestSquaredDistanceXY } from '../extent.js';
import { deflateCoordinates } from './flat/deflate.js';
import { douglasPeucker } from './flat/simplify.js';
import { extend } from '../array.js';
import { forEach as forEachSegment } from './flat/segments.js';
import { inflateCoordinates } from './flat/inflate.js';
import { interpolatePoint, lineStringCoordinateAtM } from './flat/interpolate.js';
import { intersectsLineString } from './flat/intersectsextent.js';
import { lineStringLength } from './flat/length.js';
/**
* @classdesc
* Linestring geometry.
*
* @api
*/
class LineString extends SimpleGeometry {
/**
* @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates.
* For internal use, flat coordinates in combination with `layout` are also accepted.
* @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
*/
constructor(coordinates, layout) {
super();
/**
* @private
* @type {import("../coordinate.js").Coordinate}
*/
this.flatMidpoint_ = null;
/**
* @private
* @type {number}
*/
this.flatMidpointRevision_ = -1;
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
if (layout !== undefined && !Array.isArray(coordinates[0])) {
this.setFlatCoordinates(layout,
/** @type {Array<number>} */ (coordinates));
}
else {
this.setCoordinates(
/** @type {Array<import("../coordinate.js").Coordinate>} */ (coordinates), layout);
}
}
/**
* Append the passed coordinate to the coordinates of the linestring.
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
* @api
*/
appendCoordinate(coordinate) {
if (!this.flatCoordinates) {
this.flatCoordinates = coordinate.slice();
}
else {
extend(this.flatCoordinates, coordinate);
}
this.changed();
}
/**
* Make a complete copy of the geometry.
* @return {!LineString} Clone.
* @api
*/
clone() {
const lineString = new LineString(this.flatCoordinates.slice(), this.layout);
lineString.applyProperties(this);
return lineString;
}
/**
* @param {number} x X.
* @param {number} y Y.
* @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @return {number} Minimum squared distance.
*/
closestPointXY(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(maxSquaredDelta(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return assignClosestPoint(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
}
/**
* Iterate over each segment, calling the provided callback.
* If the callback returns a truthy value the function returns that
* value immediately. Otherwise the function returns `false`.
*
* @param {function(this: S, import("../coordinate.js").Coordinate, import("../coordinate.js").Coordinate): T} callback Function
* called for each segment. The function will receive two arguments, the start and end coordinates of the segment.
* @return {T|boolean} Value.
* @template T,S
* @api
*/
forEachSegment(callback) {
return forEachSegment(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, callback);
}
/**
* Returns the coordinate at `m` using linear interpolation, or `null` if no
* such coordinate exists.
*
* `extrapolate` controls extrapolation beyond the range of Ms in the
* MultiLineString. If `extrapolate` is `true` then Ms less than the first
* M will return the first coordinate and Ms greater than the last M will
* return the last coordinate.
*
* @param {number} m M.
* @param {boolean} [extrapolate] Extrapolate. Default is `false`.
* @return {import("../coordinate.js").Coordinate|null} Coordinate.
* @api
*/
getCoordinateAtM(m, extrapolate) {
if (this.layout != 'XYM' && this.layout != 'XYZM') {
return null;
}
extrapolate = extrapolate !== undefined ? extrapolate : false;
return lineStringCoordinateAtM(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, m, extrapolate);
}
/**
* Return the coordinates of the linestring.
* @return {Array<import("../coordinate.js").Coordinate>} Coordinates.
* @api
*/
getCoordinates() {
return inflateCoordinates(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
}
/**
* Return the coordinate at the provided fraction along the linestring.
* The `fraction` is a number between 0 and 1, where 0 is the start of the
* linestring and 1 is the end.
* @param {number} fraction Fraction.
* @param {import("../coordinate.js").Coordinate} [dest] Optional coordinate whose values will
* be modified. If not provided, a new coordinate will be returned.
* @return {import("../coordinate.js").Coordinate} Coordinate of the interpolated point.
* @api
*/
getCoordinateAt(fraction, dest) {
return interpolatePoint(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, fraction, dest, this.stride);
}
/**
* Return the length of the linestring on projected plane.
* @return {number} Length (on projected plane).
* @api
*/
getLength() {
return lineStringLength(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
}
/**
* @return {Array<number>} Flat midpoint.
*/
getFlatMidpoint() {
if (this.flatMidpointRevision_ != this.getRevision()) {
this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
this.flatMidpointRevision_ = this.getRevision();
}
return this.flatMidpoint_;
}
/**
* @param {number} squaredTolerance Squared tolerance.
* @return {LineString} Simplified LineString.
* @protected
*/
getSimplifiedGeometryInternal(squaredTolerance) {
const simplifiedFlatCoordinates = [];
simplifiedFlatCoordinates.length = douglasPeucker(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, squaredTolerance, simplifiedFlatCoordinates, 0);
return new LineString(simplifiedFlatCoordinates, 'XY');
}
/**
* Get the type of this geometry.
* @return {import("./Geometry.js").Type} Geometry type.
* @api
*/
getType() {
return 'LineString';
}
/**
* Test if the geometry and the passed extent intersect.
* @param {import("../extent.js").Extent} extent Extent.
* @return {boolean} `true` if the geometry and the extent intersect.
* @api
*/
intersectsExtent(extent) {
return intersectsLineString(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, extent);
}
/**
* Set the coordinates of the linestring.
* @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates.
* @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
* @api
*/
setCoordinates(coordinates, layout) {
this.setLayout(layout, coordinates, 1);
if (!this.flatCoordinates) {
this.flatCoordinates = [];
}
this.flatCoordinates.length = deflateCoordinates(this.flatCoordinates, 0, coordinates, this.stride);
this.changed();
}
}
export default LineString;