Example #1
0
/**
 * Finds the angle formed by two adjacent segments defined by 3 points. The result will be the (positive clockwise)
 * angle with origin on the `startPoint-midPoint` segment, or its explementary angle if required.
 *
 * @name angle
 * @param {Coord} startPoint Start Point Coordinates
 * @param {Coord} midPoint Mid Point Coordinates
 * @param {Coord} endPoint End Point Coordinates
 * @param {Object} [options={}] Optional parameters
 * @param {boolean} [options.explementary=false] Returns the explementary angle instead (360 - angle)
 * @param {boolean} [options.mercator=false] if calculations should be performed over Mercator or WGS84 projection
 * @returns {number} Angle between the provided points, or its explementary.
 * @example
 * turf.angle([5, 5], [5, 6], [3, 4]);
 * //=45
 */
function angle(startPoint: Coord, midPoint: Coord, endPoint: Coord, options: {
    explementary?: boolean
    mercator?: boolean,
} = {}): number {
    // Optional Parameters
    if (!isObject(options)) { throw new Error("options is invalid"); }

    // Validation
    if (!startPoint) { throw new Error("startPoint is required"); }
    if (!midPoint) { throw new Error("midPoint is required"); }
    if (!endPoint) { throw new Error("endPoint is required"); }

    // Rename to shorter variables
    const A = startPoint;
    const O = midPoint;
    const B = endPoint;

    // Main
    const azimuthAO = bearingToAzimuth((options.mercator !== true) ? bearing(A, O) : rhumbBearing(A, O));
    const azimuthBO = bearingToAzimuth((options.mercator !== true) ? bearing(B, O) : rhumbBearing(B, O));
    const angleAO = Math.abs(azimuthAO - azimuthBO);

    // Explementary angle
    if (options.explementary === true) { return 360 - angleAO; }
    return angleAO;
}
Example #2
0
/**
 * Takes a {@link LineString} and returns a {@link Point} at a specified distance along the line.
 *
 * @name along
 * @param {Feature<LineString>} line input line
 * @param {number} distance distance along the line
 * @param {Object} [options] Optional parameters
 * @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
 * @returns {Feature<Point>} Point `distance` `units` along the line
 * @example
 * var line = turf.lineString([[-83, 30], [-84, 36], [-78, 41]]);
 * var options = {units: 'miles'};
 *
 * var along = turf.along(line, 200, options);
 *
 * //addToMap
 * var addToMap = [along, line]
 */
function along(line: Feature<LineString>| LineString, distance: number, options: {
    units?: Units
} = {}): Feature<Point> {
    // Optional parameters
    if (!isObject(options)) throw new Error('options is invalid');

    // Validation
    let coords;
    if (line.type === 'Feature') coords = line.geometry.coordinates;
    else if (line.type === 'LineString') coords = line.coordinates;
    else throw new Error('input must be a LineString Feature or Geometry');
    if (!isNumber(distance)) throw new Error('distance must be a number');

    let travelled = 0;
    for (let i = 0; i < coords.length; i++) {
        if (distance >= travelled && i === coords.length - 1) break;
        else if (travelled >= distance) {
            const overshot = distance - travelled;
            if (!overshot) return point(coords[i]);
            else {
                const direction = bearing(coords[i], coords[i - 1]) - 180;
                const interpolated = destination(coords[i], overshot, direction, options);
                return interpolated;
            }
        } else {
            travelled += measureDistance(coords[i], coords[i + 1], options);
        }
    }
    return point(coords[coords.length - 1]);
}
Example #3
0
/**
 * Takes a {@link LineString} and returns a {@link Point} at a specified distance along the line.
 *
 * @name along
 * @param {Feature<LineString>} line input line
 * @param {number} distance distance along the line
 * @param {Object} [options] Optional parameters
 * @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
 * @returns {Feature<Point>} Point `distance` `units` along the line
 * @example
 * var line = turf.lineString([[-83, 30], [-84, 36], [-78, 41]]);
 * var options = {units: 'miles'};
 *
 * var along = turf.along(line, 200, options);
 *
 * //addToMap
 * var addToMap = [along, line]
 */
export default function along(
    line: Feature<LineString> | LineString,
    distance: number,
    options: {units?: Units} = {},
): Feature<Point> {
    // Get Coords
    const geom = getGeom(line);
    const coords = geom.coordinates;
    let travelled = 0;
    for (let i = 0; i < coords.length; i++) {
        if (distance >= travelled && i === coords.length - 1) { break;
        } else if (travelled >= distance) {
            const overshot = distance - travelled;
            if (!overshot) { return point(coords[i]);
            } else {
                const direction = bearing(coords[i], coords[i - 1]) - 180;
                const interpolated = destination(coords[i], overshot, direction, options);
                return interpolated;
            }
        } else {
            travelled += measureDistance(coords[i], coords[i + 1], options);
        }
    }
    return point(coords[coords.length - 1]);
}
Example #4
0
    flattenEach(lines, function (line: any) {
        const coords: any = getCoords(line);

        for (let i = 0; i < coords.length - 1; i++) {
            //start
            const start = point(coords[i]);
            start.properties.dist = distance(pt, start, options);
            //stop
            const stop = point(coords[i + 1]);
            stop.properties.dist = distance(pt, stop, options);
            // sectionLength
            const sectionLength = distance(start, stop, options);
            //perpendicular
            const heightDistance = Math.max(start.properties.dist, stop.properties.dist);
            const direction = bearing(start, stop);
            const perpendicularPt1 = destination(pt, heightDistance, direction + 90, options);
            const perpendicularPt2 = destination(pt, heightDistance, direction - 90, options);
            const intersect = lineIntersects(
                lineString([perpendicularPt1.geometry.coordinates, perpendicularPt2.geometry.coordinates]),
                lineString([start.geometry.coordinates, stop.geometry.coordinates])
            );
            let intersectPt = null;
            if (intersect.features.length > 0) {
                intersectPt = intersect.features[0];
                intersectPt.properties.dist = distance(pt, intersectPt, options);
                intersectPt.properties.location = length + distance(start, intersectPt, options);
            }

            if (start.properties.dist < closestPt.properties.dist) {
                closestPt = start;
                closestPt.properties.index = i;
                closestPt.properties.location = length;
            }
            if (stop.properties.dist < closestPt.properties.dist) {
                closestPt = stop;
                closestPt.properties.index = i + 1;
                closestPt.properties.location = length + sectionLength;
            }
            if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
                closestPt = intersectPt;
                closestPt.properties.index = i;
            }
            // update length
            length += sectionLength;
        }

    });
Example #5
0
/**
 * @private
 * @name getCosAndSin
 * @param {Array<Array<number>>} coordinates
 * @returns {Array<number>} [cos, sin]
 */
function getCosAndSin(coordinates: number[][], isPlanar: boolean): [number, number] {
    const beginPoint: number[] = coordinates[0];
    const endPoint: number[] = coordinates[coordinates.length - 1];
    if (isPlanar) {
        const [x0, y0]: number[] = beginPoint;
        const [x1, y1]: number[] = endPoint;
        const dx: number = x1 - x0;
        const dy: number = y1 - y0;
        const h = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
        if (h < 0.000000001) {
            return [NaN, NaN];
        }
        const sin1 = dy / h;
        const cos1 = dx / h;
        return [sin1, cos1];
    } else {
        const angle = bearingToCartesian(bearing(beginPoint, endPoint));
        const radian = angle * Math.PI / 180;
        return [Math.sin(radian), Math.cos(radian)];
    }

}