diff --git a/backend/test.py b/backend/test.py new file mode 100644 index 0000000..672b166 --- /dev/null +++ b/backend/test.py @@ -0,0 +1,111 @@ +import numpy as np + +def euclidean_distance(p1, p2): + print(p1, p2) + return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) + + +def maximize_score(places, max_distance, fixed_entry, top_k=3): + """ + Maximizes the total score of visited places while staying below the maximum distance. + + Parameters: + places (list of tuples): Each tuple contains (score, (x, y), location). + max_distance (float): The maximum distance that can be traveled. + fixed_entry (tuple): The place that needs to be visited independently of its score. + top_k (int): Number of top candidates to consider in each iteration. + + Returns: + list of tuples: The visited places. + float: The total score of the visited places. + """ + # Initialize total distance and score + total_distance = 0 + total_score = 0 + visited_places = [] + + # Add the fixed entry to the visited list + score, (x, y), _ = fixed_entry + visited_places.append(fixed_entry) + total_score += score + + # Remove the fixed entry from the list of places + remaining_places = [place for place in places if place != fixed_entry] + + # Sort remaining places by score-to-distance ratio + + remaining_places.sort(key=lambda p: p[0] / euclidean_distance((x, y), (p[1][0], p[1][1])), reverse=True) + + # Add places to the visited list if they don't exceed the maximum distance + current_location = (x, y) + while remaining_places and total_distance < max_distance: + # Consider top_k candidates + candidates = remaining_places[:top_k] + best_candidate = None + best_score_increase = -np.inf + + for candidate in candidates: + score, (cx, cy), location = candidate + distance = euclidean_distance(current_location, (cx, cy)) + if total_distance + distance <= max_distance: + score_increase = score / distance + if score_increase > best_score_increase: + best_score_increase = score_increase + best_candidate = candidate + + if best_candidate: + visited_places.append(best_candidate) + total_distance += euclidean_distance(current_location, best_candidate[1]) + total_score += best_candidate[0] + current_location = best_candidate[1] + remaining_places.remove(best_candidate) + else: + break + + return visited_places, total_score + +# Example usage +places = [ + (10, (0, 0), 'A'), + (8, (4, 2), 'B'), + (15, (6, 4), 'C'), + (7, (5, 6), 'D'), + (12, (1, 8), 'E'), + (14, (34, 10), 'F'), + (15, (65, 12), 'G'), + (12, (3, 14), 'H'), + (12, (15, 1), 'I'), + (7, (17, 4), 'J'), + (12, (3, 3), 'K'), + (4, (21, 22), 'L'), + (12, (23, 24), 'M'), + (4, (25, 26), 'N'), + (2, (27, 28), 'O'), +] +fixed_entry = (10, (0, 0), 'A') +max_distance = 50 + +visited_places, total_score = maximize_score(places, max_distance, fixed_entry) +print("Visited Places:", visited_places) +print("Total Score:", total_score) + +import matplotlib.pyplot as plt + +# Plot the route +def plot_route(visited_places): + x_coords = [place[1][0] for place in visited_places] + y_coords = [place[1][1] for place in visited_places] + labels = [place[2] for place in visited_places] + + plt.figure(figsize=(10, 6)) + plt.plot(x_coords, y_coords, marker='o', linestyle='-', color='b') + for i, label in enumerate(labels): + plt.text(x_coords[i], y_coords[i], label, fontsize=12, ha='right') + + plt.title('Route of Visited Places') + plt.xlabel('X Coordinate') + plt.ylabel('Y Coordinate') + plt.grid(True) + plt.savefig('route.png') + +plot_route(visited_places) \ No newline at end of file diff --git a/frontend/lib/modules/current_trip_loading_indicator.dart b/frontend/lib/modules/current_trip_loading_indicator.dart index 1f81d60..dda6cd6 100644 --- a/frontend/lib/modules/current_trip_loading_indicator.dart +++ b/frontend/lib/modules/current_trip_loading_indicator.dart @@ -34,29 +34,85 @@ Widget loadingText(Trip trip) => FutureBuilder( Widget greeter; if (snapshot.hasData) { - greeter = AutoSizeText( - maxLines: 1, - 'Generating your trip to ${snapshot.data}...', + greeter = AnimatedGradientText( + text: 'Generating your trip to ${snapshot.data}...', style: greeterStyle, ); } else if (snapshot.hasError) { // the exact error is shown in the central part of the trip overview. No need to show it here - greeter = AutoSizeText( - maxLines: 1, - 'Error while loading trip.', + greeter = AnimatedGradientText( + text: 'Error while loading trip.', style: greeterStyle, - ); + ); } else { - greeter = AutoSizeText( - maxLines: 1, - 'Generating your trip...', + greeter = AnimatedGradientText( + text: 'Generating your trip...', style: greeterStyle, - ); + ); } return greeter; } ); +class AnimatedGradientText extends StatefulWidget { + final String text; + final TextStyle style; + + const AnimatedGradientText({ + Key? key, + required this.text, + required this.style, + }) : super(key: key); + + @override + _AnimatedGradientTextState createState() => _AnimatedGradientTextState(); +} + +class _AnimatedGradientTextState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + )..repeat(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return ShaderMask( + shaderCallback: (bounds) { + return LinearGradient( + colors: [Colors.blue, Colors.red, Colors.blue], + stops: [ + _controller.value - 1.0, + _controller.value, + _controller.value + 1.0, + ], + tileMode: TileMode.mirror, + ).createShader(bounds); + }, + child: Text( + widget.text, + style: widget.style, + ), + ); + }, + ); + } +} + diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart index de7d893..50a71c5 100644 --- a/frontend/lib/structs/landmark.dart +++ b/frontend/lib/structs/landmark.dart @@ -125,7 +125,7 @@ class LandmarkType { LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) { switch (name) { case 'sightseeing': - icon = const Icon(Icons.church); + icon = const Icon(Icons.castle); break; case 'nature': icon = const Icon(Icons.eco);