ibrierley / flutter_map_line_editor

A basic line/poly editor that works with flutter_map and dragmarkers.
MIT License
44 stars 25 forks source link

Inbetween point of a line not quite accurate on low zooms. #35

Open ibrierley opened 1 year ago

ibrierley commented 1 year ago

There's a quirk when using this on low zoom levels (I guess most people use a high zoom level for this) which I've never been quite happy with, and I feel like it should get fixed properly at some point.

Mid point markers can be offset slightly from their visual center. I suspect this is because of projections and a midway point of a LatLng isn't actually quite what we need. Again, we'll probably only notice this at low zoom levels where the effect is more pronounced.

I've tried a LatLngBounds.center, but actually I think this still has the same issue. What I suspect we need is actually to get the projection in pixels, so we have the screen space, then take the mid point, then unproject back into a LatLng.

If anyone fancies a challenge, it may be interesting to have a stab. This may need a bit more of a fundamental rejig, as I "think" it may need access to flutter_maps internals for the crs projection there, and original it was written to not need that.

josxha commented 1 year ago

I just came across the package geodesy that might have this functionality:

LatLng midpoint = geodesy.midPointBetweenTwoGeoPoints(l1, l2);

It i inactive since a long time but it has a MIT license so the functionality could be copied over.

ibrierley commented 1 year ago

Thanks, I don't think the problem is the mid point of the latlng, but the fact we want the screen position of the midpoint of the line in screen coordinates (I may be wrong), so I think what we probably want to do is get the screen coords of both points, then calculate a simple halfway of those, and convert that back to latlng. There may be a simpler way, but I "think" that makes sense (I think flutter_map can do latlngtoscreenpos)

Leffe108 commented 3 months ago

I had a look on this, and made an attempt using turf midpoint, but it visually got worse than the current lat/lng midpoint formula. I think @ibrierley is right that it a change to screen coordinate projection is necessary here.

I looked around a bit and found some answers:

It looks like we need the current zoom level to use CustomPoint<num> screenPosition = Epsg3857().latLngToPoint(latlng, mapController.zoom); So it might be that the edit() method would need to take current zoom level as parameter.

EricKrg commented 2 months ago

@Leffe108 @ibrierley Hey guys, I also played around bit and found a working solution using the geobase package, which in my opinion flies a bit under the radar, I used thew midpoint on the rhumbline (loxodrome) which from my testing seems to work correctly.

here are is what I tested:

import 'package:geobase/geobase.dart';
// ....

List<DragMarker> edit() {
    List<DragMarker> dragMarkers = [];

    for (var c = 0; c < points.length; c++) {
      final indexClosure = c;
      dragMarkers.add(DragMarker(
        point: points[c],
        size: pointIconSize,
        builder: (_, __, ___) => pointIcon,
        onDragStart: (_, __) => _markerToUpdate = indexClosure,
        onDragUpdate: updateMarker,
        onLongPress: (ll) => remove(indexClosure),
      ));
    }

    for (var c = 0; c < points.length - 1; c++) {
      final polyPoint = points[c];
      final polyPoint2 = points[c + 1];

      if (intermediateIcon != null) {
        final indexClosure = c;
        // point on Rhumbline
        final mid =
            Geographic.create(x: polyPoint.longitude, y: polyPoint.latitude)
                .rhumb
                .midPointTo(Geographic.create(
                    x: polyPoint2.longitude, y: polyPoint2.latitude));
        final intermediatePoint = LatLng(mid.lat, mid.lon);

        dragMarkers.add(DragMarker(
          point: intermediatePoint,
          size: intermediateIconSize,
          builder: (_, __, ___) => intermediateIcon!,
          onDragStart: (details, point) {
            points.insert(indexClosure + 1, intermediatePoint);
            _markerToUpdate = indexClosure + 1;
          },
          onDragUpdate: updateMarker,
        ));
      }
    }

maybe you can test it and confirm it, I can create a MR if you like the solution.

ibrierley commented 2 months ago

Had a quick test of this, it seems to break on lower zoom levels and you end up with some drag points that are way off, example screen shot localhost_36457_ note the point bottom left.

Not quite sure what's happening there...sometimes I drag a point, and it just seems to "pop" out to a new location.

I'd probably prefer it tbh without a package, but I'm not sure of a sensible way to achieve that anyway unless anyone has some ideas, so this may be the way to go.