fleaflet / flutter_map

A versatile mapping package for Flutter. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.
https://pub.dev/packages/flutter_map
BSD 3-Clause "New" or "Revised" License
2.75k stars 860 forks source link

[BUG] polylines can display no more than 20,000 points on iOS #1567

Closed RiverYangZiJiang closed 1 year ago

RiverYangZiJiang commented 1 year ago

What is the bug?

polylines can display no more than 20,000 points on iOS, Android does not have this problem. The flutter_map version is v5.0.0.

How can we reproduce it?

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_example/widgets/drawer.dart';
import 'package:latlong2/latlong.dart';

class PolylinePage extends StatefulWidget {
  static const String route = 'polyline';

  const PolylinePage({Key? key}) : super(key: key);

  @override
  State<PolylinePage> createState() => _PolylinePageState();
}

class _PolylinePageState extends State<PolylinePage> {
  List<LatLng> points = <LatLng>[];
  static double centerLat = 22.544743;
  static double centerLong = 113.964011;
  LatLng center = LatLng(22.544743, 113.964011);

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    for (var i = 0; i < 573672; ++i) {
      points.add(LatLng(centerLat + i * .00001, centerLong + i * .00001));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Polylines')),
      drawer: buildDrawer(context, PolylinePage.route),
      body: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          children: [
            const Padding(
              padding: EdgeInsets.only(top: 8, bottom: 8),
              child: Text('Polylines'),
            ),
            Flexible(
              child: FlutterMap(
                options: MapOptions(
                  center: center,
                  zoom: 8,
                ),
                children: [
                  TileLayer(
                    urlTemplate:
                    'http://map.gpsoo.net/osm_tiles/{z}/{x}/{y}.png',
                    userAgentPackageName: 'dev.fleaflet.flutter_map.example',
                  ),
                  PolylineLayer(
                    polylines: [
                    Polyline(points: points,
                      strokeWidth: 4,
                      color: Colors.purple,)
                    ], // polylineCulling: true
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Do you have a potential solution?

no

Platforms

iPhone 14 with iOS16.4 Or iPhone 7 plus with iOS15.7

Severity

Obtrusive: Prevents normal functioning but causes no errors in the console

JaffaKetchup commented 1 year ago

Hey @RiverYangZiJiang, thanks for reporting. I'm not quite sure what do you mean by "can display no more than"? What happens? How can you be sure iOS has a different behaviour than Android? If it's a performance issue, it's much more likely that the hardware device in Android is more capable, or something along those lines. What Android devices have you tested on?

RiverYangZiJiang commented 1 year ago

it's not a performance issue, you can copy my code to the replace https://github.com/fleaflet/flutter_map/blob/master/example/lib/pages/polyline.dart, just drag the Slider to see the polylines length will stop when Polyline(points: pointsTemp ’s pointsTemp more than 20000.

JaffaKetchup commented 1 year ago

That appears as though it would be an issue in your code, unless I'm missing something? If the slider stops after a value, what is FM supposed to do about it. I'm also a little confused why you're using so many points to convey a straight line?

RiverYangZiJiang commented 1 year ago

this is android phone, the lines are much longer than those on iOS

21687775032_ pic

this is iphone Screenshot 2023-06-26 at 18 14 28

RiverYangZiJiang commented 1 year ago

That appears as though it would be an issue in your code, unless I'm missing something? If the slider stops after a value, what is FM supposed to do about it. I'm also a little confused why you're using so many points to convey a straight line?

I need to plot a lot of points on the road to represent the journey of the car, 600, 000 points at most

JaffaKetchup commented 1 year ago

I'm not sure this is an issue with FM. Running on Windows, I get similar behaviour to Android. It looks like maybe the iOS platform treats the value output of a Slider a little differently?

Can you create an MRE, just to help isolate the issue to FM or your code?

RiverYangZiJiang commented 1 year ago

Can you create an MRE, just to help isolate the issue to FM or your code?

This is not a problem with the Slider, the value of the Slider is correct.

JaffaKetchup commented 1 year ago

So they scale linearly at the same rate on both platforms? Can you put the value on the screen next to the slider?

RiverYangZiJiang commented 1 year ago

I remove the slider code, just left 573672 points, the issue still exists.

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_example/widgets/drawer.dart';
import 'package:latlong2/latlong.dart';

class PolylinePage extends StatefulWidget {
  static const String route = 'polyline';

  const PolylinePage({Key? key}) : super(key: key);

  @override
  State<PolylinePage> createState() => _PolylinePageState();
}

class _PolylinePageState extends State<PolylinePage> {
  List<LatLng> points = <LatLng>[];
  static double centerLat = 22.544743;
  static double centerLong = 113.964011;
  LatLng center = LatLng(22.544743, 113.964011);

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    for (var i = 0; i < 573672; ++i) {
      points.add(LatLng(centerLat + i * .00001, centerLong + i * .00001));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Polylines')),
      drawer: buildDrawer(context, PolylinePage.route),
      body: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          children: [
            const Padding(
              padding: EdgeInsets.only(top: 8, bottom: 8),
              child: Text('Polylines'),
            ),
            Flexible(
              child: FlutterMap(
                options: MapOptions(
                  center: center,
                  zoom: 8,
                ),
                children: [
                  TileLayer(
                    urlTemplate:
                    'http://map.gpsoo.net/osm_tiles/{z}/{x}/{y}.png',
                    userAgentPackageName: 'dev.fleaflet.flutter_map.example',
                  ),
                  PolylineLayer(
                    polylines: [
                    Polyline(points: points,
                      strokeWidth: 4,
                      color: Colors.purple,)
                    ], // polylineCulling: true
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
JaffaKetchup commented 1 year ago

Thanks, I'll try to reproduce later.

JaffaKetchup commented 1 year ago

This is where the line ends when running on Windows: image

ibrierley commented 1 year ago

If you add some debug to print the length of the points list in the build method, does it get called with the correct number of points (for iOS)?

JaffaKetchup commented 1 year ago
(Just for context, @RiverYangZiJiang, you're trying to build a point every 1.5m over 858,185m.) ```dart final points = List.generate( 573672, (i) => LatLng(center.latitude + i * .00001, center.longitude + i * .00001), ); print(const Distance(roundResult: false).distance(points.first, )); ```
jesussmile commented 1 year ago

yes. i tested it on ios, In ios it is unable to render all the points. checking the print statement of the points, all points are getting called but not rendered on the map. I guess thats the way IOS handles memory? there is no errors in the debug window. but why would you use so many points if just 2 points is sufficient? The same code works fine in android and desktop. However this can be an issue if we were to plot polyline or polygon based on the terrain data.

RiverYangZiJiang commented 1 year ago

yes. i tested it on ios, In ios it is unable to render all the points. checking the print statement of the points, all points are getting called but not rendered on the map. I guess thats the way IOS handles memory? there is no errors in the debug window. but why would you use so many points if just 2 points is sufficient? The same code works fine in android and desktop. However this can be an issue if we were to plot polyline or polygon based on the terrain data.

I need to plot the path of the car, half a million points a week

mohammedX6 commented 1 year ago

you can do simplify for the points, it will reduce number of the points. https://pub.dev/packages/simplify

JaffaKetchup commented 1 year ago

Welp, I'm not sure there's a lot that we can do here. But I wouldn't recommend doing anything like this anyway! 20,000 points is more than enough for the vast majority of use cases. If your line is more than that, either simplify it (https://github.com/fleaflet/flutter_map/issues/1567#issuecomment-1621155409), or chunk it into separate polylines (which will also improve performance as the line can be culled).