///|
pub fn interpolate_point(
start : Point,
finish : Point,
fraction : Double,
) -> Result[Point, RouteError] {
match validate_point(start, 0) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_point(finish, 1) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_fraction(fraction) {
Ok(_) => ()
Err(err) => return Err(err)
}
Ok(interpolate_point_unchecked(start, finish, fraction))
}
///|
pub fn point_at_distance(
points : ArrayView[Point],
distance_m : Double,
) -> Result[RouteSample, RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_distance(distance_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
if points.length() == 1 {
return Ok(RouteSample(points[0], 0.0, 0, 0.0))
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
if total == 0.0 || distance_m <= 0.0 {
return Ok(RouteSample(points[0], 0.0, 0, 0.0))
}
if distance_m >= total {
return Ok(
RouteSample(points[points.length() - 1], total, points.length() - 2, 1.0),
)
}
let mut walked = 0.0
for i in 1.. value
Err(err) => return Err(err)
}
if segment_m == 0.0 {
()
} else if walked + segment_m >= distance_m {
let fraction = (distance_m - walked) / segment_m
let point = interpolate_point_unchecked(
points[i - 1],
points[i],
fraction,
)
return Ok(RouteSample(point, distance_m, i - 1, fraction))
}
walked = walked + segment_m
}
Ok(RouteSample(points[points.length() - 1], total, points.length() - 2, 1.0))
}
///|
pub fn sample_route_by_count(
points : ArrayView[Point],
count : Int,
) -> Result[Array[RouteSample], RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_sample_count(count) {
Ok(_) => ()
Err(err) => return Err(err)
}
let out = Array::new(capacity=count)
if count == 1 {
match point_at_distance(points, 0.0) {
Ok(sample) => out.push(sample)
Err(err) => return Err(err)
}
return Ok(out)
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
let step = total / (count - 1).to_double()
for i in 0.. out.push(sample)
Err(err) => return Err(err)
}
}
Ok(out)
}
///|
pub fn sample_route_every(
points : ArrayView[Point],
interval_m : Double,
include_end? : Bool = true,
) -> Result[Array[RouteSample], RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_positive_distance(interval_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
let out = Array::new()
match point_at_distance(points, 0.0) {
Ok(sample) => out.push(sample)
Err(err) => return Err(err)
}
if total == 0.0 {
return Ok(out)
}
let mut distance = interval_m
while distance < total {
match point_at_distance(points, distance) {
Ok(sample) => out.push(sample)
Err(err) => return Err(err)
}
distance = distance + interval_m
}
if include_end {
match point_at_distance(points, total) {
Ok(sample) =>
if out.length() == 0 ||
!points_equal(out[out.length() - 1].point, sample.point) {
out.push(sample)
}
Err(err) => return Err(err)
}
}
Ok(out)
}
///|
pub fn resample_route_by_count(
points : ArrayView[Point],
count : Int,
) -> Result[Array[Point], RouteError] {
let samples = match sample_route_by_count(points, count) {
Ok(value) => value
Err(err) => return Err(err)
}
let out = Array::new(capacity=samples.length())
for sample in samples {
out.push(sample.point)
}
Ok(out)
}
///|
pub fn resample_route_every(
points : ArrayView[Point],
interval_m : Double,
include_end? : Bool = true,
) -> Result[Array[Point], RouteError] {
let samples = match sample_route_every(points, interval_m, include_end~) {
Ok(value) => value
Err(err) => return Err(err)
}
let out = Array::new(capacity=samples.length())
for sample in samples {
out.push(sample.point)
}
Ok(out)
}
///|
pub fn densify_route(
points : ArrayView[Point],
max_segment_m : Double,
) -> Result[Array[Point], RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_positive_distance(max_segment_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
let out = Array::new()
out.push(points[0])
if points.length() < 2 {
return Ok(out)
}
for i in 1.. value
Err(err) => return Err(err)
}
if distance > max_segment_m {
let pieces = (distance / max_segment_m).ceil().to_int()
for step in 1.. Result[RouteSlice, RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_distance(start_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_distance(end_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
if end_m < start_m {
return Err(InvalidDistance(distance_m=end_m))
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
let start_clamped = min_double(start_m, total)
let end_clamped = min_double(end_m, total)
let out = Array::new()
let start_sample = match point_at_distance(points, start_clamped) {
Ok(value) => value
Err(err) => return Err(err)
}
let end_sample = match point_at_distance(points, end_clamped) {
Ok(value) => value
Err(err) => return Err(err)
}
out.push(start_sample.point)
let distances = match cumulative_distances(points) {
Ok(value) => value
Err(err) => return Err(err)
}
for i in 0.. start_clamped && distance < end_clamped {
if !points_equal(out[out.length() - 1], points[i]) {
out.push(points[i])
}
}
}
if !points_equal(out[out.length() - 1], end_sample.point) {
out.push(end_sample.point)
}
Ok(RouteSlice(start_clamped, end_clamped, end_clamped - start_clamped, out))
}
///|
pub fn split_route_by_distance(
points : ArrayView[Point],
max_slice_m : Double,
) -> Result[Array[RouteSlice], RouteError] {
match require_points(points) {
Ok(_) => ()
Err(err) => return Err(err)
}
match validate_positive_distance(max_slice_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
let out = Array::new()
if total == 0.0 {
match slice_route(points, 0.0, 0.0) {
Ok(value) => out.push(value)
Err(err) => return Err(err)
}
return Ok(out)
}
let mut start = 0.0
while start < total {
let finish = min_double(start + max_slice_m, total)
match slice_route(points, start, finish) {
Ok(value) => out.push(value)
Err(err) => return Err(err)
}
start = finish
}
Ok(out)
}
///|
pub fn split_route_by_count(
points : ArrayView[Point],
count : Int,
) -> Result[Array[RouteSlice], RouteError] {
match validate_sample_count(count) {
Ok(_) => ()
Err(err) => return Err(err)
}
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
let out = Array::new(capacity=count)
if count == 1 || total == 0.0 {
match slice_route(points, 0.0, total) {
Ok(value) => out.push(value)
Err(err) => return Err(err)
}
return Ok(out)
}
let step = total / count.to_double()
for i in 0.. out.push(value)
Err(err) => return Err(err)
}
}
Ok(out)
}
///|
pub fn prefix_route(
points : ArrayView[Point],
distance_m : Double,
) -> Result[RouteSlice, RouteError] {
slice_route(points, 0.0, distance_m)
}
///|
pub fn suffix_route(
points : ArrayView[Point],
distance_m : Double,
) -> Result[RouteSlice, RouteError] {
let total = match route_distance_meters(points) {
Ok(value) => value
Err(err) => return Err(err)
}
match validate_distance(distance_m) {
Ok(_) => ()
Err(err) => return Err(err)
}
let start = if distance_m >= total { 0.0 } else { total - distance_m }
slice_route(points, start, total)
}