Created
October 3, 2023 16:34
-
-
Save rvachev/dd6302d50eec7a629e8cf7344a764c4b to your computer and use it in GitHub Desktop.
Handling object tap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| late final MapController _mapController = MapController(); | |
| final _objects = <MapObject>[]; | |
| bool _searchForObjectsInPoints(LatLng latLng) { | |
| // Предположительные метрики в пикселях | |
| // 40 14.67 - 15.67 | |
| // 30 15.67 - 16.67 | |
| // 20 16.67 - 17.67 | |
| // 10 17.67 - 18.67 | |
| final precision = min((20 - _mapController.zoom) * 7, 40); | |
| final distances = <MapObject, double>{}; | |
| for (final object in _objects) { | |
| distances.putIfAbsent( | |
| object, | |
| () => _minDistanceToObject(object, latLng), | |
| ); | |
| } | |
| final sorted = SplayTreeMap<MapObject, double>.from( | |
| distances, | |
| (a, b) => distances[a]!.compareTo(distances[b]!), | |
| ); | |
| if (sorted.isEmpty) { | |
| return false; | |
| } | |
| if (sorted.values.first < precision) { | |
| // Function which handles object tap | |
| _onObjectTap(sorted.firstKey()!); | |
| return true; | |
| } | |
| return false; | |
| } | |
| double _minDistanceToObject( | |
| MapObject? object, | |
| LatLng latLng, | |
| ) { | |
| final tap = const Epsg3857().latLngToPoint(latLng, _mapController.zoom); | |
| if (object is PolylineWrapper) { | |
| return _minDistanceToPoints(object.polyline.points, tap); | |
| } | |
| if (object is PolygonWrapper) { | |
| if (_isInside(object.polygon, tap)) return 0; | |
| return _minDistanceToPoints(object.polygon.points, tap); | |
| } | |
| if (object is MultiPolylineWrapper) { | |
| var minDistance = double.maxFinite; | |
| for (final polyline in object.polylines) { | |
| final distance = _minDistanceToPoints(polyline.points, tap); | |
| if (distance < minDistance) { | |
| minDistance = distance; | |
| } | |
| } | |
| return minDistance; | |
| } | |
| if (object is MultiPolygonWrapper) { | |
| var minDistance = double.maxFinite; | |
| for (final polygon in object.polygons) { | |
| if (_isInside(polygon, tap)) return 0; | |
| final distance = _minDistanceToPoints(polygon.points, tap); | |
| if (distance < minDistance) { | |
| minDistance = distance; | |
| } | |
| } | |
| return minDistance; | |
| } | |
| return double.maxFinite; | |
| } | |
| double _minDistanceToPoints(List<LatLng> points, CustomPoint<double> tap) { | |
| var minDistance = double.maxFinite; | |
| for (var i = 0; i < points.length - 1; i++) { | |
| final firstPoint = | |
| const Epsg3857().latLngToPoint(points[i], _mapController.zoom); | |
| final secondPoint = | |
| const Epsg3857().latLngToPoint(points[i + 1], _mapController.zoom); | |
| final distanceOne = | |
| tap.distanceTo(firstPoint) + tap.distanceTo(secondPoint); | |
| final distanceTwo = firstPoint.distanceTo(secondPoint); | |
| if (distanceOne - distanceTwo < minDistance) { | |
| minDistance = distanceOne - distanceTwo; | |
| } | |
| } | |
| return minDistance; | |
| } | |
| //https://ru.wikibooks.org/wiki/Реализации_алгоритмов/Задача_о_принадлежности_точки_многоугольнику | |
| bool _isInside(Polygon polygon, CustomPoint<double> tap) { | |
| final points = polygon.points; | |
| var isInside = false; | |
| var j = points.length - 1; | |
| for (var i = 0; i < points.length; j = i++) { | |
| final firstPoint = | |
| const Epsg3857().latLngToPoint(points[i], _mapController.zoom); | |
| final secondPoint = | |
| const Epsg3857().latLngToPoint(points[j], _mapController.zoom); | |
| if (((firstPoint.y < secondPoint.y) && | |
| (firstPoint.y <= tap.y) && | |
| (tap.y <= secondPoint.y) && | |
| ((secondPoint.y - firstPoint.y) * (tap.x - firstPoint.x) > | |
| (secondPoint.x - firstPoint.x) * (tap.y - firstPoint.y))) || | |
| ((firstPoint.y > secondPoint.y) && | |
| (secondPoint.y <= tap.y) && | |
| (tap.y <= firstPoint.y) && | |
| ((secondPoint.y - firstPoint.y) * (tap.x - firstPoint.x) < | |
| (secondPoint.x - firstPoint.x) * (tap.y - firstPoint.y)))) { | |
| isInside = !isInside; | |
| } | |
| } | |
| return isInside; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment