export function getBearingAndCoordinatesAlongLine ({
  coordinates,
  spacingMeters = DIRECTION_MARKER_SPACING_METERS
}) {
  const markers = [{
    bearing: bearing(point(coordinates[0]), point(coordinates[1])),
    coordinates: [coordinates[0][0], coordinates[0][1]]
  }]

  for (let segIdx = 1, distanceToLastMarker = 0, totalDistance = 0; segIdx < coordinates.length; segIdx++) {
    const segStart = coordinates[segIdx - 1]
    const segEnd = coordinates[segIdx]
    const distanceThisSegment = distance(point(segStart), point(segEnd), 'kilometers') * 1000

    // while not if, may need multiple markers on a single long segment
    while (distanceToLastMarker + spacingMeters < totalDistance + distanceThisSegment) {
      // total distance is at start of this segment, figure out how much of the spacing is in this segment vs. last
      const metersIntoThisSegment = distanceToLastMarker + spacingMeters - totalDistance
      const frac = metersIntoThisSegment / distanceThisSegment
      const lat = segStart[1] + (segEnd[1] - segStart[1]) * frac
      const lon = segStart[0] + (segEnd[0] - segStart[0]) * frac

      markers.push({
        bearing: bearing(point(segStart), point(segEnd)),
        coordinates: [lon, lat]
      })

      distanceToLastMarker += spacingMeters
    }
    totalDistance += distanceThisSegment
  }

  return markers
}
Beispiel #2
0
function lineBuffer(line, radius, units, resolution) {
  var lineOffset = [];

  line.geometry.coordinates = removeDuplicates(line.geometry.coordinates);

  if (!(equalArrays(line.geometry.coordinates[0],line.geometry.coordinates[line.geometry.coordinates.length-1]))) {

    // situation at first point
    var firstLinePoint = helpers.point(line.geometry.coordinates[0]);
    var secondLinePoint = helpers.point(line.geometry.coordinates[1]);
    var firstLineBearing = bearing(firstLinePoint, secondLinePoint);
    var firstBufferPoint = destination(firstLinePoint, radius, firstLineBearing + 90, units);

    // situation at last point
    var lastLinePoint = helpers.point(line.geometry.coordinates[line.geometry.coordinates.length-1]);
    var secondlastLinePoint = helpers.point(line.geometry.coordinates[line.geometry.coordinates.length-2]);
    var lastLineBearing = bearing(lastLinePoint, secondlastLinePoint);

    lineOffset.push([]);
    lineOffset[0].push.apply(lineOffset[0],[firstBufferPoint.geometry.coordinates]); // Add first buffer point in order to close ring
    lineOffset[0].push.apply(lineOffset[0],lineOffsetOneSide(line, radius, units, resolution, false, true).geometry.coordinates);
    lineOffset[0].push.apply(lineOffset[0],arc(lastLinePoint, radius, lastLineBearing - 90, lastLineBearing + 90, units, resolution, true).geometry.coordinates);
    lineOffset[0].push.apply(lineOffset[0],lineOffsetOneSide(line, radius, units, resolution, true, true).geometry.coordinates);
    lineOffset[0].push.apply(lineOffset[0],arc(firstLinePoint, radius, firstLineBearing - 90, firstLineBearing + 90, units, resolution, true).geometry.coordinates);

    return offsetToBuffer(helpers.polygon(lineOffset));

  } else {

    lineOffset.push(ringOffsetOneSide(line, radius, units, resolution, false, true).geometry.coordinates);
    lineOffset.push(ringOffsetOneSide(line, radius, units, resolution, true, true).geometry.coordinates);

    return offsetToBuffer(helpers.polygon(lineOffset));
  }
}
Beispiel #3
0
module.exports = function (from, to) {
    var dist = distance(from, to, 'miles');
    var heading = bearing(from, to);
    var midpoint = destination(from, dist / 2, heading, 'miles');

    return midpoint;
};
Beispiel #4
0
module.exports = function (point1, point2) {
    var dist = distance(point1, point2, 'miles');
    var heading = bearing(point1, point2);
    var midpoint = destination(point1, dist / 2, heading, 'miles');

    return midpoint;
};
function pointOnLine (pt, coords) {
  var units = 'miles'
  var closestPt = point([Infinity, Infinity], {dist: Infinity});
  for(var i = 0; i < coords.length - 1; i++) {
    var start = point(coords[i])
    var stop = point(coords[i+1])
    //start
    start.properties.dist = distance(pt, start, units);
    //stop
    stop.properties.dist = distance(pt, stop, units);
    //perpendicular
    var direction = bearing(start, stop)
    var perpendicularPt = destination(pt, 1000 , direction + 90, units) // 1000 = gross
    var intersect = lineIntersects(
      pt.geometry.coordinates[0],
      pt.geometry.coordinates[1],
      perpendicularPt.geometry.coordinates[0],
      perpendicularPt.geometry.coordinates[1],
      start.geometry.coordinates[0],
      start.geometry.coordinates[1],
      stop.geometry.coordinates[0],
      stop.geometry.coordinates[1]
      );
    if(!intersect) {
      perpendicularPt = destination(pt, 1000 , direction - 90, units) // 1000 = gross
      intersect = lineIntersects(
        pt.geometry.coordinates[0],
        pt.geometry.coordinates[1],
        perpendicularPt.geometry.coordinates[0],
        perpendicularPt.geometry.coordinates[1],
        start.geometry.coordinates[0],
        start.geometry.coordinates[1],
        stop.geometry.coordinates[0],
        stop.geometry.coordinates[1]
        );
    }
    perpendicularPt.properties.dist = Infinity;
    var intersectPt;
    if(intersect) {
      var intersectPt = point(intersect);
      intersectPt.properties.dist = distance(pt, intersectPt, units);
    }
    
    if(start.properties.dist < closestPt.properties.dist) {
      closestPt = start;
      closestPt.properties.index = i;
    }
    if(stop.properties.dist < closestPt.properties.dist) {
     closestPt = stop;
     closestPt.properties.index = i;
    }
    if(intersectPt && intersectPt.properties.dist < closestPt.properties.dist){ 
      closestPt = intersectPt;
      closestPt.properties.index = i;
    }
  }
  
  return closestPt;
}
Beispiel #6
0
function lineOffsetOneSide(line, radius, units, resolution, reverse, right) {
  if (reverse === undefined) var reverse = false;
  if (right === undefined) var right = true;
  if (reverse) line.geometry.coordinates = line.geometry.coordinates.reverse();
  var coords = line.geometry.coordinates;
  var lineOffset = [];
  if (coords.length == 2) return helpers.lineString(lineOffset)

  for (var i = 1; i < coords.length-1; i++) {
    var previousLinePoint = helpers.point(coords[i-1]);
    var currentLinePoint = helpers.point(coords[i]);
    var nextLinePoint = helpers.point(coords[i+1]);
    var previousLineBearing = bearing(currentLinePoint, previousLinePoint);
    var nextLineBearing = bearing(currentLinePoint, nextLinePoint);
    lineOffset.push.apply(lineOffset, arc(currentLinePoint, radius, previousLineBearing - Math.pow(-1, right + 1) * 90, nextLineBearing + Math.pow(-1, right + 1) * 90, units, resolution, right, true).geometry.coordinates);
  }

  return helpers.lineString(lineOffset)
}
Beispiel #7
0
function ringOffsetOneSide(ring, radius, units, resolution, reverse, right) {
  if (reverse === undefined) var reverse = false;
  if (right === undefined) var right = true;
  if (reverse) ring.geometry.coordinates = ring.geometry.coordinates.reverse();
  var coords = ring.geometry.coordinates; // ring is a lineString
  var ringOffset = [];

  // situation at current point = point 0
  var previousRingPoint = helpers.point(coords[coords.length-2]);
  var currentRingPoint = helpers.point(coords[0]);
  var nextRingPoint = helpers.point(coords[1]);
  var nextRingBearing = bearing(currentRingPoint, nextRingPoint);
  var currentBufferPoint = destination(currentRingPoint, radius, nextRingBearing + 90, units);
  var previousRingBearing = bearing(currentRingPoint, previousRingPoint);

  ringOffset.push.apply(ringOffset, [currentBufferPoint.geometry.coordinates]); // Add first buffer point in order to close ring
  ringOffset.push.apply(ringOffset, lineOffsetOneSide(ring, radius, units, resolution, false, right).geometry.coordinates);
  ringOffset.push.apply(ringOffset, arc(currentRingPoint, radius, previousRingBearing - Math.pow(-1, right + 1) * 90, nextRingBearing + Math.pow(-1, right + 1) * 90, units, resolution, right, true).geometry.coordinates);

  return helpers.lineString(ringOffset)
}
Beispiel #8
0
module.exports = function lineSliceAlong(line, startDist, stopDist, units) {
    var coords;
    var slice = [];
    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');

    var travelled = 0;
    var overshot, direction, interpolated;
    for (var i = 0; i < coords.length; i++) {
        if (startDist >= travelled && i === coords.length - 1) break;
        else if (travelled > startDist && slice.length === 0) {
            overshot = startDist - travelled;
            if (!overshot) return slice.push(coords[i]);
            direction = bearing(coords[i], coords[i - 1]) - 180;
            interpolated = destination(coords[i], overshot, direction, units);
            slice.push(interpolated.geometry.coordinates);
        }

        if (travelled >= stopDist) {
            overshot = stopDist - travelled;
            if (!overshot) return slice.push(coords[i]);
            direction = bearing(coords[i], coords[i - 1]) - 180;
            interpolated = destination(coords[i], overshot, direction, units);
            slice.push(interpolated.geometry.coordinates);
            return lineString(slice);
        }

        if (travelled >= startDist) {
            slice.push(coords[i]);
        }

        travelled += distance(coords[i], coords[i + 1], units);
    }
    return lineString(coords[coords.length - 1]);
};
function locatePoint(pt, coords, mCoord) {
  var units = 'miles';
  
  var closestPt = point([Infinity, Infinity], {
    dist: Infinity
  });
  for (var i = 0; i < coords.length - 1; i++) {
    var start = point(coords[i]);
    var stop = point(coords[i + 1]);
    //start
    start.properties.dist = distance(pt, start, units);
    //stop
    stop.properties.dist = distance(pt, stop, units);
    //perpendicular
    var direction = bearing(start, stop);
    var perpendicularPt = destination(pt, 1000, direction + 90, units); // 1000 = gross
    var intersect = lineIntersects(
      pt.geometry.coordinates[0],
      pt.geometry.coordinates[1],
      perpendicularPt.geometry.coordinates[0],
      perpendicularPt.geometry.coordinates[1],
      start.geometry.coordinates[0],
      start.geometry.coordinates[1],
      stop.geometry.coordinates[0],
      stop.geometry.coordinates[1]
    );
    if (!intersect) {
      perpendicularPt = destination(pt, 1000, direction - 90, units); // 1000 = gross
      intersect = lineIntersects(
        pt.geometry.coordinates[0],
        pt.geometry.coordinates[1],
        perpendicularPt.geometry.coordinates[0],
        perpendicularPt.geometry.coordinates[1],
        start.geometry.coordinates[0],
        start.geometry.coordinates[1],
        stop.geometry.coordinates[0],
        stop.geometry.coordinates[1]
      );
    }
    perpendicularPt.properties.dist = Infinity;
    var intersectPt;
    if (intersect) {
      var intersectPt = point(intersect);
      intersectPt.properties.dist = distance(pt, intersectPt, units);
    }
	
    if (start.properties.dist < closestPt.properties.dist) {
      closestPt = start;
      closestPt.properties.index = i;
    }
    if (stop.properties.dist < closestPt.properties.dist) {
      closestPt = stop;
      closestPt.properties.index = i;
    }
    if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
      closestPt = intersectPt;
      closestPt.properties.index = i;
    }
  }

  var measureValue = interpolateM(coords[closestPt.properties.index], coords[closestPt.properties.index+1],closestPt,mCoord);

  return event({
	  fromM:measureValue,
	  offset:closestPt.properties.dist,
	  properties:pt.properties || {}
  });
  
}
Beispiel #10
0
export default function getStops ({segments}) {
  if (segments.length === 0) return []

  if (segments.length === 1 && segments[0].geometry.type === 'Point') {
    let coord = segments[0].geometry.coordinates

    return [{
      stopId: segments[0].fromStopId,
      index: 0,
      lat: coord[1],
      lon: coord[0],
      bearing: false, // this will hide directional icon, which is what we want
      autoCreated: !segments[0].stopAtStart,
      distanceFromStart: 0
    }]
  }

  let ret = []

  let coord = segments[0].geometry.coordinates[0]

  ret.push({
    stopId: segments[0].fromStopId,
    index: 0,
    lat: coord[1],
    lon: coord[0],
    bearing: bearing(point(coord), point(segments[0].geometry.coordinates[1])),
    autoCreated: !segments[0].stopAtStart,
    distanceFromStart: 0
  })

  // loop over the route, making stops as we go
  let distanceToLastStop = 0
  let distanceToLineSegmentStart = 0

  for (let segIdx = 0; segIdx < segments.length; segIdx++) {
    const segment = segments[segIdx]
    // now loop over line segments within this segment, accumulating distance as we go
    // a single transit segment can have multiple line segments, because we've used a street router between endpoints
    for (let i = 1; i < segment.geometry.coordinates.length; i++) {
      const c0 = segment.geometry.coordinates[i - 1]
      const c1 = segment.geometry.coordinates[i]
      const distanceThisLineSegment = distance(point(c0), point(c1), 'kilometers') * 1000

      // segment.spacing = 0 means no automatic stop creation in this segment
      while (segment.spacing > 0 && distanceToLastStop + segment.spacing < distanceToLineSegmentStart + distanceThisLineSegment) {
        // how far into the segment do we place the stop
        let frac = (distanceToLastStop + segment.spacing - distanceToLineSegmentStart) / distanceThisLineSegment
        if (frac < 0) frac = 0 // most likely the last segment did not have automatic stop creation

        let pos = [c0[0] + (c1[0] - c0[0]) * frac, c0[1] + (c1[1] - c0[1]) * frac]

        // can't just add segment.spacing because of converting negative fractions to zero above
        // this can happen when the last segment did not have automatic stop creation, or had a larger spacing
        // TODO in the latter case, we probably want to continue to apply the spacing from the last line segment until we create a new stop?
        distanceToLastStop = distanceToLineSegmentStart + frac * distanceThisLineSegment

        ret.push({
          stopId: null,
          index: segIdx,
          lat: pos[1],
          lon: pos[0],
          autoCreated: true,
          bearing: bearing(point(c0), point(c1)),
          distanceFromStart: distanceToLastStop
        })
      }

      distanceToLineSegmentStart += distanceThisLineSegment
    }

    if (segment.stopAtEnd) {
      let endCoord = segment.geometry.coordinates.slice(-1)[0]
      ret.push({
        stopId: segment.toStopId,
        index: segIdx + 1,
        lat: endCoord[1],
        lon: endCoord[0],
        autoCreated: false,
        distanceFromStart: distanceToLineSegmentStart,
        bearing: segIdx < segments.length - 1
          ? bearing(point(segments[segIdx + 1].geometry.coordinates[0]), point(segments[segIdx + 1].geometry.coordinates[1]))
          : false
      })

      // restart the spacing
      distanceToLastStop = distanceToLineSegmentStart // distanceToLineSegmentStart already set to the start of the next line segment
    }
  }

  // filter out autocreated stops that are very close to bona fide stops
  ret = ret.filter((stop, stopIndex, stops) => {
    if (!stop.autoCreated) return true

    let spacingThisSegment = segments[stop.index].spacing

    if (spacingThisSegment === 0) {
      // fail harder?
      debug(`segment ${stop.index} contains auto-created stops but does not have automatic stop creation enabled?`)
      return true
    }

    // last stop
    if (stopIndex === stops.length - 1) return true

    // only need to check if it's too close to the next stop, as it will always be spaced away from the previous
    // stop, since we flow stops forward from the bona fide stops
    let nextStop = stops[stopIndex + 1]
    let delta = nextStop.distanceFromStart - stop.distanceFromStart
    if (!nextStop.autoCreated && delta / spacingThisSegment < MIN_SPACING_PERCENTAGE) return false
    else return true
  })

  return ret
}