<commit_before>package route

import (
	"fmt"
	"geo"
	"graph"
	"math"
)

// Returns a human readable string for the given distance value.
func FormatDistance(distance float64) Distance {
	switch {
	case distance < 0.5:
		// Yes, this is a gag. Why do you even have to ask?
		t := fmt.Sprintf("%.2f mm", distance*1000.0)
		return Distance{t, int(distance)}
	case distance < 500.0:
		t := fmt.Sprintf("%.2f m", distance)
		return Distance{t, int(distance)}
	}
	t := fmt.Sprintf("%.2f km", distance/1000.0)
	return Distance{t, int(distance)}
}

// Returns a human readable formatting for the given time-span.
func FormatDuration(seconds float64) Duration {
	switch {
	case seconds < 30.0:
		t := fmt.Sprintf("%.2f secs", seconds)
		return Duration{t, int(seconds)}
	case seconds < 1800.0:
		t := fmt.Sprintf("%.2f mins", seconds/60.0)
		return Duration{t, int(seconds)}
	}
	t := fmt.Sprintf("%.2f hours", seconds/3600.0)
	return Duration{t, int(seconds)}
}

// Since we don't actually have max_speed values yet, we make
// something up for the time values.
// Wolfram Alpha tells me that the "typical human walking speed"
// is 1.1 m/s. So let's just roll with that.
func MockupDuration(distance float64) Duration {
	return FormatDuration(distance / 1.1)
}

// Convert from geo.Coordinate to a Point.
func StepToPoint(step geo.Coordinate) Point {
	return Point{step.Lat, step.Lng}
}

// Given a path from start to stop with intermediate steps, turn
// it into a Polyline for json output.
func StepsToPolyline(steps []geo.Coordinate, start, stop geo.Coordinate) Polyline {
	polyline := make([]Point, len(steps)+2)
	polyline[0] = StepToPoint(start)
	polyline[len(steps)+1] = StepToPoint(stop)
	for i, s := range steps {
		polyline[i+1] = StepToPoint(s)
	}
	return polyline
}

// Convert the path from start - steps - stop to a json Step
func PartwayToStep(steps []geo.Coordinate, start, stop geo.Coordinate, length float64) Step {
	instruction := fmt.Sprintf(
		"Walk from (%.4f, %.4f) to (%.4f, %.4f)",
		start.Lat, start.Lng, stop.Lat, stop.Lng)
	return Step{
		Distance:      FormatDistance(length),
		Duration:      MockupDuration(length),
		StartLocation: StepToPoint(start),
		EndLocation:   StepToPoint(stop),
		Polyline:      StepsToPolyline(steps, start, stop),
		Instruction:   instruction,
	}
}

// Convert a Path (start - steps - stop) into a json Step structure.
// This contains some additional information, which might or might
// not be accurate.
func WayToStep(steps graph.Way, start, stop geo.Coordinate) Step {
	return PartwayToStep(steps.Steps, start, stop, steps.Length)
}

// Convert an Edge (u,v) into a json Step
func EdgeToStep(g graph.Graph, edge graph.Edge, u, v graph.Vertex) Step {
	// transport (here graph.Car) does not matter for the metric distance
	// TODO only allocate once ([]geo.Coordinate(nil))
	return PartwayToStep(g.EdgeSteps(edge, u, []geo.Coordinate(nil)), g.VertexCoordinate(u), g.VertexCoordinate(v), g.EdgeWeight(edge, graph.Car, graph.Distance))
}

// Convert a single path as returned by Dijkstra to a json Leg.
func PathToLeg(g graph.Graph, distance float64, vertices []graph.Vertex, edges []graph.Edge, start, stop *graph.Way) *Leg {
	// Determine the number of steps on this path.
	totalSteps := len(edges)
	if start != nil && start.Length > 1e-7 {
		totalSteps++
	}
	if stop != nil && stop.Length > 1e-7 {
		totalSteps++
	}
	steps := make([]Step, totalSteps)

	// Add the initial step, if present
	i := 0
	if start != nil && start.Length > 1e-7 {
		// Our implementation of Dijkstra's algorithm ensures len(vertices) > 0
		steps[0] = WayToStep(*start, start.Target, g.VertexCoordinate(vertices[0]))
		i++
	}

	// Add the intermediate steps
	for j, edge := range edges {
		from := vertices[j]
		to := vertices[j+1]
		steps[i] = EdgeToStep(g, edge, from, to)
		i++
	}

	// Add the final step, if present
	if stop != nil && stop.Length > 1e-7 {
		prev := vertices[len(vertices)-1]
		steps[i] = WayToStep(*stop, g.VertexCoordinate(prev), stop.Target)
	}

	return &Leg{
		Distance:      FormatDistance(distance),
		Duration:      MockupDuration(distance),
		StartLocation: StepToPoint(start.Target),
		EndLocation:   StepToPoint(stop.Target),
		Steps:         steps,
	}
}

// Computes the union of two BoundingBox'es.
func BoxUnion(a, b BoundingBox) BoundingBox {
	// Ok, maybe this wasn't such a good idea after all:
	nwLat := math.Max(a.Northwest[0], b.Northwest[0])
	nwLng := math.Min(a.Northwest[1], b.Northwest[1])
	seLat := math.Min(a.Southeast[0], b.Southeast[0])
	seLng := math.Max(a.Southeast[1], b.Southeast[1])
	return BoundingBox{Point{nwLat, nwLng}, Point{seLat, seLng}}
}

// Compute a tight bounding box for a single step.
func ComputeBoundsStep(step Step) BoundingBox {
	if len(step.Polyline) == 0 {
		// Bug?
		return BoundingBox{Point{0.0, 0.0}, Point{0.0, 0.0}}
	}

	bounds := BoundingBox{step.Polyline[0], step.Polyline[0]}
	if len(step.Polyline) > 1 {<commit_msg>Don't use start and stop in PathToLeg, if they are nil.<commit_after>package route

import (
	"fmt"
	"geo"
	"graph"
	"math"
)

// Returns a human readable string for the given distance value.
func FormatDistance(distance float64) Distance {
	switch {
	case distance < 0.5:
		// Yes, this is a gag. Why do you even have to ask?
		t := fmt.Sprintf("%.2f mm", distance*1000.0)
		return Distance{t, int(distance)}
	case distance < 500.0:
		t := fmt.Sprintf("%.2f m", distance)
		return Distance{t, int(distance)}
	}
	t := fmt.Sprintf("%.2f km", distance/1000.0)
	return Distance{t, int(distance)}
}

// Returns a human readable formatting for the given time-span.
func FormatDuration(seconds float64) Duration {
	switch {
	case seconds < 30.0:
		t := fmt.Sprintf("%.2f secs", seconds)
		return Duration{t, int(seconds)}
	case seconds < 1800.0:
		t := fmt.Sprintf("%.2f mins", seconds/60.0)
		return Duration{t, int(seconds)}
	}
	t := fmt.Sprintf("%.2f hours", seconds/3600.0)
	return Duration{t, int(seconds)}
}

// Since we don't actually have max_speed values yet, we make
// something up for the time values.
// Wolfram Alpha tells me that the "typical human walking speed"
// is 1.1 m/s. So let's just roll with that.
func MockupDuration(distance float64) Duration {
	return FormatDuration(distance / 1.1)
}

// Convert from geo.Coordinate to a Point.
func StepToPoint(step geo.Coordinate) Point {
	return Point{step.Lat, step.Lng}
}

// Given a path from start to stop with intermediate steps, turn
// it into a Polyline for json output.
func StepsToPolyline(steps []geo.Coordinate, start, stop geo.Coordinate) Polyline {
	polyline := make([]Point, len(steps)+2)
	polyline[0] = StepToPoint(start)
	polyline[len(steps)+1] = StepToPoint(stop)
	for i, s := range steps {
		polyline[i+1] = StepToPoint(s)
	}
	return polyline
}

// Convert the path from start - steps - stop to a json Step
func PartwayToStep(steps []geo.Coordinate, start, stop geo.Coordinate, length float64) Step {
	instruction := fmt.Sprintf(
		"Walk from (%.4f, %.4f) to (%.4f, %.4f)",
		start.Lat, start.Lng, stop.Lat, stop.Lng)
	return Step{
		Distance:      FormatDistance(length),
		Duration:      MockupDuration(length),
		StartLocation: StepToPoint(start),
		EndLocation:   StepToPoint(stop),
		Polyline:      StepsToPolyline(steps, start, stop),
		Instruction:   instruction,
	}
}

// Convert a Path (start - steps - stop) into a json Step structure.
// This contains some additional information, which might or might
// not be accurate.
func WayToStep(steps graph.Way, start, stop geo.Coordinate) Step {
	return PartwayToStep(steps.Steps, start, stop, steps.Length)
}

// Convert an Edge (u,v) into a json Step
func EdgeToStep(g graph.Graph, edge graph.Edge, u, v graph.Vertex) Step {
	// transport (here graph.Car) does not matter for the metric distance
	// TODO only allocate once ([]geo.Coordinate(nil))
	return PartwayToStep(g.EdgeSteps(edge, u, []geo.Coordinate(nil)), g.VertexCoordinate(u), g.VertexCoordinate(v), g.EdgeWeight(edge, graph.Car, graph.Distance))
}

// Convert a single path as returned by Dijkstra to a json Leg.
func PathToLeg(g graph.Graph, distance float64, vertices []graph.Vertex, edges []graph.Edge, start, stop *graph.Way) *Leg {
	// Determine the number of steps on this path.
	var startPoint, endPoint Point
	totalSteps := len(edges)
	if start != nil && start.Length > 1e-7 {
		totalSteps++
	}
	if stop != nil && stop.Length > 1e-7 {
		totalSteps++
	}
	steps := make([]Step, totalSteps)

	// Add the initial step, if present
	i := 0
	if start != nil && start.Length > 1e-7 {
		// Our implementation of Dijkstra's algorithm ensures len(vertices) > 0
		steps[0] = WayToStep(*start, start.Target, g.VertexCoordinate(vertices[0]))
		i++
	}

	// Add the intermediate steps
	for j, edge := range edges {
		from := vertices[j]
		to := vertices[j+1]
		steps[i] = EdgeToStep(g, edge, from, to)
		i++
	}

	// Add the final step, if present
	if stop != nil && stop.Length > 1e-7 {
		prev := vertices[len(vertices)-1]
		steps[i] = WayToStep(*stop, g.VertexCoordinate(prev), stop.Target)
	}
	
	if start != nil {
		startPoint = StepToPoint(start.Target)
	} else {
		startPoint = steps[0].StartLocation
	}

	if stop != nil {
		endPoint = StepToPoint(stop.Target)
	} else {
		endPoint = steps[len(steps)-1].EndLocation
	}
	
	return &Leg{
		Distance:      FormatDistance(distance),
		Duration:      MockupDuration(distance),
		StartLocation: startPoint,
		EndLocation:   endPoint,
		Steps:         steps,
	}
}

// Computes the union of two BoundingBox'es.
func BoxUnion(a, b BoundingBox) BoundingBox {
	// Ok, maybe this wasn't such a good idea after all:
	nwLat := math.Max(a.Northwest[0], b.Northwest[0])
	nwLng := math.Min(a.Northwest[1], b.Northwest[1])
	seLat := math.Min(a.Southeast[0], b.Southeast[0])
	seLng := math.Max(a.Southeast[1], b.Southeast[1])
	return BoundingBox{Point{nwLat, nwLng}, Point{seLat, seLng}}
}

// Compute a tight bounding box for a single step.
func ComputeBoundsStep(step Step) BoundingBox {
	if len(step.Polyline) == 0 {
		// Bug?
		return BoundingBox{Point{0.0, 0.0}, Point{0.0, 0.0}}
	}

	bounds := BoundingBox{step.Polyline[0], step.Polyline[0]}
	if len(step.Polyline) > 1 {
{'fraction_non_alphanumeric': 0.13756666008295476, 'fraction_numerical': 0.018763578905787084, 'mean_word_length': 3.9255836575875485, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2535233', 'n_tokens_mistral': 3723, 'n_tokens_neox': 3463, 'n_words': 1056}