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.77k stars 862 forks source link

Location lat-lng getting wrong when using Yandex Map #642

Closed savasadar closed 3 years ago

savasadar commented 4 years ago

I am using flutter_map with yandex map like below. When I mark a location, Getting location lat and lon are wrong. So If I draw a polygon on the map, It drawn on wrong location. How to fix this?

FlutterMap(
  options: MapOptions(
    center: LatLng(41.334554,36.269617),
    zoom: 11.0,
    maxZoom: 18,
    minZoom: 5,
    plugins: [
      DragMarkerPlugin(),
    ],
    onTap: (value){
      print(value.toString());
      markLocation(value);
    },
  ),
  layers: [
    TileLayerOptions(
        urlTemplate: 'https://core-sat.maps.yandex.net/tiles?l=sat&v=3.569.0&x={x}&y={y}&z={z}&lang=tr_TR'
    ),
    TileLayerOptions(
        urlTemplate: 'http://vec{s}.maps.yandex.net/tiles?l=skl&v=20.06.03&z={z}&x={x}&y={y}&scale=1&lang=tr_TR',
        subdomains: ['01', '02', '03', '04'],
        backgroundColor: Colors.transparent
    ),
    CircleLayerOptions(
        circles: _circles
    ),
    PolygonLayerOptions(
      polygons: getPolygons()
    ),
    DragMarkerPluginOptions(
      markers: _markers
    )
  ],
  mapController: _mapController,
)

Actual position of polygon: Screen Shot 2020-06-03 at 17 34 38

And How to looks on device? Screenshot_20200603-173706

ruizalexandre commented 4 years ago

Projection issue ? Using 4326 can fix this ?

savasadar commented 4 years ago

Projection issue ? Using 4326 can fix this ?

I tried use csr: Epsg4326() in MapOptions but map show irrelevant location.

savasadar commented 4 years ago
L.CRS.EPSG3395 Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
L.CRS.EPSG3857 The most common CRS for online maps, used by almost all free and commercial tile providers. Uses Spherical Mercator projection. Set in by default in Map's crs option.

https://leafletjs.com/reference-1.3.4.html#crs

I guess yandex map use EPSG3395 ellipsoid projection.

https://tech.yandex.com/maps/jsapi/doc/2.1/ref/reference/projection.wgs84Mercator-docpage/

flutter_map support EPSG3857 and EPSG4326 but not EPSG3395. How can I implement EPSG3395 as a custom csr?

moovida commented 4 years ago

Yes, look at this part for how to do it: https://github.com/johnpryan/flutter_map#custom-crs

savasadar commented 4 years ago

I am trying to work with custom csr and There are some problems about it. I defined custom csr for 3395 like below.

epsg3395 = proj4.Projection('EPSG:3395') ??
        proj4.Projection.add('EPSG:3395', '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');

    final epsg3395Bounds = Bounds<double>(
      CustomPoint<double>(-180.0, -80.0),
      CustomPoint<double>(180.0, 84.0),
    );

    final resolutions = <double>[
      32768,
      16384,
      8192,
      4096,
      2048,
      1024,
      512,
      256,
      128,
    ];

    // Define CRS
    epsg3395CRS = Proj4Crs.fromFactory(
      // CRS code
      code: 'EPSG:3395',
      // your proj4 delegate
      proj4Projection: epsg3395,
      // Resolution factors (projection units per pixel, for example meters/pixel)
      // for zoom levels; specify either scales or resolutions, not both
      resolutions: resolutions,
      // Bounds of the CRS, in projected coordinates
      // (if not specified, the layer's which uses this CRS will be infinite)
      bounds: epsg3395Bounds,
      // Tile origin, in projected coordinates, if set, this overrides the transformation option
      // Some goeserver changes origin based on zoom level
      // and some are not at all (use explicit/implicit null or use [CustomPoint(0, 0)])
      // @see https://github.com/kartena/Proj4Leaflet/pull/171
      origins: [CustomPoint(0,0)],
      // Scale factors (pixels per projection unit, for example pixels/meter) for zoom levels;
      // specify either scales or resolutions, not both
      scales: null,
      // The transformation to use when transforming projected coordinates into pixel coordinates
      transformation: null,
    );

I got definion from https://epsg.io/3395

When I set custom csr to map with MapOptions, Tiles not loading.

Screen Shot 2020-06-04 at 14 43 40

Screen Shot 2020-06-04 at 14 46 09

What is my fault?

savasadar commented 4 years ago

When I manipulate location latitude polygon come to true location. But I know this is not right way for solve the issue, I am still research how to use custom csr.

LatLng(item.latitude*0.99538824, item.longitude)

Result: Screen Shot 2020-06-04 at 15 42 40

maRci002 commented 4 years ago

Try change resolutions based on this.

Or maybe hardcoded resolutions works.

    final resolutions = <double>[
      156543.03390625003,
      78271.51695312501,
      39135.75847656251,
      19567.879238281253,
      9783.939619140627,
... so on
    ];
dmitrienkop commented 4 years ago

@savasadar

Try this:

import 'dart:math' as math;
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong/latlong.dart';

class Epsg3395 extends Earth {
  @override
  final String code = 'EPSG:3395';

  @override
  final Projection projection = const Mercator();

  @override
  final Transformation transformation = const Transformation(_scale, 0.5, -_scale, 0.5);

  static const num _scale = 0.5 / (math.pi * Mercator.r);

  const Epsg3395() : super();
}

class Mercator extends Projection {
  static const int r = 6378137;
  static const double rMinor = 6356752.314245179;
  static final Bounds<double> _bounds = Bounds<double>(
    CustomPoint<double>(-20037508.34279, -15496570.73972),
    CustomPoint<double>(20037508.34279, 18764656.23138),
  );

  const Mercator() : super();

  @override
  Bounds<double> get bounds => _bounds;

  @override
  CustomPoint project(LatLng latlng) {
    var d = math.pi / 180;
    var y = latlng.latitude * d;
    var tmp = rMinor / r;
    var e = math.sqrt(1 - tmp * tmp);
    var con = e * math.sin(y);

    var ts = math.tan(math.pi / 4 - y / 2) / math.pow((1 - con) / (1 + con), e / 2);
    y = -r * math.log(math.max(ts, 1E-10));

    return CustomPoint(latlng.longitude * d * r, y);
  }

  @override
  LatLng unproject(CustomPoint point) {
    var d = 180 / math.pi;
    var tmp = rMinor / r;
    var e = math.sqrt(1 - tmp * tmp);
    var ts = math.exp(-point.y / r);
    var phi = math.pi / 2 - 2 * math.atan(ts);

    for (var i = 0, dphi = 0.1, con; i < 15 && dphi.abs() > 1e-7; i++) {
            con = e * math.sin(phi);
            con = math.pow((1 - con) / (1 + con), e / 2);
            dphi = math.pi / 2 - 2 * math.atan(ts * con) - phi;
            phi += dphi;
        }

    return LatLng(phi * d, point.x * d / r);
  }
}

Hope, it helps.

savasadar commented 3 years ago

@dmitrienkop Thank you. This is working.

zappaz00 commented 5 months ago

Unfortunately, in v7 version the Transformation and CrsWithStaticTransformation (replacing the old Earth class) classes were hidden. After migration I had to copy these classes to myself...