feat : map

This commit is contained in:
2025-04-09 17:05:38 +03:30
parent e83388670c
commit 0286725ac6
41 changed files with 1120 additions and 91 deletions

View File

@@ -0,0 +1,109 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
class ClusterParams {
final List<LatLng> points;
final double clusterRadiusMeters;
ClusterParams({
required this.points,
required this.clusterRadiusMeters,
});
}
class Cluster {
final LatLng center;
final List<LatLng> members;
Cluster(this.center, this.members);
}
// Use a more efficient quadtree-based clustering algorithm
Future<List<Cluster>> clusterMarkersQuadtreeIsolate(ClusterParams params) async {
return compute(_clusterMarkersQuadtree, params);
}
List<Cluster> _clusterMarkersQuadtree(ClusterParams params) {
final points = params.points;
final radius = params.clusterRadiusMeters;
final distance = const Distance();
final List<Cluster> clusters = [];
// Skip clustering if we have a small number of points
if (points.length < 100) {
return points.map((p) => Cluster(p, [p])).toList();
}
// Find bounds
double minLat = points[0].latitude;
double maxLat = points[0].latitude;
double minLng = points[0].longitude;
double maxLng = points[0].longitude;
for (final point in points) {
minLat = min(minLat, point.latitude);
maxLat = max(maxLat, point.latitude);
minLng = min(minLng, point.longitude);
maxLng = max(maxLng, point.longitude);
}
// Build spatial grid for faster lookups (simple spatial index)
// Convert geographic distance to approximate degrees
final double radiusDegLat = radius / 111000; // ~111km per degree latitude
final double radiusDegLng = radius / (111000 * cos(minLat * pi / 180)); // Adjust for longitude
final int gridLatSize = ((maxLat - minLat) / radiusDegLat).ceil();
final int gridLngSize = ((maxLng - minLng) / radiusDegLng).ceil();
// Create spatial grid
final List<List<List<LatLng>>> grid = List.generate(
gridLatSize + 1,
(_) => List.generate(gridLngSize + 1, (_) => <LatLng>[])
);
// Add points to grid cells
for (final point in points) {
final int latIdx = ((point.latitude - minLat) / radiusDegLat).floor();
final int lngIdx = ((point.longitude - minLng) / radiusDegLng).floor();
grid[latIdx][lngIdx].add(point);
}
// Process grid cells in batches
final Set<LatLng> processed = {};
for (int latIdx = 0; latIdx < gridLatSize; latIdx++) {
for (int lngIdx = 0; lngIdx < gridLngSize; lngIdx++) {
final cellPoints = grid[latIdx][lngIdx];
for (final point in cellPoints) {
if (processed.contains(point)) continue;
// Find nearby points
final List<LatLng> neighbors = [];
neighbors.add(point);
processed.add(point);
// Check current and adjacent cells for neighbors
for (int adjLat = max(0, latIdx - 1); adjLat <= min(gridLatSize - 1, latIdx + 1); adjLat++) {
for (int adjLng = max(0, lngIdx - 1); adjLng <= min(gridLngSize - 1, lngIdx + 1); adjLng++) {
for (final neighbor in grid[adjLat][adjLng]) {
if (!processed.contains(neighbor) && distance(point, neighbor) <= radius) {
neighbors.add(neighbor);
processed.add(neighbor);
}
}
}
}
// Calculate cluster center
if (neighbors.isNotEmpty) {
final avgLat = neighbors.map((p) => p.latitude).reduce((a, b) => a + b) / neighbors.length;
final avgLng = neighbors.map((p) => p.longitude).reduce((a, b) => a + b) / neighbors.length;
clusters.add(Cluster(LatLng(avgLat, avgLng), neighbors));
}
}
}
}
return clusters;
}

View File

@@ -0,0 +1,57 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
class GridGenParams {
final LatLng center;
final int count;
final double spacingMeters;
const GridGenParams({
required this.center,
required this.count,
required this.spacingMeters,
});
}Future<List<LatLng>> generateGridMarkersIsolate(GridGenParams params) async {
return compute(_generateGridMarkersOptimized, params);
}
List<LatLng> _generateGridMarkersOptimized(GridGenParams params) {
final List<LatLng> result = [];
final Distance distance = const Distance();
// Pre-calculate the grid dimensions
final int gridSize = sqrt(params.count).ceil();
final double halfWidth = (gridSize * params.spacingMeters) / 2;
final double halfHeight = (gridSize * params.spacingMeters) / 2;
// Calculate top-left corner of the grid
final LatLng topLeft = distance.offset(
distance.offset(params.center, -halfHeight, 0), // south
-halfWidth, 270 // west
);
// Generate grid in batches for better memory management
const int batchSize = 10000;
for (int batch = 0; batch < (params.count / batchSize).ceil(); batch++) {
final int startIdx = batch * batchSize;
final int endIdx = min((batch + 1) * batchSize, params.count);
for (int i = startIdx; i < endIdx; i++) {
final int row = i ~/ gridSize;
final int col = i % gridSize;
final double dx = col * params.spacingMeters;
final double dy = row * params.spacingMeters;
final LatLng point = distance.offset(
distance.offset(topLeft, dy, 180), // south
dx, 90 // east
);
result.add(point);
}
}
return result.sublist(0, min(result.length, params.count));
}