mapbox-maps-flutter
mapbox-maps-flutter copied to clipboard
Overlapping Polygons Affect Opacity of Fill Color
Problem: Currently, our system generates polygons comprising 360 vertices to display a red circle with a fill color set to red and an opacity of 10%. However, when these polygons overlap, the resulting opacity is not consistent. Overlapping polygons cause areas of the circle to become darker than the intended 10% opacity due to the additive effect of overlapping colors.
Expected Behavior: We expect the fill color opacity to remain consistent at 10% throughout the entire circle, regardless of overlapping polygons.
This is the current situation:

What we need is:

nonSmokingAreas[result[i].id] =
(await nonSmokingAreaManager?.create(
PolygonAnnotationOptions(
fillColor: Colors.red.withOpacity(0.1).value,
fillSortKey: 1,
geometry: Polygon(
coordinates: [
List.generate(
points.length,
(index) => Position(
points[index].lng,
points[index].lat,
),
),
],
).toJson()),
))!;
import 'dart:math';
/// Generates a list of points representing a regular polygon around a given geographic coordinate (latitude and longitude) with a specified radius.
///
/// Parameters:
/// - `lat` (double): The latitude of the central position of the polygon.
/// - `lng` (double): The longitude of the central position of the polygon.
/// - `radius` (double): The radius of the polygon in meters.
///
/// Returns:
/// - `List<({double lat, double lng})>`: A list of tuples, where each tuple represents a point on the generated polygon. Each point is represented by latitude and longitude.
///
/// Algorithm:
/// The function uses an iterative method to generate the points of the polygon. It calculates the position of each point using the distance (`radius`) and the angle relative to the central position. It uses the `_translateCoordinate` function to compute the geographic coordinates of each point.
///
/// 1. Initialize an empty list `points` to store the generated points.
/// 2. Iterate from 0 to 11 (total of 36 iterations) for creating a regular polygon.
/// 3. Calculate the angle (`angle`) for each point using the index of the iteration.
/// 4. Calculate the displacement (`dx` and `dy`) relative to the radius and angle.
/// 5. Use the `_translateCoordinate` function to compute the geographic coordinates of each point and add them to the `points` list.
/// 6. Return the `points` list containing all the generated points of the polygon.
///
/// Notes:
/// - The algorithm assumes the Earth is a perfect sphere and uses a simple approximation for computing the coordinates.
/// - The function generates a regular polygon with 36 vertices, which corresponds to a regular pentagon. The number of vertices can be changed by adjusting the loop condition.
List<({double lat, double lng})> listgeneratePolygonPoints(
double lat, double lng, double radius) {
List<({double lat, double lng})> points = [];
for (int i = 0; i < 360; i++) {
double angle = (2 * pi * i) / 360;
double dx = radius * cos(angle);
double dy = radius * sin(angle);
final point = _translateCoordinate((lat: lat, lng: lng), dx, dy);
points.add(point);
}
return points;
}
/// Translates the geographic coordinates of a point based on a given origin position, displacement in latitude and longitude, and Earth radius.
///
/// Parameters:
/// - `coordinate` ({double lat, double lng}): The initial coordinates tuple containing latitude and longitude.
/// - `dx` (double): The displacement in longitude.
/// - `dy` (double): The displacement in latitude.
///
/// Returns:
/// - `({double lat, double lng})`: A tuple containing the computed geographic coordinates of the point resulting from the displacement from the origin position.
///
/// Algorithm:
/// 1. Calculate the new latitude component (`lat`) based on the displacement in latitude and the Earth radius.
/// 2. Calculate the new longitude component (`lon`) based on the displacement in longitude, Earth radius, and the cosine of the latitude of the origin position.
/// 3. Return a tuple containing the calculated latitude and longitude of the new point.
///
/// Notes:
/// - The function considers the curvature of the Earth and uses a simple formula to compute the new coordinates.
/// - It is assumed that the displacement (`dx` and `dy`) is relatively small, so the curvature of the Earth can be neglected.
({double lat, double lng}) _translateCoordinate(
({double lat, double lng}) coordinate, double dx, double dy) {
const double earthRadius = 6378137; // Earth radius in meters
double lat = coordinate.lat + (dy / earthRadius) * (180 / pi);
double lon = coordinate.lng +
(dx / earthRadius) * (180 / pi) / cos(coordinate.lat * pi / 180);
return (lat: lat, lng: lon);
}
It looks like an expected behaviour to me. But you could merge your circles before putting them on the map. The current turf release doesn't support union operation, but ~~you could find a branch with added support in their PRs~~ (upd: I've tested it, it's completely non-working), or alternatively, you could use polybool library. Also, depending on the amount of circles you have, you may want to run this computation in isolate to prevent UI freezes.
Disclaimer: I'm not a maintainer of this repo.