addRoute method

Future<PowerMapRouteResult?> addRoute({
  1. required LatLng start,
  2. required LatLng destination,
  3. required List<LatLng> waypoints,
  4. required bool optimize,
  5. required String profile,
  6. required String language,
  7. bool fitCamera = true,
})

Calculates and draws a route between start and destination.

Calls the PowerMap Routing API, decodes the geometry, and adds the line to the map.

Implementation

Future<PowerMapRouteResult?> addRoute({
  required LatLng start,
  required LatLng destination,
  required List<LatLng> waypoints,
  required bool optimize,
  required String profile,
  required String language,
  bool fitCamera = true,
}) async {
  try {
    final String baseUrl = PowerMapSDK.baseUrl;
    final Map<String, String> headers = await PowerMapSDK.getServiceHeaders();

    final List<LatLng> points = [start, ...waypoints, destination];

    if (optimize && waypoints.isEmpty) {
      throw PowerMapException(
        code: PowerMapException.invalidRequest,
        message: 'Optimization requires at least one waypoint.',
      );
    }

    final String coordsParam = points
        .map((p) => '${p.longitude},${p.latitude}')
        .join(';');

    dynamic data;

    try {
      if (optimize && profile == 'driving') {
        data = await _requestOptimizedRoute(
          start: start,
          destination: destination,
          waypoints: waypoints,
          language: language,
          baseUrl: baseUrl,
          headers: headers,
        );
      } else {
        final queryParams = {
          'geometries': 'polyline6',
          'steps': 'true',
          'overview': 'full',
          'roundabout_exits': 'true',
          'voice_instructions': 'true',
          'banner_instructions': 'true',
          'language': language,
        };

        final uri = Uri.parse(
          '$baseUrl/api/v2/map/route/$profile/$coordsParam',
        ).replace(queryParameters: queryParams);

        final response = await http.get(uri, headers: headers);
        if (response.statusCode != 200) {
          if (response.statusCode == 401 || response.statusCode == 403) {
            throw PowerMapException(
              code: PowerMapException.auth,
              message: 'Authentication failed for routing request.',
            );
          }
          throw PowerMapException(
            code: PowerMapException.serverError,
            message: 'Routing API error: ${response.statusCode}',
            details: response.body,
          );
        }
        data = json.decode(response.body);
      }
    } catch (e) {
      if (e is PowerMapException) rethrow;
      throw PowerMapException(
        code: PowerMapException.network,
        message: 'Routing request failed due to a network error.',
        details: e,
      );
    }

    if (data != null &&
        data['routes'] != null &&
        (data['routes'] as List).isNotEmpty) {
      final best = data['routes'][0];

      // Decode geometry
      List<LatLng> geometry;
      if (best['geometry'] is String) {
        geometry = _decodePolyline(best['geometry'] as String, precision: 6);
      } else {
        // Assume GeoJSON
        final coords = (best['geometry']['coordinates'] as List);
        geometry = coords
            .map((c) => LatLng(c[1] as double, c[0] as double))
            .toList();
      }

      final result = PowerMapRouteResult(
        distance: (best['distance'] as num).toDouble(),
        duration: (best['duration'] as num).toDouble(),
        geometry: geometry,
        steps: _parseSteps(best['legs'] as List),
        raw: data,
        profile: profile,
      );

      _drawRoute(result.geometry, fitCamera: fitCamera);
      return result;
    }
  } catch (e) {
    debugPrint('PowerMap Routing Error: $e');
    rethrow;
  }
  return null;
}